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

No labels
No labels

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