Skip to content

Commit 125d1d7

Browse files
rubenmarcusclaude
andauthored
feat: unified task management across GitHub & Linear (#196)
* feat: unified task management across GitHub & Linear with --assignee support Add `ralph-starter task` command for bidirectional issue management: - list/create/update/close/comment across both platforms - Smart ID routing (#123 → GitHub, ENG-42 → Linear) - --assignee flag with Linear user resolution (name/email matching) - WritableIntegration interface extending read-only integrations - OpenClaw agent support in the agent adapter pattern - MCP ralph_task tool for Claude Desktop/Code integration - Refactored batch-fetcher to use WritableIntegration - Fix: Linear resolveIssueId now uses issue(id:) which accepts identifiers - Docs: CLI reference page, README, sidebar, source docs updated Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use Linear API url field and handle status in GitHub updateTask Address reviewer feedback: - Greptile: use issue.url from Linear API instead of constructing incorrect URL - Greptile: handle input.status in GitHub updateTask (was silently dropped) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5f93bac commit 125d1d7

File tree

14 files changed

+1537
-119
lines changed

14 files changed

+1537
-119
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ This creates:
457457
| `ralph-starter run [task]` | Run an autonomous coding loop |
458458
| `ralph-starter fix [task]` | Fix build errors, lint issues, or design problems |
459459
| `ralph-starter auto` | Batch-process issues from GitHub/Linear |
460+
| `ralph-starter task <action>` | Manage tasks across GitHub and Linear (list, create, update, close, comment) |
460461
| `ralph-starter integrations <action>` | Manage integrations (list, help, test, fetch) |
461462
| `ralph-starter plan` | Create implementation plan from specs |
462463
| `ralph-starter init` | Initialize Ralph Playbook in a project |

docs/docs/cli/task.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
sidebar_position: 3
3+
title: task
4+
description: Manage tasks across GitHub and Linear
5+
keywords: [cli, task, command, github, linear, issues, unified, assignee]
6+
---
7+
8+
# ralph-starter task
9+
10+
Unified task management across GitHub and Linear. Issues stay where they are -- ralph-starter detects the platform from the ID format and routes operations accordingly.
11+
12+
## Synopsis
13+
14+
```bash
15+
ralph-starter task list [options]
16+
ralph-starter task create --title "..." [options]
17+
ralph-starter task update <id> [options]
18+
ralph-starter task close <id> [options]
19+
ralph-starter task comment <id> "message" [options]
20+
```
21+
22+
## Description
23+
24+
The `task` command provides a single interface for managing issues on both GitHub and Linear. Instead of switching between `gh issue` and Linear's UI, you can:
25+
26+
- **List** tasks from both platforms in a unified table
27+
- **Create** issues on either platform
28+
- **Update** status, priority, or assignee
29+
- **Close** issues with optional comments
30+
- **Comment** on issues
31+
32+
### Smart ID Detection
33+
34+
ralph-starter automatically detects which platform an issue belongs to based on the ID format:
35+
36+
| Format | Platform | Example |
37+
|--------|----------|---------|
38+
| `#123` or `123` | GitHub | `ralph-starter task close #42` |
39+
| `TEAM-123` | Linear | `ralph-starter task update ENG-42 --status "In Progress"` |
40+
41+
You can always override detection with `--source github` or `--source linear`.
42+
43+
## Actions
44+
45+
### `task list`
46+
47+
List tasks from all configured integrations.
48+
49+
```bash
50+
# List from all sources
51+
ralph-starter task list
52+
53+
# List from GitHub only
54+
ralph-starter task list --source github --project owner/repo
55+
56+
# List from Linear only
57+
ralph-starter task list --source linear
58+
59+
# Filter by label and status
60+
ralph-starter task list --label "bug" --status "open" --limit 10
61+
```
62+
63+
### `task create`
64+
65+
Create a new issue on GitHub or Linear.
66+
67+
```bash
68+
# Create on GitHub (default)
69+
ralph-starter task create --title "Add dark mode" --project owner/repo
70+
71+
# Create on Linear
72+
ralph-starter task create --title "Add dark mode" --source linear --priority P1
73+
74+
# Create with assignee and labels
75+
ralph-starter task create --title "Fix auth bug" --source github \
76+
--project owner/repo --assignee octocat --label "bug,urgent"
77+
```
78+
79+
### `task update`
80+
81+
Update an existing issue.
82+
83+
```bash
84+
# Update status on Linear (auto-detected from ID)
85+
ralph-starter task update ENG-42 --status "In Progress"
86+
87+
# Assign a task
88+
ralph-starter task update ENG-42 --assignee ruben
89+
90+
# Update priority
91+
ralph-starter task update ENG-42 --priority P0
92+
93+
# Update a GitHub issue
94+
ralph-starter task update #123 --assignee octocat --project owner/repo
95+
```
96+
97+
### `task close`
98+
99+
Close an issue with an optional comment.
100+
101+
```bash
102+
# Close a Linear issue
103+
ralph-starter task close ENG-42
104+
105+
# Close with a comment
106+
ralph-starter task close #123 --comment "Fixed in PR #456" --project owner/repo
107+
```
108+
109+
### `task comment`
110+
111+
Add a comment to an issue.
112+
113+
```bash
114+
ralph-starter task comment ENG-42 "Working on this now"
115+
ralph-starter task comment #123 "Needs design review" --project owner/repo
116+
```
117+
118+
## Options
119+
120+
| Option | Description | Default |
121+
|--------|-------------|---------|
122+
| `--source <source>` | Filter by source: `github`, `linear`, or `all` | `all` (list) / `github` (create) |
123+
| `--project <name>` | Project filter (`owner/repo` for GitHub, team name for Linear) | - |
124+
| `--label <name>` | Filter by label or set labels (comma-separated) | - |
125+
| `--status <status>` | Filter by status or set status on update | - |
126+
| `--limit <n>` | Max tasks to fetch | `50` |
127+
| `--title <title>` | Task title (for create) | - |
128+
| `--body <body>` | Task description (for create) | - |
129+
| `--priority <p>` | Priority: `P0`, `P1`, `P2`, `P3` | - |
130+
| `--assignee <name>` | Assign to team member (GitHub username or Linear display name) | - |
131+
| `--comment <text>` | Comment text (for close/update) | - |
132+
133+
## Assignee Resolution
134+
135+
### GitHub
136+
137+
Pass a GitHub username directly:
138+
139+
```bash
140+
ralph-starter task update #123 --assignee octocat --project owner/repo
141+
```
142+
143+
### Linear
144+
145+
ralph-starter resolves display names, full names, and email prefixes to Linear user IDs:
146+
147+
```bash
148+
# Match by display name
149+
ralph-starter task update ENG-42 --assignee "Ruben"
150+
151+
# Match by email prefix
152+
ralph-starter task update ENG-42 --assignee "ruben"
153+
```
154+
155+
Matching is case-insensitive. If no match is found, ralph-starter shows available team members.
156+
157+
## Prerequisites
158+
159+
At least one integration must be configured:
160+
161+
```bash
162+
# GitHub (via GitHub CLI)
163+
gh auth login
164+
165+
# Linear (via API key)
166+
ralph-starter config set linear.apiKey lin_api_xxxxxxxxxxxx
167+
```
168+
169+
Check integration status:
170+
171+
```bash
172+
ralph-starter integrations list
173+
```
174+
175+
## See Also
176+
177+
- [`ralph-starter auto`](auto.md) -- Batch-process tasks autonomously
178+
- [`ralph-starter integrations`](integrations.md) -- Manage integrations
179+
- [`ralph-starter auth`](auth.md) -- Authenticate with services
180+
- [GitHub Source](../sources/github.md) -- GitHub integration details
181+
- [Linear Source](../sources/linear.md) -- Linear integration details

docs/docs/sources/github.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,26 @@ Verify your authentication:
175175
ralph-starter source test github
176176
```
177177

178+
## Task Management
179+
180+
Beyond fetching specs, you can create, update, and close GitHub issues directly from the CLI:
181+
182+
```bash
183+
# List open issues
184+
ralph-starter task list --source github --project owner/repo
185+
186+
# Create an issue
187+
ralph-starter task create --title "Add dark mode" --project owner/repo --assignee octocat
188+
189+
# Update an issue
190+
ralph-starter task update #42 --assignee octocat --project owner/repo
191+
192+
# Close an issue
193+
ralph-starter task close #42 --comment "Fixed in PR #100" --project owner/repo
194+
```
195+
196+
See [`ralph-starter task`](/docs/cli/task) for full details.
197+
178198
## Tips
179199

180200
1. **Use labels effectively** - Create a "ready-to-build" or "ralph" label for issues that are well-specified

docs/docs/sources/linear.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,31 @@ Create these labels in Linear:
136136
2. Add comments with build progress
137137
3. Close issues when build succeeds
138138

139+
## Task Management
140+
141+
Beyond fetching specs, you can create, update, close, and assign Linear issues from the CLI:
142+
143+
```bash
144+
# List issues from Linear
145+
ralph-starter task list --source linear
146+
147+
# Create an issue on a specific team
148+
ralph-starter task create --title "Add dark mode" --source linear --priority P1
149+
150+
# Assign an issue (resolves display name to user ID automatically)
151+
ralph-starter task update ENG-42 --assignee ruben
152+
153+
# Update status
154+
ralph-starter task update ENG-42 --status "In Progress"
155+
156+
# Close an issue
157+
ralph-starter task close ENG-42 --comment "Shipped in v1.2"
158+
```
159+
160+
Assignee resolution is case-insensitive and matches against display name, full name, and email prefix. If no match is found, ralph-starter shows available team members.
161+
162+
See [`ralph-starter task`](/docs/cli/task) for full details.
163+
139164
## Tips
140165

141166
1. **Write detailed issues** - Linear's rich markdown support is perfect for detailed specs

docs/sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const sidebars: SidebarsConfig = {
4646
'cli/config',
4747
'cli/source',
4848
'cli/auto',
49+
'cli/task',
4950
'cli/auth',
5051
'cli/setup',
5152
'cli/check',

src/cli.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { runCommand } from './commands/run.js';
1616
import { setupCommand } from './commands/setup.js';
1717
import { skillCommand } from './commands/skill.js';
1818
import { sourceCommand } from './commands/source.js';
19+
import { taskCommand } from './commands/task.js';
1920
import { templateCommand } from './commands/template.js';
2021
import { startMcpServer } from './mcp/server.js';
2122
import { formatPresetsHelp, getPresetNames } from './presets/index.js';
@@ -61,7 +62,7 @@ program
6162
.option('--docker', 'Run in Docker sandbox (coming soon)')
6263
.option('--prd <file>', 'Read tasks from a PRD markdown file')
6364
.option('--max-iterations <n>', 'Maximum loop iterations (auto-calculated if not specified)')
64-
.option('--agent <name>', 'Specify agent (claude-code, cursor, codex, opencode)')
65+
.option('--agent <name>', 'Specify agent (claude-code, cursor, codex, opencode, openclaw)')
6566
.option('--from <source>', 'Fetch spec from source (file, url, github, todoist, linear, notion)')
6667
.option('--project <name>', 'Project/repo name for --from integrations')
6768
.option('--label <name>', 'Label filter for --from integrations')
@@ -275,6 +276,24 @@ program
275276
});
276277
});
277278

279+
// ralph-starter task - Manage tasks across GitHub and Linear
280+
program
281+
.command('task [action] [args...]')
282+
.description('Manage tasks across GitHub and Linear (list, create, update, close, comment)')
283+
.option('--source <source>', 'Source: github, linear, or all (default: all)')
284+
.option('--project <name>', 'Project filter (owner/repo for GitHub, team name for Linear)')
285+
.option('--label <name>', 'Filter by label')
286+
.option('--status <status>', 'Filter by status or set status on update')
287+
.option('--limit <n>', 'Max tasks to fetch (default: 50)', '50')
288+
.option('--title <title>', 'Task title (for create)')
289+
.option('--body <body>', 'Task description (for create)')
290+
.option('--priority <p>', 'Priority: P0, P1, P2, P3')
291+
.option('--comment <text>', 'Comment text (for close/update)')
292+
.option('--assignee <name>', 'Assign to team member (GitHub username or Linear display name)')
293+
.action(async (action: string | undefined, args: string[], options) => {
294+
await taskCommand(action, args, options);
295+
});
296+
278297
// ralph-starter pause - Pause a running session
279298
program
280299
.command('pause')
@@ -324,7 +343,7 @@ program
324343
.option('--pr', 'Create a pull request when done')
325344
.option('--validate', 'Run tests/lint/build after each iteration')
326345
.option('--max-iterations <n>', 'Maximum loop iterations')
327-
.option('--agent <name>', 'Specify agent (claude-code, cursor, codex, opencode)')
346+
.option('--agent <name>', 'Specify agent (claude-code, cursor, codex, opencode, openclaw)')
328347
.action(async (action: string | undefined, args: string[], options) => {
329348
await templateCommand(action, args, options);
330349
});

0 commit comments

Comments
 (0)