Repository navigation
Description
Description
Summary
The permission.ask plugin hook in packages/opencode/src/permission/index.ts is currently wrapped in an if (!needsAsk) guard, which means it only fires for commands that already have an “allow” rule. For first-encounter commands where needsAsk=true, the hook is completely bypassed.
This effectively prevents plugins from intercepting or customizing the permission flow for first-encounter commands — the scenario where additional context from plugins is most valuable.
Current behavior
User runs new command → needsAsk=true → hook SKIPPED → standard dialog shown
User runs known command → needsAsk=false → hook fires → plugin can customize
Expected behavior
User runs any command → hook fires with current status ("ask" or "allow") → plugin can override → dialog shown accordingly
Why this matters for plugins
A plugin that wants to provide additional context about commands (e.g., risk assessment, documentation links, custom approval workflows) can only do so for commands the user has already approved. The first encounter — where additional context is most valuable — is unreachable.
Proposed fix
Remove the if (!needsAsk) guard so Plugin.trigger("permission.ask", ...) fires unconditionally. The hook already receives the current permissionStatus (“ask” or “allow”), so plugins can make informed decisions based on the existing status.
let permissionStatus: "ask" | "deny" | "allow" = needsAsk ? "ask" : "allow"
- if (!needsAsk) {
const hookResult = yield* Effect.tryPromise(() => Plugin.trigger(
"permission.ask",
{ sessionID: request.sessionID, permission: request.permission, patterns: request.patterns, metadata: request.metadata },
{ status: permissionStatus },
)).pipe(Effect.option)
if (hookResult._tag === "Some") {
permissionStatus = hookResult.value.status
} - }
Backward compatibility
When no plugin is registered for permission.ask, behavior is identical to current
Existing plugins that only handle needsAsk=false cases continue to work (they receive status: "allow" as before)
The only difference is that plugins now also receive status: "ask" events they previously couldn’t see
Notes
This is a 2-line removal (the if and closing brace)
Backward compatible: no behavioral change when no plugin is registered for this hook
Minor test consideration: Permission.list() calls immediately after Permission.ask() may need to account for the hook firing asynchronously on the new path
I noticed the permission module has been undergoing some refactoring recently. Happy to adapt this proposal to align with the current direction if the approach changes.
Plugins
No response
OpenCode version
No response
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Activity
github-actions commentedon Mar 29, 2026
This issue might be a duplicate of existing issues. Please check:
permission.askplugin hook is not triggered, and proposes wiring it inpermission/index.ts. The root cause and proposed fix are essentially the same.YumaKakuya commentedon Mar 29, 2026
Related: #19469 — appears to describe the same underlying issue.
My analysis points to the
if (!needsAsk)guard as the specific cause.YumaKakuya commentedon Apr 2, 2026
I put together a small PR for this so the behavior can be evaluated concretely with a narrow diff and a regression test.
feat(opencode): ship plugin as agent-cya/opencode subpath export
docs: refresh README — opencode caveat, harness terminology, releasin…
github-actions commentedon Jul 3, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.