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-meter

v2.1.0

Published

[![npm version](https://img.shields.io/npm/v/opencode-meter)](https://www.npmjs.com/package/opencode-meter) [![CI](https://img.shields.io/github/actions/workflow/status/gdfragoso/opencode-meter/ci.yml)](https://github.com/gdfragoso/opencode-meter/actions)

Readme

opencode-meter

npm version CI License: MIT npm downloads

Session metrics plugin for OpenCode. Tracks tokens, cost, tools, and agents into SQLite, with a Hono REST API and React dashboard.

Features

  • Automatic collection -- hooks into OpenCode's session, message, and tool lifecycle. No configuration needed.
  • Cost tracking -- accumulated from OpenCode's message.updated events via the plugin API. No pricing configuration needed.
  • Dashboard -- React SPA with charts, session details, tool timelines, model breakdowns, error tracking, and projects portfolio.
  • CLI -- opencode-meter --json, --summary, --serve, --prune (no bun run needed after install).
  • Your prompts are not stored -- the plugin records counts, timings and costs. Prompt text and file contents never reach the database; the one exception, a task call's arguments, is spelled out under What Is Not Stored.
  • Decoupled server -- dashboard runs independently of OpenCode. Stays alive when OpenCode closes.
  • Project portfolio -- per-directory aggregated metrics with branch breakdown and model distribution.
  • Error tracking -- captures session errors, error types, and error messages for debugging.

Prerequisites

  • Bun >=1.1 -- required runtime for the plugin and CLI.
  • OpenCode >=1.4.3 -- the plugin hooks into OpenCode's plugin system.

Quick Start

This package ships two installable components, the OpenCode plugin and the opencode-meter CLI. Install both.

  1. Install the OpenCode plugin (metrics collector)
// ~/.config/opencode/opencode.jsonc
{
  "plugin": ["opencode-meter"]
}

OpenCode loads the plugin on next startup. The plugin initializes the database and collector hooks automatically. It does not start the HTTP server, and it does not install the opencode-meter command.

  1. Install the opencode-meter CLI (dashboard plus commands)
npm install -g opencode-meter

The CLI reads from the SQLite database and provides opencode-meter --serve for the dashboard.

Troubleshooting: if you see command not found: opencode-meter, install the CLI with npm install -g opencode-meter.

Alternative Install

Clone the repository and link it manually:

git clone https://github.com/gdfragoso/opencode-meter ~/.config/opencode/plugins/opencode-meter
cd ~/.config/opencode/plugins/opencode-meter
bun install

Now make the opencode-meter command available globally:

bun link --force
# or, if you prefer npm
npm install -g .

Updating

Plugin (collector)

If installed via opencode.jsonc, change the version string in the plugin entry (or omit it to always use the latest).

CLI (dashboard plus commands)

Update from npm:

npm update -g opencode-meter

If you keep a git checkout and want the CLI updated from it:

cd ~/.config/opencode/plugins/opencode-meter
git pull
bun install
bun link --force

Dashboard Usage

The dashboard is a separate HTTP server that runs independently of OpenCode. Start it in a terminal. This requires the CLI installed (Quick Start step 2):

opencode-meter --serve

Open http://127.0.0.1:9393 in your browser. To use another port, pass --port N or set $OPENCODE_METER_PORT (the Vite dev proxy reads the same variable).

The server stays alive when OpenCode closes. You can background it with nohup, screen, tmux, or launchd. The plugin itself only initializes the database and collector hooks, it does not start the HTTP server.

CLI Usage

The CLI reads directly from the SQLite database and outputs to stdout:

opencode-meter --json      # Full metrics as JSON
opencode-meter --summary   # Per-model cost/tokens table
opencode-meter --serve     # Start dashboard HTTP server (default port 9393; override with --port N or $OPENCODE_METER_PORT)
opencode-meter --prune --days 90 --dry-run   # Show what would be deleted
opencode-meter --prune --days 90             # Delete old raw events, then VACUUM
opencode-meter             # Show help message

--json outputs total sessions, requests, cost, tokens, cache hit rate, tools, subagents, errors, per-model stats, and top agents. --summary renders a box-drawing table with model, sessions, cost, and tokens columns.

--prune deletes rows from the raw events log only. Session totals, file activity and daily rollups are kept, so historical cost and token numbers stay correct — what those sessions lose is the per-event tool timeline (the Gantt chart and the per-tool breakdown in Session Detail). Run --dry-run first to see the size. VACUUM needs an exclusive lock, so if OpenCode is running the rows are deleted but the space is only returned to the filesystem on a later prune with OpenCode closed; the command says which of the two happened.

What This Plugin Tracks

| Metric | Description | |--------|-------------| | Tokens | Input, output, reasoning, cache read, cache write per session | | Cost | Total cost per session with input/output/cache breakdown | | Tools | Tool call counts and durations, per session and aggregated | | Agents | Main sessions and subagent sessions with parent/child relationships | | File activity | Files read, created, modified, deleted per session | | Steps and TTFT | Per-step token/cost breakdown and time-to-first-token | | Compaction count | Number of context compaction events per session | | Permissions | Permission requests and responses | | Errors | Session error types and error messages |

What Is Not Stored

The database holds counts, timings, costs and file paths. It does not hold content:

| | | |---|---| | Your prompts | Never read. The collector counts messages; it does not keep their text. | | File contents | OpenCode's session.diff event carries the whole file before and after each edit. Only the file path and the added/removed line counts are persisted. | | Assistant replies | Never read. Only token counts and cost per message. |

The one exception is the task tool's arguments, stored on tool.before and tool.after so delegations can be attributed to the subagent they spawned. Those are the instructions written for a subagent, truncated to 500 characters per field. If that matters to you, it is sanitizeArgs in src/collector/hooks.ts.

Architecture

flowchart LR
    OC[OpenCode] -->|hooks| C[Collector]
    C -->|writes| DB[(SQLite)]
    DB -->|reads| API[Hono API]
    API -->|serves| D[React Dashboard]

The architecture is decoupled into two layers that share a SQLite database:

  • Collector (src/collector/) -- hooks into OpenCode events via the plugin system. Accumulates session data in memory and persists it to SQLite on session end. Runs inside OpenCode's process.
  • Server (src/api/) -- Hono REST API and React dashboard. Served by the CLI's --serve mode as a standalone HTTP server. Has no runtime dependency on the collector code; the two sides meet only at src/data/ (schema, repositories, model types).

This means the dashboard can stay running even when OpenCode is closed, and the data keeps accumulating across OpenCode restarts.

API Endpoints

| Method | Path | Description | Route file | |--------|------|-------------|------------| | GET | /health | Health check | health.ts | | GET | /api/sessions | List sessions (?days=&search=&status=&limit=&offset=&project=&branch=) | sessions.ts | | GET | /api/sessions/types | Main vs subagent breakdown (?days=&project=&branch=) | sessions.ts | | GET | /api/sessions/:id | Session detail with subagents | sessions.ts | | GET | /api/sessions/:id/tree | Delegation tree rooted at the session, with per-branch totals | sessions.ts | | GET | /api/sessions/:id/events | Raw events for a session | sessions.ts | | GET | /api/sessions/:id/tools | Tool usage breakdown for a session | sessions.ts | | GET | /api/sessions/:id/files | File activity per session (read/created/modified/deleted) | files.ts | | GET | /api/cost-efficiency | Cost per file changed / per edit / per line / per session, over the whole window (?days=&project=&branch=) | cost.ts | | GET | /api/period-comparison | This window against the one before it, same length (?days=&project=&branch=) | comparison.ts | | GET | /api/models/cache-timeline | Cache hit rate per model, day by day (?days=&project=&branch=) | cache-timeline.ts | | GET | /api/summary | Aggregate: total sessions, tokens, cost, top models/agents (?days=&project=&branch=) | summary.ts | | GET | /api/daily | Daily rollup rows (?days=&project=&branch=) | daily.ts | | GET | /api/events | Events (?session_id=) | events.ts | | GET | /api/skills | Aggregated skill usage (?days=&project=&branch=) | skills.ts | | GET | /api/tools/overview | Aggregated tool call counts (?days=&project=&branch=) | tools.ts | | GET | /api/tools | Call counts and average duration per tool (?days=&project=&branch=) | tool-metrics.ts | | GET | /api/tool-metrics | Same as /api/tools (alias) | tool-metrics.ts | | GET | /api/errors | Error session aggregation (?days=&project=&branch=) | errors.ts | | GET | /api/models | Per-model aggregate stats (?days=&project=&branch=) | models.ts | | GET | /api/projects | Project portfolio (?days=&project=&branch=) | projects.ts | | GET | /api/projects/:directory | Project detail with branch breakdown, model distribution | projects.ts |

Every route above except /health, /api/events and the per-session ones (/api/sessions/:id...) accepts optional ?days=, ?project= and ?branch= to filter by window, project directory and branch. The limit parameter on /api/sessions is clamped between 1 and 200, default 50.

Data Storage

All data is stored in a single SQLite database at:

~/.local/share/opencode-meter/metrics.db

The database uses WAL mode for concurrent read/write access. Four tables:

| Table | Contents | |-------|----------| | sessions | Session metadata, tokens, cost, tools, errors, parent/child relationships, file activity, steps, tool timings | | events | Raw event log (tool calls, step starts, permissions, commands, LSP diagnostics) | | daily_rollups | Pre-computed daily aggregates (sessions, tokens, cost, tools, models, agents) | | session_files | Per-file activity log (path, action, tool, additions, deletions) |

Development

bun run dev        # Vite dev server (dashboard only)
bun run build      # tsc + vite build
bun test           # Run test suite
bun run typecheck  # tsc --noEmit

Troubleshooting

Port conflict. The default port is 9393. --serve checks the port before binding: if another opencode-meter dashboard already answers there, it says so and exits.

[opencode-meter] A dashboard is already serving on port 9393: http://127.0.0.1:9393
Use --port to run a second one, or stop the other process.

Either use that dashboard, or run a second one with --serve --port N (or $OPENCODE_METER_PORT, which the Vite dev proxy also reads, so dev and served builds agree).

Uninstall

  1. Remove "opencode-meter" from the plugin array in ~/.config/opencode/opencode.jsonc.
  2. Optionally delete the data directory:
    rm -rf ~/.local/share/opencode-meter
  3. If installed via git clone, remove the plugin directory:
    rm -rf ~/.config/opencode/plugins/opencode-meter

Links

License

MIT