Skip to content

🤖 fix: stop letting plan run as a sub-agent#3304

Merged
ammario merged 2 commits into
mainfrom
plan-agents-c7kx
May 17, 2026
Merged

🤖 fix: stop letting plan run as a sub-agent#3304
ammario merged 2 commits into
mainfrom
plan-agents-c7kx

Conversation

@ammar-agent
Copy link
Copy Markdown
Collaborator

@ammar-agent ammar-agent commented May 17, 2026

Summary

Stop letting the Plan agent be spawned as a sub-agent, and update the orchestrate playbook to match. The runtime already restricts plan-mode edits to the plan file via validatePlanModeAccess, but plan still had subagent.runnable: true with a wide-open add: ['.*'] tool list and no read-only prose injunction — so a plan sub-agent would happily emit file_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.md defines tools with add: ['.*'] and only narrows the list via remove for image/git-patch/config/skills/analytics tools. file_edit_* and bash are left enabled by design — the comment says they "ARE available but restricted to plan file only at runtime."
  • That runtime restriction lives in src/node/services/tools/fileCommon.ts::validatePlanModeAccess (gated by config.planFileOnly && config.planFilePath) and is wired in via src/node/services/aiService.ts (planFileOnly: agentIsPlanLike).
  • src/node/services/tools/task.ts:302 already prevents a plan parent from spawning anything other than explore. 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:
    if (frontmatter.subagent?.runnable !== true) {
      return Err(
        `Task.create: agentId is not runnable as a sub-agent (${agentId}). ${hint}`,
      );
    }
    Flipping the flag is enough; no new enforcement code is needed.
  • The orchestrate skill (restored in 🤖 feat: restore Orchestrator as hidden /orchestrate skill #3295) previously delegated complex work to plan sub-agents and relied on the post-propose_plan auto-handoff. With plan non-runnable, those task calls would now fail at Task.create, so orchestrate is updated alongside.

Implementation

src/node/builtinAgents/plan.md: subagent.runnable: truefalse, with a rationale comment explaining why future contributors should not re-enable it.

src/node/builtinSkills/orchestrate.md: removed every recommendation to delegate to plan. Orchestrate now sends all implementation work to exec, and gets the "higher complexity" benefit from parallel explore tasks shaping a richer exec brief (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 by scripts/generate-builtin-agents.sh, scripts/generate-builtin-skills.sh, and make fmt.

No agent inherits from plan (only desktop and explore inherit from exec), 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.create for every non-runnable agent already (e.g., compact, name_workspace). Top-level plan workspaces — the only legitimate use case for plan — are unaffected because runnable only gates sub-agent spawning.

The legacy handleSuccessfulProposePlanAutoHandoff flow in taskService.ts remains 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 from Task.create.

The only behavior change a caller could notice is task({ agentId: "plan", ... }) returning Task.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

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.
@mintlify
Copy link
Copy Markdown

mintlify Bot commented May 17, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Mux 🟢 Ready View Preview May 17, 2026, 9:22 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@ammar-agent
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/node/builtinAgents/plan.md
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.
@ammar-agent
Copy link
Copy Markdown
Collaborator Author

@codex review

Updated to also drop plan from the orchestrate playbook. Orchestrate now sends all implementation work to exec (with richer briefs shaped by parallel explore tasks when needed), and a new note explicitly states that plan is intentionally not runnable as a sub-agent.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ 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".

@ammario ammario merged commit da7ff65 into main May 17, 2026
24 checks passed
@ammario ammario deleted the plan-agents-c7kx branch May 17, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants