Skip to content

[FEATURE]: Plugin extensibility gaps blocking dictation/voice input plugins #17425

@mathew-cf

Description

@mathew-cf

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Dictation and voice input are highly requested (#4695, #9264, #11345), but implementing them as a plugin is currently difficult to deliver a reasonable user experience due to three missing extension points. This means every voice implementation either forks core (#11345) or lives entirely outside OpenCode (#4695 comment thread workarounds with Raycast, Handy, etc.).

The same gaps also block other categories of plugins — anything that needs to react to UI state, inject input, or clean up resources.

Gap 1: No active session awareness
Plugins receive sessionID in several hooks, but there is no way to know:

  • Which session is currently focused in the UI
  • When the user switches sessions (tui.session.select exists internally but isn't surfaced to plugins)
    Minimal addition: Surface session.focus / session.blur events through the plugin event hook, or provide a query like getActiveSession() on PluginInput.

Gap 2: No plugin-triggered input injection or custom keybinds
Plugins can intercept outbound flows but cannot inject input into the UI:

  • No hook to register custom keybindings (TUI Config.Keybinds schema is .strict())
  • No API to programmatically insert text into the user's input box (while plugins can send messages or intercept outgoing chat, they cannot stage text for the user to review/edit before sending)
  • No way to register commands in the web UI command palette
    Minimal addition: A command hook for registering plugin commands (with optional keybind), and an input.inject method on PluginInput to programmatically insert text.

Gap 3: No shutdown/dispose lifecycle hook (previously requested in #10524 and #10003)
Plugins cannot clean up when OpenCode exits. For dictation, this leaves audio recording processes running.
Minimal addition: A shutdown hook in the Hooks interface, called before Instance.dispose().

Summary of proposed additions

export interface Hooks {
  // Existing hooks...

  // New: cleanup before exit (refs #10524, #10003)
  shutdown?(): Promise<void>

  // New: register commands (with optional keybind)
  command?(): CommandDefinition[]
}

Plus surfacing session.focus / session.blur through the existing event hook, and an input.inject() helper on PluginInput.

These additions would allow dictation (and other resource-heavy or UI-interacting features) to exist purely as plugins rather than requiring forks of core.

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions