Captures OpenCode session events in-process and forwards them to the slopometry CLI for storage, analysis, and mid-session feedback injection.
OpenCode (in-process) Slopometry (external)
┌─────────────────────┐ ┌─────────────────────┐
│ Plugin hooks into: │ │ │
│ - tool.execute.* │ spawn + stdin │ hook-opencode CLI │
│ - bus events │ ──────────────> │ parses JSON │
│ - promptAsync() │ <── stdout ─── │ stores in DB │
│ │ (feedback) │ generates feedback │
└─────────────────────┘ └─────────────────────┘
The plugin hooks into OpenCode's in-process event system and spawns
slopometry hook-opencode --event-type <type> per event, passing JSON on stdin.
This mirrors how slopometry integrates with Claude Code via shell hooks.
| Event | Source | Data |
|---|---|---|
pre_tool_use |
tool.execute.before hook |
tool name, session ID, call ID, args |
post_tool_use |
tool.execute.after hook |
tool name, args, output (truncated), duration_ms |
message_updated |
message.updated bus event |
per-message tokens, cost, model, agent |
todo_updated |
todo.updated bus event |
full todo list with status/priority |
subagent_start |
session.created bus event (with parentID) |
child session ID, parent ID |
stop |
session.idle bus event |
aggregated tokens, cost, transcript via SDK |
When slopometry returns feedback on stdout (code smells, context coverage warnings), the plugin injects it in two ways:
- Inline — appended to tool output via
tool.execute.after(visible with the tool result) - Stop feedback — on
session.idle, if slopometry returns smell feedback, the plugin callsclient.session.promptAsync()to send a synthetic user message that triggers a new agent turn to address the smells (mirrors Claude Code's blocking stop hook). AnawaitingFeedbackTurnflag prevents the follow-up idle from looping, but re-arms for subsequent user turns.
- slopometry must be installed and in PATH (
uv tool install slopometryor from source) - OpenCode v1.2+ with plugin support
Find your OpenCode config directory:
# Usually one of:
# ~/.config/opencode/ (Linux default)
# $XDG_CONFIG_HOME/opencode/ (if XDG_CONFIG_HOME is set)
# ~/.opencode/ (macOS / fallback)Create a plugins directory and symlink:
mkdir -p $XDG_CONFIG_HOME/opencode/plugins
ln -sf /path/to/slopometry/plugins/opencode/index.ts \
$XDG_CONFIG_HOME/opencode/plugins/slopometry.tsOpenCode auto-discovers plugins/*.ts files in config directories and
auto-installs @opencode-ai/plugin (creates a managed package.json
and runs bun install in the config dir on startup).
Add the plugin path to opencode.json (project-level or in .opencode/):
{
"plugin": ["file:///path/to/slopometry/plugins/opencode"]
}Then ensure dependencies are installed in the plugin directory:
cd /path/to/slopometry/plugins/opencode
bun installslopometry install --target opencodeThis writes the file:// plugin path into opencode.json in the current directory.
- Start an OpenCode session and use some tools (file reads, edits, bash commands)
- Check that slopometry captured events:
slopometry solo ls slopometry latest
- Verify the session shows
source=opencodein the database:slopometry solo show <session-id>
The plugin is a single TypeScript file (index.ts) that exports a Plugin function.
It has no build step — OpenCode (Bun) imports .ts files directly.
To iterate on the plugin:
- Edit
index.ts - Restart OpenCode (the plugin is loaded on startup)
- Check
slopometry hook-opencode --helpfor the CLI interface
To test the CLI handler in isolation:
echo '{"tool":"Bash","session_id":"test","call_id":"c1","args":{"command":"ls"}}' \
| slopometry hook-opencode --event-type pre_tool_use