Skip to content

[FEATURE]: plugin hook for streamed tool metadata (bash output is persisted before tool.execute.after can redact it) #51937

Open

Description

@r-d-w

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

Problem: a plugin that redacts secrets in tool.execute.after can't reach the copies of bash output that were already persisted while the command was still running.

While output streams, bash calls ctx.metadata({ metadata: { output } }). Each update is saved as a running-state message.part.updated row in the event table of opencode.db, before tool.execute.after runs. Mutating output.output / output.metadata in the after-hook fixes the final part, the model context and the truncated-output file, but the streamed rows keep the raw value.

Repro (1.18.18, macOS):

export const RedactDemo = async () => ({
  "tool.execute.after": async (_input, output) => {
    const scrub = (s: string) => s.replaceAll("SECRET-1234567890", "<redacted>")
    output.output = scrub(output.output)
    if (typeof output.metadata?.output === "string") output.metadata.output = scrub(output.metadata.output)
  },
})
  1. Load the plugin and have the model run printf SECRET-1234567890.
  2. The tool result shows <redacted>.
  3. sqlite3 ~/.local/share/opencode/opencode.db "select count(*) from event where instr(data, 'SECRET-1234567890') > 0" returns > 0.

Ask: either of these would let plugins close the gap:

  • a hook such as tool.execute.metadata, run on each ctx.metadata() update before it is published or persisted, which can mutate the metadata; or
  • an option not to persist running-state part updates, keeping only the final state.

Built-in redaction was declined in #19425 / #32183. This asks only for the hook, so plugins can do it themselves. We use it to mask 1Password op:// secrets that a plugin resolves for MCP auth.

Activity

  1. github-actions commented on Sep 28, 2026

    @github-actions
    Contributor

    This issue might be related to existing issues. Please check:

  2. r-d-w commented on Oct 6, 2026

    @r-d-w
    Author

    Checked these, none are duplicates:

  3. r-d-w commented on Oct 6, 2026

    @r-d-w
    Author

    @rekram1-node happy to send a PR for this if you'd take it.

    Approach: add a tool.execute.metadata hook that runs where a tool's ctx.metadata() update is published and persisted, with { tool, sessionID, callID } as input and a mutable { title, metadata } output. That way a plugin can rewrite streamed bash output before it's written to the event table. It's a no-op when no plugin registers it. I'd include a test showing that a registered hook's changes land in the persisted part.

    OK to proceed?

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