Skip to content

[FEATURE]: Comprehensive Plugin Pipeline - Middleware-Style Data Flow Control #5148

Closed as not planned

Description

@mlanza

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

OpenCode's current plugin system provides event hooks but lacks comprehensive pipeline access comparable to middleware patterns like Ring (Clojure) or Rack (Ruby) and dozens in JS land. This restricts plugins from:

  1. Universal tool interception - MCP tools bypass plugin hooks (MCP Tool Calls Don't Trigger Plugin Hooks #2319)
  2. Result manipulation - Plugins can't modify tool outputs before AI sees them
  3. Configuration access - No read access to current tool/agent settings
  4. Pipeline control - Can't implement sophisticated security or transformation policies

Security is my chief concern. If I can’t see and intercept every part of the pipeline — including the pieces that stay tucked away — it’s difficult to build trust. When the whole system is open to inspection, trust comes much easier, because the platform hands some control back to us.

Proposed Solution

Extend plugin system to expose the pipeline and permit middleware. As I explained in my request for modal dialogs (#5147), human-in-the-loop interactions are pipeline based, not event based. Better security, too, is pipeline based. You need to influence what's flowing through the system, not just react to it.

With an extensible middleware architecture and modals, you have a solid backbone which permits an overwhelming number of feature requests to fall out of core and back to the community. That's been my goal with these recent requests: to shift more and more of the feature burden to the community. My thought is every penny spent here is a dime in savings.

Universal Pipeline Hooks

export const PipelinePlugin = async ({ project, client, $, directory, worktree }) => {
  return {
    // Universal interception for ALL operations
    pipeline: {
      before: async (context) => {
        // Intercept any operation (tools, sessions, config)
        // Modify inputs, add auth, implement policies
      },
      after: async (context, result) => {
        // Transform outputs, filter content, add metadata
      },
      error: async (context, error) => {
        // Error handling, recovery, logging
      }
    }
  }
}

The above is purely suggestive of the idea.

Configuration Access

Benefits to Existing Issues

This could help solve:

Implementation Pattern

Similar to established middleware patterns:

  • Chain of responsibility for plugin composition
  • Request/response transformation capabilities
  • Early termination for security policies
  • Context preservation across pipeline stages

Use Cases Enabled

  • Session tainting ([FEATURE]: Session Tainting — A Directional Safety Pattern for Agentic Work #5091) with complete data flow control
  • Security policies for network access and data exfiltration
  • Content filtering and sanitization
  • Advanced logging and audit trails
  • Custom approval workflows beyond basic permissions
    This approach transforms OpenCode plugins from event handlers into powerful middleware capable of sophisticated data flow control, enabling an ecosystem of advanced security, monitoring, and transformation tools.

My several requests are all in service to writing plugins to service my own needs. My goal is to, as much as possible, do that, but it depends on the core you expose (#753).

I'll continue to say it: this is an amazing product. It's only because I'm chomping at the bit to jump in and develop my own features I've been so aggressive with requests. I want to build on opencode. I just want to do it by extension.

Activity

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Dec 5, 2025
  2. github-actions commented on Dec 5, 2025

    @github-actions
    Contributor

    This issue might be a duplicate or closely related to existing issues. Please check:

    Your feature request for a comprehensive plugin pipeline middleware system appears to build upon the foundation of #753. Consider reviewing how the existing plugin system can be extended to support the middleware pattern you're proposing, particularly for universal interception of all operations (including MCP tools) and configuration access.

    Feel free to ignore if your request addresses specific gaps not covered by these issues.

  3. mlanza commented on Dec 6, 2025

    @mlanza
    Author

    In #4960 it really mentions 2 asks. It appears the --config ask has gained traction. I just wanted to note that the other --system-prompt ask is about transparency. The exact thing that a truly open pipeline exposes. So provided the system prompts flow through such a pipeline, this issue swallows that one.

  4. ooohmynas commented on Mar 23, 2026

    @ooohmynas

    feat: plugin pipeline short-circuit for universal tool interception

    Summary
    Implement middleware-style pipeline control for the plugin system via PipelineExecutor
    Enable plugins to intercept and override any tool execution (including MCP tools) using short-circuit
    Extend tool.execute.before hook with result field — setting it skips tool execution and returns the result directly
    Handle Zod v3/v4/JSONSchema7 parameter type mismatches in tool resolution
    Closes #5148

    Changes
    PipelineExecutor — before/after/error hooks with priority sorting and shortCircuit support
    ToolSource — unified composition of built-in and MCP tools
    triggerToolExecution — replaces Plugin.trigger for tool execution, wires hooks through PipelineExecutor
    tool.execute.before hook — new result field: { title: string, output: string, metadata?: Record }

  5. paroque28 commented on Mar 31, 2026

    @paroque28

    Strong +1 on this. We hit exactly the limitation described here. Event-based hooks can't intercept and transform data flowing through the pipeline.

    I built claude-code-redact as a workaround: an external proxy that sits between the client and the LLM provider, redacting outgoing requests and un-redacting incoming responses. It works, but it's a workaround for the lack of middleware-style pipeline access.

    The pipeline.before / pipeline.after pattern proposed here would allow to do this natively, no external proxy needed. Our specific need is redacting secrets/PII before they reach the provider and un-redacting the response, but the middleware pattern is general enough to support compliance logging, DLP, cost monitoring, and more.

    Related: #4961, #19425

  6. removed
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on May 3, 2026
  7. OddballGreg commented on Jun 16, 2026

    @OddballGreg

    A concrete, minimal use case for the "early termination" part of this, in case it helps scope a first slice.

    I'm building a memory/cache plugin. On a read/grep it sometimes already holds the answer, an indexed summary or cached result, and wants to return that instead of doing the read. Today tool.execute.before can only mutate args, and the runtime calls item.execute(...) unconditionally afterwards (in packages/opencode/src/session/tools.ts, both the native path around L88-93 and the MCP path around L129-139), so the read always runs. tool.execute.after can rewrite the result, but by then the work has already happened. permission.ask denies a call but returns an error rather than a clean substitute result.

    The smallest version of "early termination" that would unblock this is letting 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>

    If skip or result is set, build the output from result and bypass item.execute(...). It stays backwards compatible since hooks that set neither behave exactly as today. The native and MCP paths return different output shapes, so both would need handling.

    Not trying to narrow the broader pipeline vision here, just flagging a real plugin that needs the early-termination piece, in case a minimal before short-circuit is a reasonable first step toward it.

  8. OddballGreg commented on Jun 17, 2026

    @OddballGreg

    Opened a PR for the minimal early-termination slice described above: #32679. It adds an optional result to tool.execute.before so a plugin can answer a tool call itself and skip execution, wired through both the native and MCP paths. Backwards compatible. Picks up the idea from the earlier #18689 in a much smaller form, scoped just to the before short-circuit rather than the full pipeline.

  9. github-actions commented on Aug 17, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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