Repository navigation
Add worker_* tool family (spawn/send/stop/status/list/diff) #223
Copy link
Copy link
Closed
Labels
enhancementNew feature or requestNew feature or requestinfraInfrastructure, CI, tooling, or release workInfrastructure, CI, tooling, or release workpriority:mediumMedium priorityMedium priority
Description
Parent: #217 (delta 1 of 4). Depends on #222 (isWorker flag).
Problem
#217 proposes a manager agent that dispatches work to independent worker sessions running in fresh worktrees. The existing `task` tool is the wrong primitive:
- `task` is synchronous — yields on `ops.prompt()` and joins child output into a `<task_result>` string (`packages/opencode/src/tool/task.ts:138,160-166`). A worker tool must return a session id immediately and never join output back.
- `task` does not create a worktree or set `cwd`.
All needed building blocks already exist (see #217 audit comment). This issue is pure plumbing on top of them.
Tools to add
| Tool | Wraps | Notes |
|---|---|---|
| `worker_spawn({ prompt, agent, branch?, base? })` | `Worktree.Service.create` (`worktree/index.ts:300-306`) → `Session.create({ parentID, isWorker: true, directory })` → `POST /session/:id/prompt_async` (`session.ts:908-948`) | Returns `{ session_id, worktree_path, branch }` synchronously. Generation runs async. |
| `worker_send(session_id, prompt)` | `POST /session/:id/prompt_async` | Injects a follow-up user turn. Non-blocking. |
| `worker_stop(session_id)` | `POST /session/:id/abort` (`session.ts:419-449`) | |
| `worker_status(session_id)` | `GET /session/:id` + `GET /session/status` (`session.ts:99-122`) + git status of worker branch | Returns `{ state: busy|idle, last_message_excerpt, branch, commits_ahead, diff_stats, blocked_on_permission }`. |
| `worker_list()` | `GET /session/:managerID/children` (`session.ts:156-188`) filtered to `isWorker: true` | Returns active workers spawned by this manager. |
| `worker_diff(session_id)` | `git diff ...` in the worker's worktree | The durable artifact. |
Constraints
- All tools are non-blocking. `worker_spawn` returns as soon as the session row is created and `prompt_async` has been dispatched.
- Manager invokes these tools instead of `task` when it wants an independent, attachable worker.
- Workers retain their own permission preset from their agent definition (see Ship manager primary agent + planner/implementor/reviewer subagent roster #224 for the roster).
- `worker_spawn` should refuse if the manager itself is not configured with the `task` permission denied — keeps the manager's role coherent. (Open to discussion.)
Acceptance criteria
- Six tools registered under `packages/opencode/src/tool/worker/` (or wherever `task.ts` lives).
- `worker_spawn` creates worktree + session + dispatches initial prompt in a single tool call.
- Returned `session_id` appears in `GET /session` with `roots: true` (verifies Decouple parentID side effects (add isWorker flag) #222 integration).
- Killing the manager session does not delete the worker (verifies Decouple parentID side effects (add isWorker flag) #222 cascade opt-out).
- Test: end-to-end — manager calls `worker_spawn` with a trivial prompt → worker session exists, runs to idle, branch has expected commits, `worker_diff` returns the diff.
Out of scope
- `@agent-name` invocation syntax (does not exist; tracked separately if pursued).
- Cross-instance / distributed bus.
- Worker→manager push (see docs: record reconciler port and tool typecheck status #225).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestinfraInfrastructure, CI, tooling, or release workInfrastructure, CI, tooling, or release workpriority:mediumMedium priorityMedium priority
Activity