npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-capture

v0.1.0

Published

opencode plugin that captures session traces (reasoning, tool calls, text, files) as JSONL for the CMF recorder.

Readme

opencode-capture

An opencode plugin that captures the full turn-by-turn trace of a coding-agent session — reasoning ("thinking"), tool calls, text, files, including attempts that were started and then abandoned — while the session is running, and writes it as JSONL for the CMF recorder to pick up.

The plugin runs in-process inside opencode, so there is no separate terminal, no opencode serve + opencode attach coordination, and no SSE/HTTP round-trip. It captures sessions that an out-of-process capture tool cannot reach (bare opencode TUI sessions, which start their own server on a protected random port).

See DESIGN.md for the full design and rationale.

How it works

The plugin subscribes to opencode's event hook, which delivers the host process's Event stream. Each event is handed to the OpencodeAdapter, which translates it into the common trace-event schema and appends it to <spoolDir>/<session_id>.jsonl. The CMF recorder (a separate Python process) tails that file and records each turn into CMF with turn-to-turn lineage.

opencode (with this plugin)  --JSONL-->  spool/  --tail-->  recorder/  -->  CMF
                              (in-process)        (Python, cmflib)

Configuration

Two settings are required — the plugin throws at load if either is missing:

| Setting | Description | |---|---| | pipelineName | CMF label — the top-level grouping all captured turns get recorded under. Not tied to any project; use any name to query later (e.g. cmf execution list -p <name>). | | spoolDir | Absolute path to the directory where <session_id>.jsonl files are written. Must match the recorder's spool_dir. |

Optional:

| Setting | Default | Description | |---|---|---| | sessions | (all) | Array of session IDs to capture; omit to capture every session. |

Settings are passed via the opencode.json plugin options tuple (see Install). For local dev installs that don't receive config options, environment variables are used as a fallback:

| Plugin option (opencode.json) | Environment variable (dev) | |---|---| | pipelineName | OPENCODE_CAPTURE_PIPELINE | | spoolDir | OPENCODE_CAPTURE_SPOOL_DIR | | sessions | (not available via env) |

Install

npm package (published)

opencode auto-installs npm plugins via Bun at startup. Add the plugin to the project's opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [["opencode-capture", {
    "pipelineName": "autoresearch",
    "spoolDir": "/path/to/spool"
  }]]
}

No environment variables needed — options come from the config tuple. Restart opencode and the plugin is active.

Local file plugin (dev)

For local development (editing the adapter, testing changes before publishing), opencode auto-loads any .js or .ts file placed in its plugins directory at startup. Build the plugin and copy the output there:

cd ~/opencode-capture
npm install
npm run build
cp dist/*.js ~/.config/opencode/plugins/   # global (all projects)
# or: cp dist/*.js .opencode/plugins/      # project-local

Local file plugins don't receive opencode.json options, so configuration is via environment variables:

OPENCODE_CAPTURE_PIPELINE=autoresearch \
OPENCODE_CAPTURE_SPOOL_DIR=/path/to/spool \
opencode

Rebuild after any code change:

cd ~/opencode-capture && npm run build && cp dist/*.js ~/.config/opencode/plugins/

Then restart opencode.

Running

Two terminals:

  1. Start the recorder (from the directory where cmf init was run):

    cd /path/to/working_directory
    source "/path/to/recorder/.venv/bin/activate"
    cmf-recorder --spool-dir /path/to/spool
  2. Run opencode (bare TUI, no serve/attach needed):

    With the npm package installed via opencode.json (options come from config):

    cd /path/to/working_directory
    opencode

    Or, with the local dev plugin (configure via env vars):

    cd /path/to/working_directory
    OPENCODE_CAPTURE_PIPELINE=autoresearch \
    OPENCODE_CAPTURE_SPOOL_DIR=/path/to/spool \
    opencode

    Send any prompt. Within ~1 second a <session_id>.jsonl file appears in the spool dir.

Verify it's working

tail -f /path/to/spool/*.jsonl

Expected output:

{"type":"session_start","session_id":"ses_...","pipeline_name":"autoresearch",...}
{"type":"turn_start","session_id":"ses_...","turn_id":"msg_...","turn_index":0,...}
{"type":"part","session_id":"ses_...","part_type":"text","status":"running",...}
{"type":"part","session_id":"ses_...","part_type":"text","status":"completed",...}
{"type":"turn_end","session_id":"ses_...","status":"completed",...}

Then query CMF:

cmf pipeline list                       # should show the configured pipelineName
cmf execution list -p {pipelineName}    # one row per turn
cmf artifact list -p {pipelineName}     # reasoning.jsonl / tool-calls.jsonl / transcript.jsonl per turn

Develop

npm install
npm run typecheck
npm test

test/opencode-adapter.test.ts feeds a synthetic sequence of SDK Event objects (user turn -> reasoning -> a tool call that errors out and is abandoned -> a follow-up text part -> turn completion) through the adapter and checks the resulting trace-event JSONL — this is what pins down that an abandoned tool call keeps its status: "error" and the same seq across updates, and that concurrent sessions and the sessions filter don't cross-talk.

Publish to npm

The package has zero runtime dependencies (all SDK imports are type-only and erase at compile time), so the published tarball contains only dist/*.js and dist/*.d.ts.

  1. Log in to npm (one-time):

    npm login
  2. Bump the version (if needed):

    npm version patch   # or minor / major
  3. Build and publishprepublishOnly runs tsc automatically before packing, so only the built dist/ is included (enforced by "files": ["dist"] in package.json):

    npm publish
  4. Verify it's installable:

    npm view opencode-capture

To publish a new version, bump the version and re-run npm publish.

Architecture

The package is split into a thin plugin entry (src/plugin.ts, ~25 lines) and the reusable adapter core (src/opencode-adapter.ts, src/spool-writer.ts, src/schema.ts). Only the entry knows about the opencode plugin API; the adapter is driven purely by Event objects and writes the common trace-event schema, so it can be reused by any other entrypoint (a CLI, a test harness, another host). See DESIGN.md for the full rationale.

License

ISC