Description
When configuring agent-level permissions with absolute path patterns, external_directory works correctly but edit silently fails to match because they use different path formats internally.
Agent config (YAML frontmatter):
permission:
edit:
"*": ask
"/tmp/my-tmp-folder/**": allow
external_directory:
"/tmp/my-tmp-folder/**": allow
Expected: Both permissions resolve to allow for files under /tmp/my-tmp-folder/.
Actual: external_directory resolves to allow, but edit resolves to ask (prompts the user).
Root cause
In write.ts (line 26) and edit.ts (line 45), the edit permission check passes a relative path:
await ctx.ask({
permission: "edit",
patterns: [path.relative(Instance.worktree, filepath)],
// ...
})
But in external-directory.ts (line 18), the external_directory check passes an absolute path:
const glob = path.join(dir, "*")
await ctx.ask({
permission: "external_directory",
patterns: [glob],
// ...
})
For non-git projects, Instance.worktree is / (as noted in the comment in instance.ts). So:
path.relative("/", "/tmp/my-tmp-folder/file.md")
// -> "tmp/my-tmp-folder/file.md" (no leading slash)
The configured pattern /tmp/my-tmp-folder/** produces regex ^/tmp/my-tmp-folder/.*$, which does NOT match tmp/my-tmp-folder/... (missing leading /).
The "*": ask catch-all is the last matching rule, so the user gets prompted.
Steps to reproduce
- Create an agent markdown file with the config shown above
- Start OpenCode in a non-git directory (so
Instance.worktree is /)
- Have the agent write a file to
/tmp/my-tmp-folder/test.md
- Observe the permission prompt despite the
allow rule
Suggested fix
Normalize the path format so edit and external_directory use the same representation when matching against permission rules. Either:
- Use absolute paths consistently in both checks, or
- Document clearly that
edit patterns are relative to the worktree and external_directory patterns are absolute
The first option is better UX since users configure both in the same permission block and expect the same path format.
Environment
- OpenCode version: 1.3.0
- OS: macOS (arm64)
Issue is discovered by OpenCode :)
Description
When configuring agent-level permissions with absolute path patterns,
external_directoryworks correctly buteditsilently fails to match because they use different path formats internally.Agent config (YAML frontmatter):
Expected: Both permissions resolve to
allowfor files under/tmp/my-tmp-folder/.Actual:
external_directoryresolves toallow, buteditresolves toask(prompts the user).Root cause
In
write.ts(line 26) andedit.ts(line 45), theeditpermission check passes a relative path:But in
external-directory.ts(line 18), theexternal_directorycheck passes an absolute path:For non-git projects,
Instance.worktreeis/(as noted in the comment ininstance.ts). So:The configured pattern
/tmp/my-tmp-folder/**produces regex^/tmp/my-tmp-folder/.*$, which does NOT matchtmp/my-tmp-folder/...(missing leading/).The
"*": askcatch-all is the last matching rule, so the user gets prompted.Steps to reproduce
Instance.worktreeis/)/tmp/my-tmp-folder/test.mdallowruleSuggested fix
Normalize the path format so
editandexternal_directoryuse the same representation when matching against permission rules. Either:editpatterns are relative to the worktree andexternal_directorypatterns are absoluteThe first option is better UX since users configure both in the same
permissionblock and expect the same path format.Environment
Issue is discovered by OpenCode :)