Support {file:...} references for agent permissions #1459

Closed
opened 2026-02-16 17:31:04 -05:00 by yindo · 11 comments
Owner

Originally created by @ndrwstn on GitHub (Aug 23, 2025).

Originally assigned to: @thdxr on GitHub.

Currently, agent permissions must be inline JSON objects. The {file:...} syntax works for prompts but not permissions:

// Works:
"prompt": "{file:./prompts/build.md}"

// Doesn't work:
"permission": "{file:./permissions/build.json}"

// Current requirement:
"permission": {
  "edit": "ask",
  "bash": {
    "*&&*": "deny",
    // ... 40+ lines of permission rules
  }
}

Would be great to support external permission files like we already do for prompts.

Originally created by @ndrwstn on GitHub (Aug 23, 2025). Originally assigned to: @thdxr on GitHub. Currently, agent permissions must be inline JSON objects. The `{file:...}` syntax works for prompts but not permissions: ```jsonc // Works: "prompt": "{file:./prompts/build.md}" // Doesn't work: "permission": "{file:./permissions/build.json}" // Current requirement: "permission": { "edit": "ask", "bash": { "*&&*": "deny", // ... 40+ lines of permission rules } } ``` Would be great to support external permission files like we already do for prompts.
yindo closed this issue 2026-02-16 17:31:04 -05:00
Author
Owner

@aspiers commented on GitHub (Aug 23, 2025):

If you'll forgive a bit of a tangent from the main issue, please note that denying *&&* won't protect you much - I've provided more info in #2206.

@aspiers commented on GitHub (Aug 23, 2025): If you'll forgive a bit of a tangent from the main issue, please note that denying `*&&*` won't protect you much - I've provided more info in #2206.
Author
Owner

@ndrwstn commented on GitHub (Aug 23, 2025):

Yeah, the wildcarding system leaves a bit to be desired, sadly. It catches a bit though, so I keep it in there.

@ndrwstn commented on GitHub (Aug 23, 2025): Yeah, the wildcarding system leaves a bit to be desired, sadly. It catches a bit though, so I keep it in there.
Author
Owner

@thdxr commented on GitHub (Aug 23, 2025):

the whole file reference thing only really makes sense for strings, don't really want to get into supporting it for objects makes the typesafety on the config useless because every field could potentially be a string

@thdxr commented on GitHub (Aug 23, 2025): the whole `file` reference thing only really makes sense for strings, don't really want to get into supporting it for objects makes the typesafety on the config useless because every field could potentially be a string
Author
Owner

@thdxr commented on GitHub (Aug 23, 2025):

also not sure if denying && is needed - did you add this after observing specific behavior? we parse the bash command and check individual subcommands one at a time

@thdxr commented on GitHub (Aug 23, 2025): also not sure if denying `&&` is needed - did you add this after observing specific behavior? we parse the bash command and check individual subcommands one at a time
Author
Owner

@ndrwstn commented on GitHub (Aug 23, 2025):

also not sure if denying && is needed - did you add this after observing specific behavior? we parse the bash command and check individual subcommands one at a time

I have seen it bypass denied commands using && chaining. Specifically, "git push*" is denied and a few days ago it jammed one through using either an && or a |, I can't recall.

@ndrwstn commented on GitHub (Aug 23, 2025): > also not sure if denying `&&` is needed - did you add this after observing specific behavior? we parse the bash command and check individual subcommands one at a time I have seen it bypass denied commands using && chaining. Specifically, "git push*" is denied and a few days ago it jammed one through using either an && or a |, I can't recall.
Author
Owner

@ndrwstn commented on GitHub (Aug 23, 2025):

the whole file reference thing only really makes sense for strings, don't really want to get into supporting it for objects makes the typesafety on the config useless because every field could potentially be a string

It makes a lot more sense for json permissions than you're giving credit for at least two reasons: (1) reusability over multiple configs and (2) reusability in a single config.

For the first, I have a cli.json that I use for opencode run commands that I have to keep in sync with my tui.json (which is what lives as opencode.json), so being able to edit one permissions file for both places is just easier.

For the second, while I didn't know about treesitter, my list of allowed and denied commands has become very granular because I've seen a lot of hijinks. Some of it may have been my fault, I'm not sure, and now knowing about treesitter I'm going to reevaluate my permissions, I've found gloval permissions to be essentially worthless and have every primary and subagent with their own permissions. This results in a lot of duplication with minor differences.

Add the two together, even letting an agent try to adjust all the files at the same time, it introduces a lot of inconsistency. I do understand the type-safety concern, so if it just can't be done, you can close this as not planned and I'll hope someone will work out a solution (or I learn that I'm doing something horribly wrong) in time.

@ndrwstn commented on GitHub (Aug 23, 2025): > the whole `file` reference thing only really makes sense for strings, don't really want to get into supporting it for objects makes the typesafety on the config useless because every field could potentially be a string It makes a lot more sense for json permissions than you're giving credit for at least two reasons: (1) reusability over multiple configs and (2) reusability in a single config. For the first, I have a cli.json that I use for opencode run commands that I have to keep in sync with my tui.json (which is what lives as opencode.json), so being able to edit one permissions file for both places is just easier. For the second, while I didn't know about treesitter, my list of allowed and denied commands has become very granular because I've seen a lot of hijinks. Some of it may have been my fault, I'm not sure, and now knowing about treesitter I'm going to reevaluate my permissions, I've found gloval permissions to be essentially worthless and have every primary and subagent with their own permissions. This results in a lot of duplication with minor differences. Add the two together, even letting an agent try to adjust all the files at the same time, it introduces a lot of inconsistency. I do understand the type-safety concern, so if it just can't be done, you can close this as not planned and I'll hope someone will work out a solution (or I learn that I'm doing something horribly wrong) in time.
Author
Owner

@rekram1-node commented on GitHub (Aug 23, 2025):

for these cli run commands vs tui, why not just define an agent?

also can you explain what u mean by global permissions are worthless?

@rekram1-node commented on GitHub (Aug 23, 2025): for these cli run commands vs tui, why not just define an agent? also can you explain what u mean by global permissions are worthless?
Author
Owner

@ndrwstn commented on GitHub (Aug 23, 2025):

for these cli run commands vs tui, why not just define an agent?

I have specific agents defined for specific tasks I perform (edit adding:) in the cli. I don't need more to manage.

also can you explain what u mean by global permissions are worthless?

They're overridden by agent permissions, so if you have an agent denied with "*": the global permissions don't seem to apply at all? A lot of my agents have an explicit instruction regarding any other command (either allow or deny, and one has ask),

Edit to add: I'm trying to refactor and simplify things now. I got really in the weeds for a few days, as I think a lot of people do, so I'm trying to figure out if the problem was me or the permissions workflow, but I do think the workflow could been improved

@ndrwstn commented on GitHub (Aug 23, 2025): > for these cli run commands vs tui, why not just define an agent? I have specific agents defined for specific tasks I perform (edit adding:) _in the cli_. I don't need more to manage. > also can you explain what u mean by global permissions are worthless? They're overridden by agent permissions, so if you have an agent denied with "*": <anything> the global permissions don't seem to apply at all? A lot of my agents have an explicit instruction regarding any other command (either allow or deny, and one has ask), Edit to add: I'm trying to refactor and simplify things now. I got *really* in the weeds for a few days, as I think a lot of people do, so I'm trying to figure out if the problem was me or the permissions workflow, but I do think the workflow could been improved
Author
Owner

@rekram1-node commented on GitHub (Aug 23, 2025):

They're overridden by agent permissions

Well we do merge the permissions so the global ones are the defaults, if you change that for an agent then the overriding would be expected, but if the permissions don't overlap they should merge as expected

@rekram1-node commented on GitHub (Aug 23, 2025): > They're overridden by agent permissions Well we do merge the permissions so the global ones are the defaults, if you change that for an agent then the overriding would be expected, but if the permissions don't overlap they should merge as expected
Author
Owner

@ndrwstn commented on GitHub (Aug 23, 2025):

They're overridden by agent permissions

Well we do merge the permissions so the global ones are the defaults, if you change that for an agent then the overriding would be expected, but if the permissions don't overlap they should merge as expected

For a command like git, most of the permissions do overlap, don't they? The permissions hierarchy where commands are otherwise identical is longest -> shortest?

@ndrwstn commented on GitHub (Aug 23, 2025): > > They're overridden by agent permissions > > Well we do merge the permissions so the global ones are the defaults, if you change that for an agent then the overriding would be expected, but if the permissions don't overlap they should merge as expected For a command like git, most of the permissions do overlap, don't they? The permissions hierarchy where commands are otherwise identical is longest -> shortest?
Author
Owner

@rekram1-node commented on GitHub (Dec 27, 2025):

[automated] Closing due to 90+ days of inactivity. Feel free to reopen if you still need this!

@rekram1-node commented on GitHub (Dec 27, 2025): [automated] Closing due to 90+ days of inactivity. Feel free to reopen if you still need this!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#1459