[KongchangAI]
· 3 min read· 1,505 words

Planning Agent Keeps Stealing the Work? Here's the Fix: Make It Unable to Write a Single File

Planning Agent Keeps Stealing the Work? Here's the Fix: Make It Unable to Write a Single File

After three permission defense failures, Atomic Agent finally chose to completely prohibit the planner from writing anything.

The open-source project Atomic Agent's Fusion mode uses a planner-worker architecture, with cloud models planning and local models executing to save API tokens. The author disclosed three permission-control failures: delegation returned ok even when all Workers failed, opening soft gating by mistake; the needs_orchestrator handoff became an exception channel that let 13 writes slip through; and in an earlier version the permission check was never called by the executor, so unit tests passed but production never triggered it. The final solution bans all mutation operations during the planner's entire turn, treats all MCP tools as writes regardless of declared permission hints, and returns rejection messages to protect the KV cache. The author admits this guardrail is the most painful—the planning model once spent 22 minutes writing a fix into the rejection message—but still kept it, because planner overreach is the root cause of architectural degradation.

In multi-agent collaboration architectures, separating the responsibilities of the Planner and the Worker is a common design. But an awkward reality is that planning agents often can't resist doing the work themselves. The author of the open-source project Atomic Agent shared the full process of solving this problem on Reddit, and the solution was surprising—completely prohibit the planner from writing any files.

Planning agent write permission control

Fusion Architecture: Separating Planning from Execution

Atomic Agent is an MIT-licensed open-source project, and its Fusion mode adopts a planner-worker architecture: one model is responsible for task planning, decomposition, and review, while multiple Worker models execute the concrete work in parallel. A typical configuration uses a cloud model for planning and local models for execution, so that only the planning stage consumes API tokens.

The core challenge of this architecture is not model capability, but the design of permission boundaries—what exactly is the planner allowed to do. After trying multiple approaches, the author's team ultimately gave an extreme answer: nothing is allowed. The planner can only read, delegate, and reply.

Three Defensive Lines That Failed

The author disclosed in detail three failed attempts at permission control, each exposing a different design flaw.

The false success of soft gating. The initial design was: the planner is prohibited from writing before the first successful delegation. But the problem was that fusion.delegate returned an ok status even when all Workers failed. The planner saw the success signal, the gate opened, and as a result it wrote 15 files and executed 5 commands on its own. The whole process "looked normal," but Fusion mode existed in name only.

The loophole in requirement handoff. The team allowed Workers to return tasks via needs_orchestrator when a task was too large or unclear. This mechanism opened an exception channel for the planner, and 13 writes slipped through this gap. In one run, 4 out of 6 tasks took this path.

Dead-code gating. In an earlier version, the gating logic was never called by the executor at all—the step executor only forwarded the plan-mode parameter, and the permission check was never triggered. In one driven test, the planner wrote all four files without any obstruction and with zero rejections. All unit tests passed, but this gate was never queried on the production path.

MCP (Model Context Protocol) is an open standard proposed by Anthropic at the end of 2024 to let large language models call external tools and data sources in a unified way, comparable to a "USB-C interface for AI applications." In this case, all of the planner's tool calls were exposed through an MCP server, so the author treated "all MCP tools" as mutation operations across the board. This conservative strategy stems from a key judgment: MCP servers are often third-party code, and the permission hints they declare (such as readOnly) are merely self-descriptions that cannot be forcibly verified by the host program. A tool declared as read-only may well perform write operations internally, so trusting its metadata is equivalent to handing the security boundary to uncontrolled code. This is also the fundamental reason the architecture chooses "guilty by default" rather than "harmless by default."

Current Solution: No Mutation Operations During the Entire Turn

The current rule is very simple: during the planner's entire turn, it cannot perform any mutation operations.

All MCP tools are treated as mutation operations, regardless of what permission hints they declare—because they are third-party code, and their self-descriptions cannot be trusted. Workers are responsible for writing files; the planner can only read files, run read-only checks, and re-delegate tasks.

The method of rejection was also carefully considered: rather than removing write tools from the planner's tool catalog, a short message is attached to the tool call result—"You are responsible for planning, Workers are responsible for writing." This is done to protect the KV cache of the local planning model: if tools were dynamically removed, the prompt prefix would change, and every rule trigger would invalidate the cache, causing a significant performance loss.

