Skip to content

Track upstream: collapse .opencode-plugin to a thin shell-script bridge once OpenCode ships native Claude Code hook compat #58

Description

@jsirish

Context

Jason raised a real architectural concern during #56's fix-up: .opencode-plugin/ is a full TypeScript reimplementation of the same capture/redaction/session-start logic that hooks/*.sh already implements for Claude Code and Codex, rather than one shared implementation with a thin per-harness adapter. That's a real maintenance cost — this session alone fixed two production bugs (#56) that were exactly this kind of reimplementation drift (a wrong naming-convention assumption, a wrong event-consumption model) that could not have happened if OpenCode ran the same shell scripts Claude Code and Codex do.

What's blocking a shell-out today

Researched via context7 + the upstream anomalyco/opencode repo:

  • anomalyco/opencode#12472 — "native Claude Code hooks compat," open, active (18 comments, last updated days ago), assigned to a maintainer. Proposes OpenCode natively read ~/.claude/settings.json-style hooks, translate tool names (bashBash, editEdit), and pipe the same JSON-on-stdin/exit-code protocol our shell scripts already speak — i.e. exactly what would let .opencode-plugin become a thin bridge instead of a reimplementation. Not shipped.
  • A community member got frustrated enough to submit the adjacent piece directly — #19519, tool.execute.after message injection — filed two weeks after the underlying issue (#17412) went unanswered by maintainers. Closed, unmerged. No committed timeline for either.
  • A community bridge plugin already exists, magarcia/opencode-claude-hooks — loads .claude/settings.json and runs its hooks as shell commands inside OpenCode's plugin system, real precedent for the shell-out pattern. Its own docs note "existing Claude Code hooks don't move to OpenCode due to different runtime and API requirements," so it's not a drop-in reference implementation, but it proves the pattern works.
  • Our own experimental.chat.system.transform usage (the only way to inject the HANDOFF.md/git-state block into context today) rests on the same missing primitive #17412 describes — plugin hooks can't inject AI-visible messages through any stable API yet. This is the correct tool available today, not a stopgap we chose poorly; it's just genuinely fragile until OpenCode ships something more stable, matching the plugin's own header comment.

Decision

Don't attempt a partial shell-out now — hand-rolling our own stdin/exit-code bridge ahead of any committed OpenCode compat surface would just be a second bespoke OpenCode integration, arguably worse than the current TypeScript port (which at least has full test coverage and doesn't depend on translating tool-call arg shapes across two independently-evolving protocols).

Trigger for revisiting: when anomalyco/opencode#12472 (or an equivalent native-hooks feature) ships, re-evaluate collapsing .opencode-plugin/src/hooks/*.ts down to a thin adapter that shells out to hooks/*.sh the same way Codex reuses them via its own convention — eliminating the version-drift and reimplementation-bug class entirely. Low priority until then; watch the upstream issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions