pingdotgg / pingdotgg/t3code

[Bug]: OpenCode Auto mode ignores user opencode permission patterns and asks for every bash, MCP, and webfetch call

Open
#11,458 4 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area: apps/server

Steps to reproduce

  1. Run T3 Code with the OpenCode provider (opencode 1.18.30, runtime build sha256-02c38816, WSL2 runtime) and keep the thread runtime mode on Auto.
  2. Define fine-grained permissions in ~/.config/opencode/opencode.jsonc, for example: "permission": { "bash": { "*": "allow", "rm -rf *": "ask", "git push *": "ask", "kubectl delete *": "ask" } }.
  3. Send a turn that runs ls, then a turn that calls any MCP tool (I used context7 query-docs), then one that fetches a URL.
  4. All three stop on the approval dialog (Allow once / Allow for workspace / Deny).

Expected behavior

Auto mode for the OpenCode provider should honor the permission configuration opencode already supports. With the config above, ls and the MCP call run without approval and git push asks. Auto then becomes the fine-grained middle ground between Supervised and Full access, instead of a second Supervised.

Actual behavior

The OpenCode adapter injects its own rule set on every session.create/session.update and overrides the user's config. buildOpenCodePermissionRules("auto") returns *: * -> ask, then allow-lists read (with .env ask), glob, grep, lsp, skill, todowrite, question, and leaves bash, edit, webfetch, websearch, codesearch, external_directory, and doom_loop on ask. MCP tools match the catch-all, so every MCP call asks. The patterns the user wrote in opencode.jsonc never reach opencode.

Findings

  • The installed server bundle (apps/server/dist/bin.mjs, runtime dir sha256-02c38816d0b6722af4ec74c48982ab009586fe7f84274cc757fe8f039c4784db) carries buildOpenCodePermissionRules(runtimeMode) as a binary branch on full-access. Every non-full-access mode shares one rule list; only edit flips to allow under auto-accept-edits.
  • The adapter applies the list at session.create({ ..., permission: buildOpenCodePermissionRules(input.runtimeMode) }), and again at session.update({ sessionID, permission: ... }) on resume and fork, so the override survives session reuse.
  • The Claude driver maps the same thread mode onto Claude Code's own policy: auto -> --permission-mode auto, auto-accept-edits -> acceptEdits, full-access -> bypassPermissions. I verified both behaviors in the same session pair: the identical ls, MCP call, and webfetch ran without any approval under the Claude provider in Auto mode and each prompted under the OpenCode provider in Auto mode. One mode label, two policies.
  • Full access is the only escape, and it removes gating entirely: *: allow, external_directory: allow, plus auto-reply to any residual ask. That is too coarse for day-to-day work, so people either approve constantly or run ungated.

Validation

  • sqlite3 (read-only) on ~/.t3/userdata/state.sqlite reports runtime_mode = 'auto' for the affected threads, and the T3 server process env contains none of the opencode permission config, so the injected rules are the only permissions opencode sees.
  • I extracted and quoted the rule list above from the running bundle rather than from docs or memory.
  • I reproduced the prompts listed in the repro steps on this thread before writing this report.
  • The OpenCode provider session receives the rules via the SDK permission field, which is why the global ~/.config/opencode/opencode.jsonc permission block has no effect under T3 while working as documented when running opencode standalone.

Suggested fix

session.create/session.update already accept permission rule arrays, and opencode already evaluates per-tool glob patterns with last-match-wins. When the runtime mode is Auto, pass the user's opencode permission config through to the session instead of the catch-all ask list, and fall back to the current defaults when no user config exists. This keeps Supervised as-is, keeps full access for people who want zero gates, and gives Auto an actual middle ground.

References

  • #5164 reported this collapse and closed as completed with no comment when #7100 merged. #7100 fixed auto-accept-edits only; Auto still collapses to ask-all in the current build.
  • #9282 fixed the full-access auto-reply path.
  • #6517 tracks the mid-turn mode-change restart that applies mode changes on the next turn.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in the apps/server adapter around buildOpenCodePermissionRules(runtimeMode), then trace the permission values passed to session.create and session.update. Reproduce the Auto-mode steps with the OpenCode provider and confirm that user opencode.jsonc patterns are honored for allowed and prompting commands while existing Supervised and Full access behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.