Skip to content

feat(hooks): map notification, permissionDenied and beforeSubmitPrompt for OpenCode and Kilo - #2617

Merged
dyoshikawa merged 2 commits into
mainfrom
resolve-issue-2592-opencode-hook-events
Aug 7, 2026
Merged

feat(hooks): map notification, permissionDenied and beforeSubmitPrompt for OpenCode and Kilo#2617
dyoshikawa merged 2 commits into
mainfrom
resolve-issue-2592-opencode-hook-events

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

OpenCode (verified against anomalyco/opencode v1.18.14) exposes three plugin surfaces rulesync was not mapping, so hooks authored on notification, permissionDenied and beforeSubmitPrompt were silently dropped for OpenCode and Kilo.

Changes

  • notification -> tui.toast.show (a generic event.type dispatch; defined in packages/schema/src/tui-event.ts and listed under TUI Events in the plugins docs).
  • permissionDenied -> permission.replied (packages/schema/src/v1/permission.ts, reply is one of once/always/reject). The event fires for every reply, so the generated handler is gated on event.properties.reply === "reject" through a new GENERIC_EVENT_PROPERTY_GATES table - the generic-dispatch counterpart of the existing SHELL_EVENT_TOOL_GATES.
  • beforeSubmitPrompt -> chat.message, registered as a named (input, output) hook with a null matcher subject, the same way experimental.session.compacting already is. A matcher on it is dropped, since the prompt text lives in output.parts rather than a single matchable field.

Kilo follows automatically because KILO_HOOK_EVENTS aliases OPENCODE_HOOK_EVENTS; its tests are updated alongside OpenCode's. Docs prose, the generated hook event x tool matrix, and docs-content are regenerated. Verified locally with the hooks e2e spec.

Note on the payload field: the v1 SDKs generated Eventtyping still describespermission.repliedas{ permissionID, response }, but the schema source, the v2 typings, and the TUI's live consumer all agree on { requestID, reply }`, so the stale codegen is not followed. This is recorded in a comment next to the gate.

Part of #2592
Part of #2499

Remaining, deliberately not in this PR: #2592 gap 3 (references authoring) is a discretionary design item, and gap 4 (the V2 GA gate) has not fired - the latest release is still 1.18.14. #2499's mode-directories item remains design-gated.

🤖 Generated with Claude Code

…t for OpenCode and Kilo

OpenCode's plugin event surface documents tui.toast.show and
permission.replied as subscribable events, and chat.message as a named
(input, output) hook. Map the canonical notification, permissionDenied
and beforeSubmitPrompt events onto them so they are no longer dropped
for OpenCode and Kilo.

permission.replied fires for every reply, so the generated handler is
gated on a rejecting reply via a new declarative gate table for generic
event dispatches.
…dler

Kilo's plugin docs enumerate the same events as OpenCode's except for the
TUI section, which they omit entirely, so tui.toast.show is dropped from
Kilo's surface rather than emitted into a plugin where it may never fire.

The permission.replied gate now hangs off the canonical event, like
SHELL_EVENT_TOOL_GATES, and is emitted per handler, so a future canonical
event mapped onto the same dispatch cannot inherit its sibling's gate.

Also record the toast channel's breadth in the docs prose, cover the
matcher drop on the new generic events, and syntax-check the generated
plugin now that a condition is composed into the emitted if.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants