feat(features,web,desktop): an agent with no plan is messaged, stopped, and changed like any other, its summary naming no plan
Merged
DA
4d ago+189+189+012345678901234567890123456789-93-93-01234567890123456789
Step 8 (second part) of the automations plan (docs/proposals/automations-scope.md). It is stacked on #2710.
What changes
- A planless agent works through every agent route.
reachedAgentadmits an agent with no plan again, so message, stop, model and effort, rename, archive, MCP servers, transcript, pull request, changes, and terminals all work on one. #2663 had refused it until the wire could say so. This is what the desktop agent page needs to drive one. - The summary's
planIdis nullable.codingAgentSummarySchema.planIdis nowNullOr(uuid).- Only a read that names the agent can answer a planless one. A plan's list holds the plan's own agents, and the account Inbox keeps planless items under their own keys (#2688).
- A build that predates planless agents never learns such an id, so it never meets a null.
status.tsdrops thePlannedCodingAgentnarrowing, the plan list and the Start answer no longer filter, andcodingAgentPageSchemano longer overridesplanId(the summary carries it).
- The desktop handles a null plan in its three places:
- The notices ledger passes over a planless agent named by a message's answer, since every read it keeps is a plan's; step 9 gives planless agents notices of their own.
- A message refused for an unreachable repository says its words alone for a planless agent, since every remedy is pressed on a plan.
- A test fixture.
- Wire goldens. Only
planId's schema changes, from a uuid to a uuid or null, incodingAgentSummarySchemaand the four answers that carry it. They were re-recorded withLUKE_UPDATE_FIXTURES=1. None of these is a model-facing tool schema.
Tests
coding-agents-app.test.ts: a planless agent is messaged (eve gets the line, and the answer's summary hasplanIdnull) and its transcript is read by a member. This replaces the test that asserted 404s.coding-agent-model.test.ts: a repository-unreachable refusal names the plan's remedy on a plan, and only the words for a planless agent.agent-notices.test.ts: a planless agent in a message's answer reads no plan list and announces nothing. This fails without the guard.
pnpm check:affected passes. The desktop changes are type-level handling of a null plan, with no new drawing; CI cannot verify the Mac UI, and ./scripts/verify.sh was not run (LUKE-159 stands in before the first release).
🤖 Generated with Claude Code
Summary by cubic
An agent with no plan now works through every agent route—messaged, stopped, and changed like any other—so the desktop agent page can drive one. Previously these routes refused a planless agent because the wire summary required a planId; codingAgentSummarySchema.planId is now NullOr(uuid), the summary carries it, and the plan-only filters are gone.
- Only a read that names the agent answers a planless one: a plan's list holds the plan's own agents, and the account Inbox keeps planless items under their own keys.
- The desktop passes over a planless agent in the notices ledger, and a repository-unreachable refusal keeps the remedy that needs no plan—giving the repository to Luke on GitHub—while saying only its words where the remedy is pressed on the plan.
- Wire goldens were re-recorded for the nullable
planId; tests replace the former 404 assertions with messaging, transcript, refusal, and notice coverage.