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
2. Reach hook parity with the Claude integration
3. Make it installable
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 |
Decisions needed
- 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.
- 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.
- 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
Why
OpenCode is a first-class host in this repository —
.opencode/command/carries a twin of every command, and.opencode/plugins/procoder.mjsships 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 inopencode.json'spluginarray — 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:
tool.execute.before,tool.execute.afterfile.edited,file.watcher.updatedsession.created,session.idle,session.compacted,session.diff,session.error,session.status,session.updated,session.deletedcommand.executedpermission.asked,permission.repliedtui.toast.show,tui.prompt.append,tui.command.executeshell.env; LSP —lsp.client.diagnostics,lsp.updatedexperimental.session.compactingDirectories scanned under
.opencode/are the plural forms —agents/,commands/,plugins/,modes/,skills/,themes/,tools/— with singular names supported only for backwards compatibility.opencode.jsonkeys we are not using:instructions(file paths and globs, combined with AGENTS.md),permission(per-toolask/allow/deny),agent,command,mcp,formatter,lsp.AGENTS.md is read automatically. OpenCode traverses up from the working directory for
AGENTS.md, thenCLAUDE.md, then~/.config/opencode/AGENTS.md. Theinstructionskey supplements that — it does not replace it.Where we stand
SessionStart→principles --hookexperimental.chat.system.transformpushes AGENTS.md every turnPreToolUse(Bash)tool.execute.before(bash)PostToolUse(Write|Edit)Stop→hook stopsession.idle)PreCompact→hook stopexperimental.session.compacting)SessionStartprints branch, sprint, open work, index freshnesssession.created)commands/*.md(34).opencode/command/*.md(34, parity-tested)skills/procoder/SKILL.mdconfig.skills.pathsby the plugin.opencode/skills/is scanned nativelyTasks
1. Stop doing by hand what the platform does natively
AGENTS.mdis auto-loaded. If it is, delete theexperimental.chat.system.transforminjection — 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.confighook to a scanned.opencode/skills/location, or state in the code why the hook is still needed..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(orsession.compacted) →hook stop, so the handoff survives compaction as it does under Claude.file.editedortool.execute.after→hook post-tool-use, the write hook.3. Make it installable
procoder-opencodeor@procoder/opencode), soopencode.jsoncan 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.docs/how-to-install-manually.mdanddocs/portability.md: thepluginentry, the binary on PATH, and what each provides.@opencode-ai/pluginas 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/pluginwith unresolvedworkspace:*references broke third-party installs, so the dependency needs a tested floor, not a caret guess.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/rejectedwith a rejection reason). The record it stores:productIdtypemcp-server,slash-command,hook,theme,web-view,plugin,fork,tooldisplayNamedescriptionrepoUrlhomepageUrltagsinstallationtype. We are apluginthat also ships 34slash-commands and severalhooks; one record has to be chosen, with the rest described ininstallation.productId: procoder.installationmarkdown against the npm package from task 3 — a listing that says "clone this repo" is a listing nobody installs.awesome-opencoderegistry — it is the de facto discovery layer and a different audience from the cafe.Decisions needed
procoder-opencodereads as an adapter;@procoder/opencodeneeds the org. Either commits us to publishing on every release, which the release controller should then verify.procoderon 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.Note
opencode.jsonkeeps 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