🤖 fix: stop letting plan run as a sub-agent#3304
Conversation
Plan's whole job is to produce a plan for the user to review. Nothing downstream consumes a plan sub-agent's report (the auto-handoff after propose_plan was removed in 351c772), so spawning plan as a child served no purpose. Worse, plan inherits add: ['.*'] without a prose read-only injunction, so it would happily emit file_edit_* calls; the runtime guard in validatePlanModeAccess rejected them per-call, but the agent kept trying every turn — burning tokens and eroding the "plan never touches code" guarantee. Flip plan.md to subagent.runnable: false. TaskService.create already rejects non-runnable agentIds with a clear error, so any parent that asks for agentId: "plan" now gets a clean rejection at task creation before any tool calls happen.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 34bd6badfe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The orchestrate playbook (restored in #3295) explicitly told the calling agent to delegate complex work to `plan` sub-agents. With plan no longer runnable as a sub-agent, those `task` calls would fail at Task.create. Update orchestrate to delegate all implementation work to `exec`, investing in richer briefs (via parallel `explore` tasks for context) when subtasks are non-trivial. The skill is purely instructional, so this is a prompt-only change.
|
@codex review Updated to also drop |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Stop letting the Plan agent be spawned as a sub-agent, and update the
orchestrateplaybook to match. The runtime already restricts plan-mode edits to the plan file viavalidatePlanModeAccess, but plan still hadsubagent.runnable: truewith a wide-openadd: ['.*']tool list and no read-only prose injunction — so a plan sub-agent would happily emitfile_edit_*calls every turn. The runtime would reject each call, but the model kept trying, burning tokens and eroding the "plan never touches code" guarantee. There is no legitimate use case for a plan sub-agent: nothing downstream consumes its report.Background
src/node/builtinAgents/plan.mddefines tools withadd: ['.*']and only narrows the list viaremovefor image/git-patch/config/skills/analytics tools.file_edit_*andbashare left enabled by design — the comment says they "ARE available but restricted to plan file only at runtime."src/node/services/tools/fileCommon.ts::validatePlanModeAccess(gated byconfig.planFileOnly && config.planFilePath) and is wired in viasrc/node/services/aiService.ts(planFileOnly: agentIsPlanLike).src/node/services/tools/task.ts:302already prevents a plan parent from spawning anything other thanexplore. The missing half was preventing an exec parent from spawning a plan child.TaskService.create(src/node/services/taskService.ts:1019) already has the matching guard:orchestrateskill (restored in 🤖 feat: restore Orchestrator as hidden /orchestrate skill #3295) previously delegated complex work toplansub-agents and relied on the post-propose_planauto-handoff. With plan non-runnable, thosetaskcalls would now fail atTask.create, so orchestrate is updated alongside.Implementation
src/node/builtinAgents/plan.md:subagent.runnable: true→false, with a rationale comment explaining why future contributors should not re-enable it.src/node/builtinSkills/orchestrate.md: removed every recommendation to delegate toplan. Orchestrate now sends all implementation work toexec, and gets the "higher complexity" benefit from parallelexploretasks shaping a richerexecbrief (goal + constraints + acceptance) rather than from a plan handoff. Added an explicit note that "plan is intentionally not runnable as a sub-agent."src/node/services/agentDefinitions/builtInAgentContent.generated.ts,src/node/services/agentSkills/builtInSkillContent.generated.ts,docs/agents/index.mdx: regenerated snapshots picked up byscripts/generate-builtin-agents.sh,scripts/generate-builtin-skills.sh, andmake fmt.No agent inherits from
plan(onlydesktopandexploreinherit fromexec), so no other built-in shape changes.Validation
bun test src/node/services/agentDefinitions/builtInAgentDefinitions.test.ts✓bun test src/node/services/taskService.test.ts✓bun test src/node/services/tools/file_edit_operation.test.ts src/node/services/tools/task.test.ts✓bun test src/node/services/agentResolution.test.ts src/node/services/agentDefinitions/ src/node/services/streamContextBuilder.test.ts src/node/services/aiService.test.ts✓make static-check✓ (lint + typecheck + fmt-check + docs sync)Risks
Low. The change is one frontmatter flag flip on a built-in agent plus prompt-only edits to the orchestrate skill. The runtime path that handles "user asked for an unrunnable sub-agent" is exercised by
TaskService.createfor every non-runnable agent already (e.g.,compact,name_workspace). Top-level plan workspaces — the only legitimate use case for plan — are unaffected becauserunnableonly gates sub-agent spawning.The legacy
handleSuccessfulProposePlanAutoHandoffflow intaskService.tsremains in place. It's now effectively defensive code for any historical plan sub-agent workspaces that existed before this change; it cannot be re-entered fromTask.create.The only behavior change a caller could notice is
task({ agentId: "plan", ... })returningTask.create: agentId is not runnable as a sub-agent (plan). …instead of silently working-and-then-failing. That is the intended outcome.Generated with
mux• Model:anthropic:claude-opus-4-7• Thinking:max• Cost:$6.63