KV cache (Key-Value Cache) is a key optimization in Transformer inference: the self-attention mechanism must recompute the key-value vectors of all previous tokens when generating each token. Once these intermediate results are cached, the cost of continuously generating new tokens drops substantially. The tradeoff is that the cache is strictly bound to the prefix. Once the system prompt or tool definitions at the beginning of the prompt change, the entire cache becomes invalid and must be fully recomputed. This is exactly why the author does not dynamically remove write tools from the planner's tool catalog, but instead chooses to attach a rejection message to the tool call return value—the former changes the prompt prefix and breaks the cache every time the rule triggers, while the latter places the hint in the call result, keeping the prefix stable and maintaining the inference performance of the local model.

plan-mode is in many Agent frameworks a runtime state flag: once enabled, only read-only operations are allowed, and a plan is generated without making changes. In this case, the failure of "dead-code gating" precisely exposed the fragility of this state propagation—the executor only forwarded the plan-mode parameter downward, but never actually queried that flag in the tool call chain, so the permission check became dangling logic that was never reached. Unit tests passed while the production path failed, which shows that the tests covered the gating function itself, not the integration fact of "whether the executor called the gate." This also suggests that multi-agent systems need end-to-end driven tests for permission paths, not just function-level assertions.

The Most Painful Guardrail: 22 Minutes of "Armchair Strategy"

The author admits that among all measured metrics, this rule is the most "painful" one.

In one run, the local planning model found a real bug, diagnosed it completely correctly, and then spent 22 minutes writing the fix into the text of the rejection message—because it was not allowed to write to files.

The team still kept this rule. The reason is straightforward: the planner doing the work itself is precisely the root cause of Fusion mode quietly degrading twice. A slower planner handoff will at least show up in the trace, and the corresponding remedy is to give Workers better task briefs.

Migrating Other Agent Configurations

Atomic Agent provides importers for six Agents, each supporting --dry-run mode without writing anything. API keys are migrated only when --migrate-secrets is explicitly used.

Supported import sources include Claude Code, Codex, Hermes, OpenClawAd, Pi, and Oh-My-Pi, covering dimensions such as skills, memory, MCP servers, and session records. It should be noted that memory data from Hermes and OpenClaw cannot be migrated—the two have different storage formats and no exchange standard, and the author chose to state this directly rather than leave users facing an empty memory panel.

The project runs as a terminal Agent, and a desktop application (supporting Mac, Windows, and Linux) was recently added. Approval options on the desktop side include "allow once" and "reject/abort run," and users can switch modes in the editor to reduce confirmation frequency.

Implications for Planner-Worker Architectures

Atomic Agent's practice reveals a counterintuitive conclusion: the hardest thing to design in a planner-worker architecture is not the task decomposition algorithm, but the strict enforcement of permission boundaries. All three failures stemmed from "leaving room"—soft gating, exception channels, and uncalled checks—and each instance of room led to architectural degradation.

At the end of the post, the author asked the community: if you are also running a planner-worker architecture, would you let the planner write? Or did you ultimately choose zero permissions as well?

For developers building multi-agent systems, the value of this case lies in this: every "what if" in permission design can become an entry point for system degradation, and while complete prohibition brings efficiency friction, it at least makes the problem visible and traceable.

One-line Summary

After three permission defense lines failed, Atomic Agent ultimately chose to completely prohibit the planner from writing anything.

Paragraph Summary

The Fusion mode of the open-source project Atomic Agent adopts a planner-worker architecture, with cloud models planning and local models executing to save API tokens. The author disclosed three failures in permission control: delegation results still returned ok even when all Workers failed, causing soft gating to be mistakenly opened; the needs_orchestrator handoff mechanism became an exception channel that let 13 writes slip through; and in an earlier version the permission check was never called by the executor, so unit tests passed but the production path was never triggered. The final solution is to prohibit all mutation operations during the planner's entire turn, treating all MCP tools as write operations regardless of what permission hints they declare, and giving rejections as return-value messages to protect the KV cache. The author admits this guardrail is the most painful in cost—the planning model once spent 22 minutes writing a fix into the rejection message—but still chose to keep it, because planner overreach is precisely the root cause of architectural degradation.

#Atomic Agent#planner-worker architecture#agent permissions#MCP#KV cache#multi-agent systems
Share:

Related articles