Skip to content

Desktop app: local plugins load and register but their hooks (tool.execute.before, event) are never invoked #38604

Description

@SamBWagner

Description

The Desktop app (ai.opencode.desktop) discovers and registers local plugins from ~/.config/opencode/plugins/ — the plugin shows up correctly in the old-layout status popover's Plugins tab with an active (green) status indicator. However, its hooks (tool.execute.before and event) are never actually invoked at runtime, even across multiple real tool calls that should trigger them. The identical, unmodified plugin file works correctly when run via the CLI (opencode run).

This looks like a registration/listing vs. hook-dispatch gap specific to the Desktop app's embedded server.

Related but distinct issues, for context (none of these appear to be duplicates — happy to be corrected):

Environment

  • OpenCode Desktop: v1.18.4 (macOS, arm64)
  • OpenCode CLI (for comparison): v1.17.11 (same machine)
  • Plugin location: ~/.config/opencode/plugins/my-plugin.ts (also reproduced with a project-local equivalent)

Minimal repro plugin

import type { Plugin } from "@opencode-ai/plugin"

export const DebugPlugin: Plugin = async ({ $, client }) => {
  await $`echo "plugin loaded at $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> /tmp/debug-plugin-loaded.log`.nothrow()

  return {
    "tool.execute.before": async (input, output) => {
      await client.app.log({
        body: { service: "debug-plugin", level: "info", message: "tool.execute.before fired", extra: { tool: input.tool } },
      })
    },
    event: async ({ event }) => {
      if (event.type !== "permission.asked") return
      await client.app.log({
        body: { service: "debug-plugin", level: "info", message: "permission.asked fired" },
      })
    },
  }
}

Steps to reproduce

  1. Place the plugin above in ~/.config/opencode/plugins/debug-plugin.ts.
  2. Fully quit and relaunch OpenCode Desktop.
  3. Confirm the plugin is registered: open the status popover from the session header and check the Plugins tab (reproduced on both the old and new/V2 layout). The plugin is listed with a green/active status dot as file:///.../debug-plugin.ts.
  4. Trigger any tool call that requires permission approval (e.g. an MCP tool with "permission": {"ask": ...} configured, or any edit/bash call gated to ask).
  5. Approve or reject the permission prompt as normal.
  6. Check /tmp/debug-plugin-loaded.log and the app log (~/.local/share/opencode/log/opencode.log) for debug-plugin entries.

Expected behavior

  • /tmp/debug-plugin-loaded.log contains a line from plugin initialization.
  • The app log contains tool.execute.before fired for the tool call and permission.asked fired for the permission prompt.

Actual behavior

  • Neither file/log ever receives an entry, across every real tool call and permission prompt triggered through the Desktop session — despite the plugin being listed as actively loaded in the Plugins tab.
  • Running the exact same plugin file via opencode run --dangerously-skip-permissions "..." (CLI) does produce both the marker file and the tool.execute.before/event log entries correctly, on the same machine, same config directory, same plugin file.

Additional notes

  • This was discovered while building a plugin to surface real tool arguments in MCP permission prompts (workaround for MCP tools show * instead of actual tool name in permission dialogs #19549) — the workaround is fully proven to work via CLI but is completely inert in Desktop because its hooks never fire.
  • Since even a shell-free signal (client.app.log(), no $/spawn involved) never appears, this doesn't look like an Electron sandboxing/shell-restriction issue specifically — it looks like the Desktop app's plugin loader registers the module (enough to list it in the UI) but doesn't wire its returned hook object into the actual event/tool-execution dispatch path.

OpenCode version

Desktop v1.18.4 / CLI v1.17.11

Plugins

Yes — ~/.config/opencode/plugins/debug-plugin.ts (see repro above). Confirmed listed/active in Desktop's Plugins tab, confirmed working via CLI, confirmed inert via Desktop's actual hook dispatch.

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions