Stop OpenCode hanging on permission asks without a native policy by utkarsh261 · Pull Request #145 · sineframe/m3 · GitHub
Skip to content

Stop OpenCode hanging on permission asks without a native policy - #145

Open
utkarsh261 wants to merge 3 commits into
mainfrom
fix/opencode-permission-ask-hang
Open

utkarsh261 wants to merge 3 commits into
mainfrom
fix/opencode-permission-ask-hang

Conversation

@utkarsh261

@utkarsh261 utkarsh261 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
  • With no native policy, m3 wrote no permission block, so OpenCode's defaults applied: external_directory, doom_loop and .env reads are ask. Nothing answered those prompts, so any path outside the workspace stalled the turn until it timed out.
  • Those defaults now follow the session's permission_policy, the same setting Codex and ACP approvals use: denied by default, allowed with "allow", and left as ask under "prompt".
  • While a turn runs, m3 answers pending OpenCode permission requests (GET /permission, POST /permission/{id}/reply) from the turn's session and its descendants (Task subagents), through the permission handler with the permission, patterns and metadata in PermissionRequest.context. Each request is decided once and the reply is retried until OpenCode accepts it. No interactions means reject, so a stray ask can't hang a turn in any mode.
  • The V2 dialect now gets V2's ordered permissions rule list (no doom_loop) instead of the V1 permission object, for native policies too.
  • Native mcp_only/mcp_read_only/full policies are unchanged; they already override every ask through "*".

Testing: unit tests for the rendered V1 and V2 config per policy, and for answering root and subagent prompts and retrying failed replies against a fake OpenCode server (failed before, pass now); OpenCode adapter tests, docs/skill reference checks, ruff and mypy pass. PermissionRequest.context matches the same change in #143.

Without a native policy m3 wrote no permission block, so OpenCode's
defaults applied and external_directory stayed on ask. m3 cannot answer
permission prompts, so the turn blocked until it timed out. Write an
explicit block that turns each default ask into deny.
OpenCode's default ask prompts now map from permission_policy (deny by
default, allow, or ask under prompt), and a responder answers this session's
pending permission requests through the permission handler while a turn runs,
so a stray ask can no longer stall the turn.
The permission responder now answers prompts from descendant sessions of the
turn's session (Task subagents) and ignores unrelated session trees. A
decision is made once per request and its reply is retried until OpenCode
accepts it. The V2 dialect gets an ordered permissions rule list instead of
the V1 permission object, without doom_loop.
@utkarsh261 utkarsh261 added wontfix This will not be worked on canary Publish an installable canary build of this PR and removed do-not-merge labels Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

@utkarsh261 utkarsh261 added do-not-merge wontfix This will not be worked on do-not-merge-this and removed wontfix This will not be worked on canary Publish an installable canary build of this PR do-not-merge labels Oct 19, 2026

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant