Repository navigation
Description
Summary
The built-in plan agent (Plan mode) cannot write to its own plan directory (~/.opencode/plan/) when the session's working directory is an ancestor of that directory — the common case, e.g. starting a session from ~. The write is hard-denied (no prompt) with a misleading error — "Cannot use write to modify files outside the Plan directory" — even though the target file is inside the plan directory. Root cause is a resource-format mismatch: the plan plugin's allow rule uses an absolute path, but the permission check passes a location-relative resource for files inside the session's cwd.
Environment
- opencode version: 2.1.4
- OS: Linux 6.18.55-2-cachyos-lts (x86_64)
- Terminal: TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/bash
- Install/channel: latest
- Active plugins:
*(all plugins in~/.opencode/plugins/)
Reproduction
- Start a session on the
planagent from a working directory that is an ancestor of~/.opencode/plan(e.g.cd ~). - Have the plan agent write a file into
~/.opencode/plan/(e.g. via thewritetool). - Observe the result.
Contrast: starting the same session from a cwd that does not contain the plan dir (e.g. a project subdirectory) makes the write succeed — the plan dir is then "external" to the location and the resource is absolute.
Expected Behavior
The plan agent can create/modify files inside ~/.opencode/plan/ (its designated plan directory), per the built-in opencode.plan plugin's allow edit <home>/.opencode/plan/* rule.
Actual Behavior
The write is hard-denied (no prompt) with:
Cannot use write to modify files outside the Plan directory: <home>/.opencode/plan
even though the target file is inside that directory.
Additional Context
Root cause (from decompiling the built-in opencode.plan plugin in the opencode binary, v2.1.4):
-
The plugin pushes three rules onto the
planagent:allow question *deny edit *allow edit <home>/.opencode/plan/*(absolute path)
-
The permission resolver is last-match-wins (
findLastover the matching rules), and a singledenymatch short-circuits to deny. -
The
write/edit/patchtools checkaction: "edit"withresources: [q.resource], whereq.resourcecomes fromFileAccess.resolve:- file inside the session's location/project dir →
resourceis relative to the cwd (e.g..opencode/plan/foo.md); - file outside →
resourceis the absolute path.
- file inside the session's location/project dir →
-
So when cwd is an ancestor of the plan dir (e.g.
~), the resource is.opencode/plan/foo.md(relative). The plugin's allow rule<home>/.opencode/plan/*(absolute) does not match it. Onlydeny edit *matches → last-match-wins → deny. The plan-dir allow rule is effectively dead code for the common case. -
The plugin's
tool.hook("execute.after")then rewrites anyPermission.BlockedErrorfrom a plan-agent edit/write/patch to "Cannot use <tool> to modify files outside the Plan directory" — misleading here because the file is inside the plan dir.
Workaround (user-side): add a relative-path allow rule to the plan agent in opencode.json:
{ "action": "edit", "resource": ".opencode/plan/*", "effect": "allow" }This lands after the plugin's deny edit * in the merged rule list and wins under last-match-wins. (Alternatively, write plan files via a shell heredoc, since shell is ask.)
Suggested fix (upstream): make the plan plugin's allow rule match the resource format the resolver actually produces — e.g. also allow the location-relative form (.opencode/plan/*), or have FileAccess.resolve pass an absolute resource for permission checks. And make the execute.after error message accurate (only claim "outside the Plan directory" when the target actually is outside it).
Activity
opencodejr commentedon Oct 28, 2026
Thanks for the detailed root-cause analysis and the workaround. I think this is a duplicate of #46358, which is open and tracking the same problem: the plan agent's absolute allow rule for
~/.opencode/plan/*never matches the cwd-relative path the file tools check when the session runs from an ancestor directory such as~. Sodeny edit *wins, and you get the misleading "outside the Plan directory" error.Possible duplicates and related issues, ordered from most to least likely:
$HOMEand no custom configedit/readrules against the full path; it does not change the error message inplugin/plan.tsYour point about the error message may be worth adding on #46358, since the linked PR leaves the message as it is. Your relative-path workaround (
{ "action": "edit", "resource": ".opencode/plan/*", "effect": "allow" }) would also be useful to others there.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
opencodejr commentedon Oct 29, 2026
We haven't heard back, so I'm closing this as a duplicate of #46358. That issue tracks the same bug: the plan agent's absolute allow rule for
~/.opencode/plan/*doesn't match the cwd-relative path that is checked when the session runs from an ancestor directory like~. The open PR #53365 proposes a fix for it.Please subscribe to #46358 for updates. Your note about the misleading "outside the Plan directory" message, and your relative-path workaround, would be useful to add there. If your problem turns out to be different, reply here and we can reopen this. Thanks again for the thorough analysis!