Skip to content

[FEATURE]: Plugin hooks should be able to inject AI-visible messages into conversation context #17412

Description

@doomsday616

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

OpenCode's plugin hooks (tool.execute.before, tool.execute.after, session.idle) can intercept and modify tool calls, but they cannot inject messages into the AI's conversation context. This makes it impossible to build skills that require ongoing behavioral enforcement — the AI simply forgets after a few tool calls, and near-guaranteed forgets after compaction.

Evidence: planning-with-files skill benchmark

The planning-with-files skill enforces a structured 3-file planning pattern (task_plan.md, findings.md, progress.md). On Claude Code, it uses PreToolUse/PostToolUse/Stop hooks to continuously remind the AI. The hooks inject messages the AI sees in conversation — not just intercept tool calls.

Benchmark results (10 parallel subagents, 5 task types, 30 objectively verifiable assertions):

Metric With skill + hooks (Claude Code) Without skill
Pass rate (30 assertions) 96.7% (29/30) 6.7% (2/30)
3-file pattern followed 5/5 evals 0/5 evals
Blind A/B wins 3/3 (100%) 0/3
Avg blind rubric score 10.0/10 6.8/10

What happens on OpenCode today

We run this same skill on OpenCode. The SKILL.md loads, the AI starts strong, then:

  1. After ~5-10 tool calls — the AI "forgets" to update progress.md and findings.md. No PostToolUse hook to remind it.
  2. After automatic compaction — the planning workflow is ~100% forgotten. The compacted summary doesn't preserve behavioral rules. The AI continues the task but abandons the 3-file pattern entirely.
  3. When the AI finishes — no Stop hook to check "did you update all planning files?" — it just stops.

We've tried mitigations: AGENTS.md rules, agent.prompt injection for subagents, TodoWrite tracking. None survive compaction reliably.

The gap

Capability Claude Code OpenCode
Block/modify tool calls ✅ hooks ✅ tool.execute.before
Inject AI-visible message after tool call ✅ (stderr → system message) ❌
Re-activate agent before stopping ✅ Stop hook (exit 2 → continue) ❌ (session.idle is fire-and-forget)

Proposed API

For tool.execute.after — allow injecting a message the AI sees:

"tool.execute.after": async (input, output) => {
  if (input.tool === "edit") {
    output.inject = [
      { role: "user", text: "Remember to update progress.md with what you just changed." },
    ]
  }
}

For session.stopping (per #16598) — allow continuation with injected message:

"session.stopping": async (input, output) => {
  output.inject("You haven't updated progress.md yet.");
  output.continue();
}

Implementation

We've submitted a proof-of-concept PR that implements the tool.execute.after injection side:

#19519 — feat: allow tool.execute.after hooks to inject AI-visible messages

The implementation is ~57 lines across 2 files:

  • Adds an optional inject field to the tool.execute.after output type
  • A flushInjectedMessages() helper persists injected entries as synthetic user messages (same pattern as existing subtask summary messages)
  • Handles all three hook call sites: registry tools, MCP tools, and subtask tools
  • Fully backward compatible — inject is optional, existing plugins are unaffected

Why this matters

Skills are OpenCode's strongest differentiator. But any skill requiring behavioral enforcement beyond initial instructions (planning, linting, security guardrails, SOP compliance) degrades severely without message injection. The benchmark data shows a 96.7% → estimated ~30% drop — making an entire category of skills non-viable.

Related

Activity

added
coreAnything pertaining to core functionality of the application (opencode server stuff)
on Mar 13, 2026

github-actions commented on Mar 13, 2026

@github-actions
Contributor

This issue might be a duplicate of existing issues. Please check:

(Note: #12472 and #16626 are already referenced in your issue.)

doomsday616 commented on Mar 13, 2026

@doomsday616
Author

Paging interested parties

Tagging folks from related discussions who may find this relevant:

The core argument: OpenCode's plugin system can already intercept tool calls, but skills that need ongoing behavioral enforcement (planning, linting, security) degrade severely because there's no way to inject reminders the AI actually sees. Compaction makes it worse — behavioral rules from initial skill loading are the first thing lost.

doomsday616 commented on Mar 13, 2026

@doomsday616
Author

🐱 Gentle nudge to the team

    /\_____/\
   /  o   o  \
  ( ==  ^  == )
   )         (
  (           )
 ( (  )   (  ) )
(__(__)___(__)__)

  "plz... can haz
   output.inject()?"

Hey OpenCode team — would love to get some eyes on this from the core maintainers:

  • @thdxr — you're assigned to Native Claude Code hooks compatibility (PreToolUse, PostToolUse, Stop) #12472 which covers the broader Claude Code hooks compat. This issue distills the single most impactful missing primitive: letting plugin hooks inject messages into the AI's conversation. The benchmark data (96.7% → ~6.7% without enforcement hooks) makes a strong case. Would love to hear if output.inject() on tool.execute.after is something that fits the plugin architecture direction.
  • @adamdotdevin @nexxeln @Hona — as core team members, curious if this aligns with the plugin system roadmap. The proposed API is minimal (one new method on the output object), but it would unlock an entire category of enforcement-based skills that currently only work on Claude Code.
  • @jayair @fwang — you've both been active contributors. The session.stopping draft PR (feat: add session.stopping hook for plugins #16598) by @yehudacohen already tackles half of this (the Stop hook side). The other half (PostToolUse message injection) is arguably simpler to implement.
  • @kujtimiihoxha — your work on the plugin system internals means you'd know best whether output.inject() is feasible within the current hook execution pipeline.

This isn't just about one skill — it's about making OpenCode's skill ecosystem competitive for any workflow that needs the AI to stay on track beyond initial instructions. The data shows it's a 10x difference. 🙏

added a commit that references this issue on Apr 4, 2026
e52ef15
removed
coreAnything pertaining to core functionality of the application (opencode server stuff)
on May 3, 2026

Arcadi4 commented on May 27, 2026

@Arcadi4
Contributor

Seems like the core problem is already resolved by experimental.chat.messages.transform. However, I still found the DX and UX undesirable, so I opened a follow-up #29633.

github-actions commented on Jul 27, 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