Add task_stage assign action — claim minus the stage advance#4
Open
memphyssk wants to merge 1 commit intokeshrath:mainfrom
Open
Add task_stage assign action — claim minus the stage advance#4memphyssk wants to merge 1 commit intokeshrath:mainfrom
memphyssk wants to merge 1 commit intokeshrath:mainfrom
Conversation
Existing `claim` action conflates two operations: assign an agent AND
advance from the first stage to the next. For the default pipeline
(backlog → spec → plan → ...) this is fine — backlog isn't a do-work
stage, so claim's auto-advance from backlog to spec matches intent.
For custom pipelines whose first stage is itself a do-work stage
(read context, pull from queue, load principles), there's no way to
hand a task to an agent without also moving the work forward. Today
that means either:
(a) call `task_update assign_to=...` and lose the confidence gate +
claim event + status flip from claim, or
(b) call `claim` and accept an unwanted stage advance.
This PR adds `task_stage({action: "assign"})` — the same path as claim
(pending check, confidence gate, claim event, status → in_progress)
but the stage stays put. About 30 lines in the domain layer + 4 in the
transport layer.
- domain/tasks.ts: new TaskService.assign() — clone of claim() minus
the firstStage→nextStage logic. Same gating, same event, same error
semantics. Status flips pending → in_progress (a "pending + assigned"
state would be incoherent for the next-task picker).
- transport/mcp.ts: action enum gains "assign"; tool description updated.
- transport/mcp-handlers.ts: handleStage dispatches "assign" → tasks.assign().
- tests/tasks.test.ts: 5 domain tests (default pipeline, custom pipeline,
reject non-pending, event emission, confidence gate parity).
- tests/mcp.test.ts: 5 MCP tests (assign without advance, custom claimer,
reject after claim, parity coverage).
REST has no `/claim` endpoint today, so no REST surface change.
All 440 tests pass; npm run check (typecheck + lint + format:check + test) green.
memphyssk
pushed a commit
to memphyssk/agent-tasks
that referenced
this pull request
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
task_stage({action: "assign"})— same semantics asclaim(assign agent, flip status toin_progress, emittask:claimed, respect confidence gate) but does NOT advance the stage.Why
claimconflates two operations:For the default pipeline (
backlog → spec → plan → ...) this is correct.backlogisn't a do-work stage; it just means "queued." Claiming naturally advances tospec(the first do-work stage). Same shape for most projects using the default pipeline.For custom pipelines registered via
task_config(action: \"pipeline\")whose first stage is itself a do-work stage, this becomes friction. Concrete example from a downstream framework:I-0-pullis the head agent's "read principles + scope interpretation + tooling" stage — a real do-work stage that needs to happen before planning. When the head wants to pick up a queued task atI-0-pullwithout skipping context-read and jumping straight toI-1-plan, today the only options are:claimI-1-plan, skippingI-0-pulltask_update({assign_to: ...})task:claimedevent, no status flipNeither is right. The natural verb is "assign without advancing" — claim's contract minus one step.
How
assignis a clone ofclaimwith thefirstStage → nextStagelogic removed. Stage stays put. Status flipspending → in_progress(a "pending + assigned" state would be incoherent for the next-task picker, which would otherwise re-hand the task out).claimclaimmin_confidence_for_claim)assigned_toset to claimerin_progresstask:claimedeventChanges
src/domain/tasks.tsTaskService.assign()(~30 LOC) — same gating, same event, same error semantics, no stage motionsrc/transport/mcp.tstask_stageaction enum gains\"assign\"; tool description updatedsrc/transport/mcp-handlers.tshandleStagedispatches\"assign\"→tasks.assign()REST has no
/api/tasks/:id/claimendpoint today, so no REST surface change. (ExistingPUT /api/tasks/:id/stageis advance/regress only.)Tests
10 new tests, all passing:
tests/tasks.test.ts(5):task:claimedeventmin_confidence_for_claimgate (parity withclaim)tests/mcp.test.ts(5):claimerargOpen design choices (happy to adjust)
claimerarg name. MCP handler readsoptString(args, 'claimer')for bothclaimandassign. Avoids adding a new arg name; keeps the schema small. Tool description spells out that it applies to both.task:claimedevent channel. Bothclaimandassignare "agent took ownership" — same event type makes downstream consumers (knowledge bridge, agent-comm, dashboard) work without changes.claim. Reassignment is a future PR; this is the minimal surgical addition.Pairing
This pairs naturally with the
task_listtagsfilter PR (#3) — same downstream framework needed both. Independent reviews welcome; either can land first.🤖 Generated with Claude Code