feat(coder): start a coding agent on a developer's task instead of the plan

Merged
DA
8d ago
+369-63

Summary

Dean, on the "+" menu's New coding agent: it "must NOT send the plan". A new agent from the "+" starts on the developer's first message, used as its task. Until now, every Start handed the agent the plan document as its first message, and nothing could carry anything else. This is the service half of that split, agreed with the orchestrator. The desktop's "+" row and draft tab come in a PR stacked on this one.

  • The start request gains an optional task (codingAgentStartRequestSchema, so also the view params, the gateway, and the act payload). It is trimmed and bounded like a message (MAX_MESSAGE_CHARS, 16,000). host-operator.ts forwards it explicitly, as it does model and effort.
  • startEndpoint: with a task, the eve session opens with the task as its first message, and the plan is never sent. The agent still works in the plan's repository, under the same checks as before (owned plan, repository set, GitHub reaches it, model choice, idempotency key). A Start without a task is byte-for-byte what it was.
  • Body cap kept, sized for the task: MAXIMUM_START_BODY_BYTES grows from 4,096 to 6 Ɨ MAX_MESSAGE_CHARS + 4,096, so a task at its bound still fits at JSON's widest escape. This is the same rule the message route's cap uses.
  • Store (migration 0067_coding_agent_task): coding_agent.task text NULL is added, and plan_snapshot becomes nullable. Exactly one of the two holds what the agent was handed, so a task agent keeps no copy of the plan. NewCodingAgent takes the pair as a union type (CodingAgentBriefText), so the compiler won't build a row with both or neither. drizzle-schema.test.ts checks the module against the migrated database.
  • Coder instructions: coderInstructions(repository, brief). The plan wording is unchanged character for character. The task wording says the job is "the task the developer gave as the first message", reads the code the task touches, and says nothing of a plan. Everything else (checkout, branch rule, commit identity, checks, delegation, never printing secrets) is shared.
  • CodingAgentSummary.brief (plan | task, optional): every list, start, and change answer says what the agent was handed. The desktop uses it to draw a task as the developer's own message, not the "Plan" card. It is optional so a desktop reading an older service treats a missing value as the plan. An older desktop ignores the new key, since answers ignore unknown keys.
  • Docs: apps/web/server/README.md (coding-agent service and routes), docs/PLANNING.md, and PRIVACY.md. Deleting a plan now removes "the copy of the plan, or the task you wrote in its place" an agent was handed. This is a product-facing wording change, called out here.

The never-secrets rules are unchanged: a task is the developer's own words, stored and shown exactly like a message to an agent.

Evidence

  • Platform-independent checks: ./scripts/check.sh exits 0.
  • macOS Electron verification (./scripts/verify.sh): not run. CI could not verify the Mac. This PR changes no UI. Its one desktop change is the main process forwarding task in host-operator.ts. Done on a Linux VM; LUKE-159 is the manual Mac pass.

Visual evidence

  • None: no UI changes in this PR.

Physical-device evidence

  • Screenshot or screen recording: not attached

Tests

Each fails without this change:

  • coding-agents-app.test.ts:
    • A Start naming a task (padded with whitespace) opens eve with the trimmed task as the only first message, never the plan. The stored row has the task and a null plan_snapshot, and is in the plan's repository. The answer and the list say brief: task.
    • A task one past the bound, or whitespace only, is refused as invalid-request and opens nothing. A task at the bound made entirely of a character JSON escapes to six bytes is accepted (the old 4,096-byte cap refused it).
    • The existing Start test now also asserts brief: plan and task: null.
  • coding-agent-store.test.ts: a task Start stores the task and no plan copy, and reads back the same.
  • coder-agent.test.ts:
    • The task wording names the task as the job, keeps the repository, and contains no "plan".
    • The commit-identity, checkout, and delegation rules hold for both wordings.
  • coding-agent-client.test.ts: a task travels to the service as sent. Before, the client's own request schema refused it and sent nothing.
  • host-operator.test.ts: a Start's task reaches the gateway, and a Start without one carries no task field.

Goldens (LUKE_UPDATE_FIXTURES=1, packages/hosted/fixtures/json-schema/). Seven files, each adding one optional property:

  • coding-agent-wire-codingAgentStartRequestSchema.json and coding-agent-view-codingAgentStartParamsSchema.json: task (string, 1–16,000), not required.
  • coding-agent-wire-codingAgentSummarySchema.json, plus the four answers that embed the summary (coding-agent-wire-codingAgentAnswerSchema, -ListAnswerSchema, coding-agent-view-codingAgentAgentAnswerSchema, -ListAnswerViewSchema): brief (enum plan | task), not required.

Test count: +6.

Invariants

  • ./scripts/check.sh green; verify.sh not run (no UI; Linux VM).
  • JSON Schema goldens changed only as listed above, each an added optional property.
  • Every behavior change has, in this PR, the test that fails without it; no change-detector test added.
  • Gateway envelope goldens unchanged (none exist for coding agents).
  • No new as type assertion outside the allowlisted files.
  • No Effect.runPromise/runSync/runFork outside the runtime edges.
  • No new setTimeout/setInterval/new Promise/AbortController/fs.watch.
  • No Effect, Stream, or Layer written as a statement and dropped.
  • Test count delta listed above.
  • No hand-rolled file replaced.
  • Docs naming the changed parts edited (apps/web/server/README.md, docs/PLANNING.md); AGENTS.md/CLAUDE.md name none of them.
  • PRIVACY.md changed: what deleting a plan removes now names the task an agent may have been handed in the plan's place.
  • No dependency changes.
  • No barrel/door change.

Notes

  • The desktop half (the "+" New coding agent row, which opens a draft agent tab whose first message starts the agent on that task) is stacked on this PR.

šŸ¤– Generated with Claude Code


Devin Review