OpenCode capture¤
jdsl captures OpenCode as a Tier-B host hook source. OpenCode remains an evidence
source; .jdsl packages still run through the jdsl package runtime.
Requirements¤
- OpenCode installed and configured with your model provider.
- The jdsl harness daemon running locally.
- The project-local plugin from
plugins/jdsl-opencode-plugin/jdsl.ts.
Development note: in this workspace, opencode --version returned command notfound, so the TypeScript plugin follows the official documented OpenCode hook
shape but still needs verification against your installed OpenCode type
declarations.
Install the plugin¤
Project-local install:
mkdir -p .opencode/plugins
ln -sf ../../plugins/jdsl-opencode-plugin/jdsl.ts .opencode/plugins/jdsl.ts
Global install:
mkdir -p ~/.config/opencode/plugins
ln -sf "$(pwd)/plugins/jdsl-opencode-plugin/jdsl.ts" ~/.config/opencode/plugins/jdsl.ts
OpenCode loads plugins from .opencode/plugins/ and
~/.config/opencode/plugins/.
Start capture¤
export JDSL_HARNESS_HOME=/tmp/jdsl-opencode
export JDSL_CAPTURE_ID=cap_opencode
export JDSL_INGEST_URL=http://127.0.0.1:8848
export JDSL_HOOK_TIMEOUT=0.5
uv run jdsl harness serve
In another shell:
opencode
Drive a task that performs tool calls, then inspect the capture:
uv run jdsl capture list
uv run jdsl capture inspect cap_opencode
What is recorded¤
The plugin forwards a stable jdsl.opencode-hook.v1 envelope to:
POST /hook/opencode?cap=<capture_id>
The Python adapter maps:
session.created -> episode.started
tool.execute.before -> tool.call.started
tool.execute.after -> tool.call.completed/tool.call.failed
session.error -> annotation
session.deleted -> episode.finished
Tool starts and completions are correlated by OpenCode callID when present.
The canonical trace stores that value as host_call_id and links completion
events with parent_event_id.
Failure behavior¤
The plugin fails open. If the jdsl daemon is unavailable, slow, or rejects a payload, OpenCode tool execution continues. The plugin emits at most one local warning for transport failures.
Compile¤
Once the capture contains enough successful episodes:
uv run jdsl compile cap_opencode \
--name opencode-behavior \
--out opencode-behavior.jdsl
Then inspect and run the package through jdsl:
uv run jdsl package inspect opencode-behavior.jdsl
uv run jdsl package run opencode-behavior.jdsl --tools <bindings.py> --input <input>=<value>
<bindings.py> must define TOOLS = {logical_id: callable} for every capability
shown by package inspect. The input names are the keys printed in the compile
report's stats.inputs; for example, if compile reports "inputs": ["command"],
run with --input command='...'.
Troubleshooting¤
If capture list is empty, confirm JDSL_CAPTURE_ID, JDSL_INGEST_URL, and
that uv run jdsl harness serve is still running.
If events lack parent linkage, inspect whether the plugin envelope includes
call_id. Without a host call id, jdsl marks correlation as inferred or
ambiguous.
If OpenCode does not load the plugin, verify the symlink target and run:
opencode --version
Then inspect the installed @opencode-ai/plugin type declarations and adjust
plugins/jdsl-opencode-plugin/jdsl.ts if your local hook shape differs.
Uninstall¤
Project-local:
rm .opencode/plugins/jdsl.ts
Global:
rm ~/.config/opencode/plugins/jdsl.ts