Skip to content

Let tool.execute.before short-circuit a tool call with a substitute result #32565

Description

@OddballGreg

Problem

tool.execute.before can mutate a tool's args but can't stop the tool from running, and tool.execute.after only rewrites the result after it ran. There's no way for a plugin to answer a tool call itself and skip execution.

The runtime always runs the tool after the before-hook (packages/opencode/src/session/tools.ts, native path ~L88–93 and MCP path ~L129–139): it triggers tool.execute.before, then unconditionally calls item.execute(...).

Use case: a memory/cache plugin that already holds the answer for a read/grep (an indexed summary or cached result) and wants to return it instead of doing the read. Today it can only let the read happen and prepend a note in tool.execute.after, so the unnecessary work still runs. permission.ask can deny a call but returns an error, not a substitute result.

Proposal

Let tool.execute.before optionally supply a result and/or skip execution:

"tool.execute.before"?: (
  input: { tool: string; sessionID: string; callID: string },
  output: { args: any; result?: string; skip?: boolean },
) => Promise<void>

After the trigger, if skip is set (or result is provided), build the standard output from result and bypass item.execute(...). Backwards compatible — hooks that set neither behave exactly as today. The native and MCP paths return slightly different output shapes, so the substitute would need handling in both.

Alternatives

  • tool.execute.after banner — the tool still runs.
  • permission.ask deny — blocks, but yields an error rather than a clean result.

Happy to open a PR if this seems reasonable. Wanted to check the approach first per the contributing guide.

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