Skip to content

OpenCode: reach parity with the Claude integration, then get listed #77

Description

@piwi3910

Why

OpenCode is a first-class host in this repository — .opencode/command/ carries a twin of every command, and .opencode/plugins/procoder.mjs ships the same gate the Claude plugin does. But the integration was written against assumptions that no longer hold, it uses an experimental API for something the platform now does natively, and it cannot be installed by anyone who has not cloned this repository.

The goal: an OpenCode user runs one install line and gets what a Claude Code user gets — the contract injected, the commands registered, the gate holding at the tool boundary, and the session hooks that make the loop work. Then we get listed where OpenCode users actually look.

What OpenCode supports today (researched, with sources)

Plugins are JS/TS modules exporting a function that receives { project, directory, worktree, client, $ } and returns a hooks object. They load from .opencode/plugins/ (project), ~/.config/opencode/plugins/ (global), or an npm package named in opencode.json's plugin array — installed automatically via Bun and cached in ~/.cache/opencode/node_modules/. Types come from @opencode-ai/plugin (currently 1.18.18).

The hook surface is much wider than what we use. Documented events include:

  • tools — tool.execute.before, tool.execute.after
  • files — file.edited, file.watcher.updated
  • sessions — session.created, session.idle, session.compacted, session.diff, session.error, session.status, session.updated, session.deleted
  • commands — command.executed
  • permissions — permission.asked, permission.replied
  • TUI — tui.toast.show, tui.prompt.append, tui.command.execute
  • shell — shell.env; LSP — lsp.client.diagnostics, lsp.updated
  • experimental — experimental.session.compacting

Directories scanned under .opencode/ are the plural forms — agents/, commands/, plugins/, modes/, skills/, themes/, tools/ — with singular names supported only for backwards compatibility.

opencode.json keys we are not using: instructions (file paths and globs, combined with AGENTS.md), permission (per-tool ask/allow/deny), agent, command, mcp, formatter, lsp.

AGENTS.md is read automatically. OpenCode traverses up from the working directory for AGENTS.md, then CLAUDE.md, then ~/.config/opencode/AGENTS.md. The instructions key supplements that — it does not replace it.

Where we stand

Surface Claude OpenCode Gap
Contract injection SessionStart → principles --hook experimental.chat.system.transform pushes AGENTS.md every turn experimental API for something native; likely double-injected
Commit gate PreToolUse (Bash) tool.execute.before (bash) at parity
Write hook PostToolUse (Write|Edit) — missing
Session handoff Stop → hook stop — missing (session.idle)
Pre-compaction handoff PreCompact → hook stop — missing (experimental.session.compacting)
State of play at session start SessionStart prints branch, sprint, open work, index freshness — missing (session.created)
Commands commands/*.md (34) .opencode/command/*.md (34, parity-tested) directory is the legacy singular
Skills skills/procoder/SKILL.md pushed into config.skills.paths by the plugin .opencode/skills/ is scanned natively
Install plugin marketplace entry clone the repo, or hand-copy two directories no npm package

Tasks

1. Stop doing by hand what the platform does natively

  • Verify against the installed OpenCode version whether AGENTS.md is auto-loaded. If it is, delete the experimental.chat.system.transform injection — an experimental API carrying content the host already has is duplication with a deprecation date attached. Keep the Kilo branch if Kilo still needs it.
  • Move the skills path from the plugin's config hook to a scanned .opencode/skills/ location, or state in the code why the hook is still needed.
  • Rename .opencode/command/ to .opencode/commands/, keeping the twin-parity test and the generation rule pointed at the new name.

2. Reach hook parity with the Claude integration

  • session.created → the state-of-play block (principles --hook), so an OpenCode session opens knowing the branch, the sprint, and whether the index is stale.
  • session.idle → hook stop, writing .procoder/state/handoff.md.
  • experimental.session.compacting (or session.compacted) → hook stop, so the handoff survives compaction as it does under Claude.
  • file.edited or tool.execute.after → hook post-tool-use, the write hook.
  • Each hook exits 0 and says nothing when it has nothing to say — the same silence rule the Claude hooks follow.

3. Make it installable

  • Publish the plugin as an npm package (procoder-opencode or @procoder/opencode), so opencode.json can name it instead of a vendored path. The package ships the plugin, the commands, and the skill; the Go binary stays a separate install, exactly as it is for Claude.
  • Document the install in docs/how-to-install-manually.md and docs/portability.md: the plugin entry, the binary on PATH, and what each provides.
  • Decide whether the package pins @opencode-ai/plugin as a peer or a dev dependency only. Note @opencode-ai/plugin@1.1.45 published with unresolved workspace:* and catalog: references — breaks third-party plugin installs anomalyco/opencode#11353 — a published @opencode-ai/plugin with unresolved workspace:* references broke third-party installs, so the dependency needs a tested floor, not a caret guess.
  • Add the OpenCode install path to CI, so a broken plugin is a red check rather than a user's bug report.

4. Get listed

Submissions to opencode.cafe go through the web form at https://opencode.cafe/submit (GitHub sign-in, five submissions per hour, each record reviewed: pending → approved/rejected with a rejection reason). The record it stores:

Field Rule
productId lowercase letters and hyphens only, must start and end with a letter, globally unique
type one of mcp-server, slash-command, hook, theme, web-view, plugin, fork, tool
displayName display name
description short description
repoUrl repository URL
homepageUrl optional
tags array of strings
installation installation instructions, markdown
  • Decide the type. We are a plugin that also ships 34 slash-commands and several hooks; one record has to be chosen, with the rest described in installation.
  • Reserve productId: procoder.
  • Write the installation markdown against the npm package from task 3 — a listing that says "clone this repo" is a listing nobody installs.
  • Submit only after tasks 1-3 land. The review is human and a rejection reason is recorded; arriving with a working install is cheaper than arguing.
  • Separately, open a PR against the awesome-opencode registry — it is the de facto discovery layer and a different audience from the cafe.

Decisions needed

  1. npm package name and scope. procoder-opencode reads as an adapter; @procoder/opencode needs the org. Either commits us to publishing on every release, which the release controller should then verify.
  2. Whether the plugin bundles the binary. Today the plugin shells out to procoder on PATH. Bundling per-platform binaries in the npm package would make it one install instead of two, at the cost of a much larger package and a release job that ships five platforms to npm.
  3. One listing or several. The cafe's types are singular; we span three of them.

Note

opencode.json keeps regaining a "$schema": "https://app.kilo.ai/config.json" line that nothing in this repository writes — presumably the Kilo CLI. It has been reverted once already. If Kilo genuinely needs it, it should be committed deliberately with a comment; if not, it needs to stop being written.

Sources: https://opencode.ai/docs/plugins/ · https://opencode.ai/docs/config/ · https://opencode.ai/docs/commands/ · https://opencode.ai/docs/rules/ · https://github.com/R44VC0RP/opencode.cafe (convex/schema.ts, lib/constants.ts, convex/extensions.ts) · anomalyco/opencode#11353

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions