Skip to content

Agent is making edits when on plan mode #53955

Open

Description

@RodrigoAroeira

Description

Multiple times, no matter which model is being used, the plan mode agent has been breaking protocol and running commands which make destructive changes, even when not prompted to do so.

It is sometimes able to make edits in plan mode, and when it isn't, it writes scripts and run it on cli to make edits.

Plugins

No response

OpenCode version

opencode v2.0.24

Steps to reproduce

No response

Screenshot and/or share link

No response

Operating System

CachyOS

Terminal

Konsole

Activity

  1. opencode-agent commented on Oct 8, 2026

    @opencode-agent
    Contributor

    Thanks for the report, @RodrigoAroeira!

    To dig into this, could you share a few more details?

    • Provider and model(s) you saw this with, e.g. anthropic/claude-sonnet-4.6.
    • Which tool made the edits in the cases where it edited directly: was it the edit/write/patch tool, or a shell command such as cat > file, sed -i or a script? In v2.0.24 the Plan agent is denied the edit tools for everything outside ~/.opencode/plan/, so a direct edit through those tools would be a separate bug.
    • Your config: any custom agent/agents or permission settings, and how you entered Plan mode (Tab in the TUI, default_agent, an IDE/ACP client, …).
    • An example: a share link (/share), a screenshot of the tool calls, or the prompt that led to it.

    About the scripts: in v2.0.24 the Plan agent has no rule for shell commands, so they run without asking, and only the Plan mode instructions tell the model not to modify files. Until that changes, you can make Plan ask before running any shell command by adding this to your config:

    {
      "agent": {
        "plan": {
          "permission": { "bash": "ask" }
        }
      }
    }

    You can reply here with the details, or edit the issue. If you edit it, please also leave a comment saying you've updated it so we know you're done.

    Related issues, ordered from most to least likely to match:

  2. RodrigoAroeira commented on Oct 8, 2026

    @RodrigoAroeira
    Author
    • Models: Big Pickle, MiMo-V2.6, LongCat 2.5
    • Edits: Some were done by itself in plan mode; tools: bash, python, git {add,reset,commit}, rm, mv
    • Config: Default config, no changes were ever made
    • Prompts that led to edits: "Ok, in main.rs.tmp I fixed it, but, first, I want to "debloat" main.rs and move RbcHelper into it's own file.", "maybe it could be repl.rs", "What else should I move files"
  3. opencode-agent commented on Oct 8, 2026

    @opencode-agent
    Contributor

    Thanks for the details, @RodrigoAroeira! I was able to reproduce this.

    On v2.0.24 with the default config, I started a session in the Plan agent and asked it to move RbcHelper out of main.rs into repl.rs. The model answered with a single shell command that created src/repl.rs, edited and then deleted src/main.rs, and ran git add / git commit. OpenCode ran it without a permission prompt, so the files changed and a commit was created while still in Plan mode.

    The cause is that Plan only blocks the file-editing tools (outside ~/.opencode/plan/). It has no rule for shell commands, so those run without asking, and only the Plan mode instructions tell the model not to change anything. Some models ignore those instructions, which is what you saw with bash, python, git, rm and mv. The latest v2 (a67cf4c) behaves the same.

    Until this is addressed, you can make Plan ask before every shell command by adding this to your config (e.g. ~/.config/opencode/opencode.json):

    {
      "agent": {
        "plan": {
          "permission": { "bash": "ask" }
        }
      }
    }

    Related: #53530 (v2 Plan mode not stopping edits with ACP models; it also notes the missing shell rule) and #39491 (the same shell behaviour on v1).

  4. argszero commented on Oct 9, 2026

    @argszero
    Contributor

    I'd like to work on this.

    The cause looks like the Plan agent's permission set in packages/core/src/plugin/plan.ts: it denies the file-editing tools outside ~/.opencode/plan/, but there is no rule for the shell tool, so shell commands fall through to the agent default (* -> allow). That matches the documented Plan mode behaviour, which says both file edits and bash are ask by default.

    Plan: add a shell -> ask rule to the plan agent so read-only exploration still works, but any shell command requires confirmation first. I'll cover it with a test alongside the existing plan plugin suite.

  5. argszero commented on Oct 9, 2026

    @argszero
    Contributor

    Opened #54165 with the v2 fix.

    For the record on ordering: I claimed this issue on 2026-10-09T01:17Z and had the branch ready, and #54119 was opened later the same day against dev. That PR was closed because v1 only takes critical fixes and because on v2 the rules live in packages/core/src/plugin/plan.ts with the tool named shell — which is what #54165 does. If @potoior wants to take this over on v2 I am happy to hand the branch over.

    The change is one additive rule in the Plan agent's permission set:

    item.permissions.push({ action: "shell", resource: "*", effect: "ask" })

    Permission.evaluate uses findLast, so with no shell rule every shell command fell through to the agent default (* -> allow) — the Plan system reminder was the only thing stopping a model that mutates files through bash / git / rm. That matches the published agent docs, which describe Plan mode as asking before both file edits and bash.

    Verified both ways on the current v2 tip: with only the source hunk reverted the new test reads allow (12 pass / 1 fail), and with the change it reads ask (13 pass / 0 fail). explore is deliberately untouched — other built-in agents keep the * -> allow default, which packages/core/test/agent.test.ts pins.

  6. rtkirill commented on Oct 13, 2026

    @rtkirill

    same for me in the latest version - v2.0.27

  7. MowlandCodes commented on Oct 18, 2026

    @MowlandCodes

    Same for me in the latest version v2.0.32, it uses cat > "file" << 'TERMINATOR' shell command to achieve it...

    Image

    It even trying to create and apply a patch to the current project even though it fails

    Image Image
  8. VariableVince commented on Oct 19, 2026

    @VariableVince

    Same here. Agent created test files and a test npm installation during plan mode. But then said it couldn't remove those because.. it was in plan mode. So it's half aware of the suggestion but happily goes about creating editing and installing in order to get more information.

    Possibly or partly fixed via #55127?

  9. samvallad33 commented on Oct 23, 2026

    @samvallad33

    Hi Rodrigo,

    Which stung more, the rm calls or the git reset it ran in Plan mode?

    In Plan mode, deletes and resets should face a check the model cannot overrule. I could show you a simple system merging memory, security and authority.

    Sam

  10. Pheonix7284 commented on Oct 29, 2026

    @Pheonix7284

    This is a possible cause in permission.ts. The Plan agent's edit deny does not hold when the global config sets edit: { "*": "ask" } (the default in opencode.jsonc) or edit: { "*": "allow" } — the global rule overrides it.

    The Plan agent sets:

    item.permissions.push({ action: "edit", resource: "*", effect: "deny" })
    item.permissions.push({ action: "edit", resource: path.join(directory, "*"), effect: "allow" })

    But configured merges session permissions onto the agent's:

    return merge(agent?.permissions ?? missingAgentPermissions, session.permissions ?? [])

    evaluate uses findLast, so the last matching rule wins. For a file outside the plan directory, both the agent's { edit, *, deny } and the session's { edit, *, ask } match — findLast picks the session's ask, the denied check (evaluate(...).effect === "deny") returns false, and the deny never fires. The edit prompts for approval (or goes straight through under allow).

    This breaks any agent-level deny that a matching session/global ask/allow rule overrides — not just edit in Plan mode.

    Worked in v1.19.5: configured returned only the agent's permissions, so the agent's deny was the last match. Broken since v2.0.0, when configured started merging session permissions in.

    Fix suggestion for someone willing to put in the effort: denied should check whether any matching rule is deny (not just the last match's effect), or agent permissions should be evaluated after session permissions so the agent's deny is the last match.

    Someone already tried a fix and was rejected though: #56913
    SO if this is the way they want to go, maybe the issue need to be marked as not an issue.

  11. Pheonix7284 commented on Oct 30, 2026

    @Pheonix7284

    I did see improvement when updating the permissions json to have agent and plan/build specific permissions though - so maybe something for trying? Though would be nice if it was more clear the expected template for certain permission needed to be different.

    {
      "$schema": "https://opencode.ai/config.json",
    
      // Per-agent overrides — these come LAST in findLast, so they win
      "agent": {
        "build": {
          "permission": {
            "edit":  { "*": "ask", "<allowed paths>": "allow" },
            "write": { "*": "ask", "<allowed paths>": "allow" }
          }
        },
        "plan": {
          "permission": {
            "edit":  { "*": "deny" },
            "write": { "*": "deny" }
          }
        }
      },
    
      // Global — applies to every agent
      "permission": {
        "bash":             { /* your bash rules */ },
        "read":             { /* your read rules */ },
        "websearch":        "ask",
        "webfetch":         "ask",
        "external_directory": { /* your dir rules */ }
      }
    }
    
  12. dani-nagy commented on Nov 1, 2026

    @dani-nagy

    It even commited in an unwanted change of a git submodule without asking me in plan mode.
    IDK guys what the heck you did with 2.x but I'm at the edge of going back to 1.x and trying out DeepSeek Harness at this point.....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions