Skip to content

Split external_directory permission into read vs write #5395

Description

@charles-cooper

Currently, external_directory is a single permission that controls all file operations (read, write, edit, patch, bash workdir) outside the working directory. This makes it impossible to allow reading external files while blocking writes.

Use case

I want the agent to be able to read reference files, configs, or documentation outside the project directory without prompts, but still block (or prompt for) any writes to external locations. Currently I must choose between:

  • "allow" - permits both reads and writes (too permissive)
  • "ask" - prompts for every read (too noisy)
  • "deny" - blocks all external access (too restrictive)

Proposed solution

Split into two permissions:

{
  "permission": {
    "external_directory_read": "allow",
    "external_directory_write": "ask"
  }
}

Or alternatively, add a mode qualifier:

{
  "permission": {
    "external_directory": {
      "read": "allow",
      "write": "ask"
    }
  }
}

Implementation notes

Looking at the source, this would require:

  1. Update config schema in config/config.ts and agent/agent.ts
  2. Modify permission checks in tool/read.ts, tool/write.ts, tool/edit.ts, tool/patch.ts, tool/bash.ts to use the appropriate permission type
  3. For backwards compatibility, the existing external_directory could be kept as a shorthand that sets both read and write

Note: This issue was drafted with Claude Opus 4.5

Activity

  1. github-actions commented on Dec 11, 2025

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if your use case is different from these.

  2. self-assigned this
    on Dec 11, 2025
  3. rekram1-node commented on Dec 11, 2025

    @rekram1-node
    Collaborator

    Yeah we need more granular permissions

  4. jgordijn commented on Dec 18, 2025

    @jgordijn

    It would be nice if instead of just ask/allow/deny we can configure it even on directory bases:
    something like:

    "external_directory_read": {
       "~/.config/opencode/skills": "allow",
       "*": "ask"
    }
    
  5. fpdy commented on Dec 20, 2025

    @fpdy
    Contributor

    made first proposal implementation at #5841

  6. 5 remaining items

  7. jgordijn commented on Dec 21, 2025

    @jgordijn

    I also took a stab at it, so it may have been a waste of my time for this PR. It was a learning experience nonetheless. I leave it to the creators of OpenCode to decide which implementation is better. #5905

    Sorry @fpdy don't want to overrule you or anything. Was just playing with the codebase to see if I could do it. Didn't know you were also working on it.

  8. fpdy commented on Dec 21, 2025

    @fpdy
    Contributor

    @jgordijn Thanks for the kind words, I realize I should’ve said on the issue that I was working on it too — so sorry for the overlap and for making you spend time on it (btw your implementation looks a bit more solid than mine tbh)

  9. jgordijn commented on Dec 21, 2025

    @jgordijn

    @fpdy you and me both :-). I didn't claim the issue as well. But hey, let's fix more ;-)

  10. jgordijn commented on Dec 29, 2025

    @jgordijn

    @thdxr Is there anything I/we can do to get this going? Does this stand a chance to get merged in?

  11. ethaizone commented on Jan 21, 2026

    @ethaizone

    Any updates?

    I'm looking forward to this feaure as it's really important for Go developer. In many cases we need AI to read latest code from ~/go/pkg/mod/github.com as Go doesn't install deps in work directory but install in folder inside home directory and in normal case. We need only read permissions.

    Now I need to click accept manually everytimes.

  12. Nindaleth commented on Feb 4, 2026

    @Nindaleth
    Contributor

    @jgordijn @fpdy I was interested in this too and after reading the current Permissions docs I believe OpenCode can do what you propose. What do you think?

  13. enesaltinkaya commented on Mar 5, 2026

    @enesaltinkaya

    If i do this;

    {
      "$schema": "https://opencode.ai/config.json",
      "permission": {
        "external_directory": {
          "~/projects/personal/**": "allow"
        }
      }
    }
    

    is there a chance that agent will modify external files?

  14. CarloWood commented on Apr 13, 2026

    @CarloWood
    Contributor

    I am having the following simple problem:

    • I want write (edit) permissions in the whole worktree (lets say /path/workspace/worktree)
    • I want read permissions in a much larger directory structure (/path/workspace).

    For the latter I have to add:

        "external_directory": {
          "{env:WORKSPACE_ROOT}/**": "allow"
        }
    

    (or give permission ever command and verify if it is reading or writing; giving permission 'always' is the same as adding the above).

    However, now it seems impossible to specify that you allow edit in /path/workspace/worktree because the pattern given under "edit" is matched against a relative directory, relative to the worktree!

    Using "*" also matches "../../evil/access".
    Using "/path/workspace/worktree/*" never matches because that doesn't match literally against any relative path.

  15. YoungJurry commented on Apr 29, 2026

    @YoungJurry

    Have this fixed?i meet the same problem,,I want to implement something like Codex, where the model can read files globally—able to read anywhere—but editing, deleting, and creating operations are only allowed within the current directory. Operations outside this directory should require asking for permission first.

  16. CarloWood commented on Apr 29, 2026

    @CarloWood
    Contributor

    @smithyyang I fixed this in my dev...CarloWood:opencode:CW09-globbing branch.

    Then use, for example, "**/*" as edit permissions, which no longer match everything but only match the current repository.

    Example config: https://github.com/CarloWood/ai-cli-bwrap/blob/master/xdg-home/config/opencode/opencode.json#L180

  17. github-actions commented on Jun 29, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

  18. Summersyard commented on Oct 8, 2026

    @Summersyard
    Image

    Still relevant — reopening the discussion from #34014, which was auto-closed as
    stale and flagged as a duplicate of this one.

    The concrete pain point is the approval prompt itself:

    ⚠ Permission required
    Access files outside the project directory
    /home/georg/.local/bin/*

    "Access" hides the one piece of information that decides how I answer. Reading a
    reference file outside the project and writing/deleting to it are not remotely the
    same risk, yet I get a single yes/no on a glob. If the prompt said read vs.
    write/edit, I could approve reads casually and stay strict on writes — instead
    I either click through every read (noisy) or grant "always" and silently open up
    writes too (unsafe).

    So this is really two coupled asks:

    1. Distinguish read vs. write in the permission itself (external_directory_read
      / external_directory_write, as proposed in the original description) — so config
      can allow reads and ask on writes.
    2. Show the operation in the prompt text, even for users who keep a single
      external_directory rule. This is cheap and already helps on its own.

    The external_directory permission is currently a single key gating read, write,
    edit, patch and bash workdir access outside the worktree, which makes the common
    "read anywhere, write only in the project" setup (what #5395, #34014 and several
    later comments ask for) impossible to express — see also #49941 and #51046 for
    adjacent permission-UX issues.

    Prior work exists and would be a reasonable base: #5841 and #5905.

    Happy to help drive this forward if the maintainers indicate which shape they'd
    prefer (separate keys vs. a mode qualifier) — I'd keep external_directory as a
    backwards-compatible shorthand for both.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions