Skip to main content

agentabacus

Local-first analytics for AI coding agents. Every agent CLI writes session logs to your disk in its own format. Nothing reads all of them. agentabacus normalizes them into one schema and answers: what did this cost, which model actually finishes the work, and where is the spend going?

No server. No account. No network calls. It reads files that are already on your machine and writes one DuckDB file.

uvx agentabacus collect      # read new log data into the archive
uvx agentabacus report       # cost and tokens, last 30 days

Why this exists

Three things make the naive version of this tool wrong, and all three are handled here.

1. Summing usage per log line overcounts by 2–3×

Claude Code writes one JSONL line per content block — thinking, text, each tool_use — and every one of those lines repeats the full usage of the parent API response. Measured on a real session: 16 assistant lines, 6 actual requests.

naive per-line sum deduped by requestId overcount
input 5,273 1,759 3.0×
output 18,555 7,861 2.4×
cache read 712,283 264,865 2.7×
cache write 61,219 25,647 2.4×

The multiplier depends on how many content blocks a response happened to emit, so it can't be corrected after the fact with a constant. agentabacus keys the turns table on request_id and merges with MAX().

2. Cache writes are not one number

A 1-hour TTL cache write bills at base input. A 5-minute write bills at 1.25×. A cache read bills at 0.1×. Claude Code records the split (cache_creation.ephemeral_1h_input_tokens vs ephemeral_5m_input_tokens); collapsing them into a single cache_creation_input_tokens figure misprices exactly the long sessions where cache tokens accumulate.

3. Subagent transcripts live in separate files

~/.claude/projects/<slug>/<uuid>.jsonl                             # main transcript
~/.claude/projects/<slug>/<uuid>/subagents/agent-*.jsonl           # plain subagent
~/.claude/projects/<slug>/<uuid>/subagents/workflows/wf_*/agent-*.jsonl   # workflow subagent

Two things bite here. A projects/*/*.jsonl glob — the obvious one — misses every subagent file. And a */subagents/*.jsonl glob still misses the workflow subagents one level deeper, which on a machine that runs workflows are the majority (measured: 80 of 127). Discovery has to recurse.

Subagent files carry the parent's sessionId plus their own agentId, so the thread is what separates them, not the session. agentabacus report --by thread splits main-loop from subagent spend — a number no other tool surfaces.


Install

uvx agentabacus report          # zero-install trial
pipx install agentabacus        # permanent CLI

Then:

agentabacus doctor              # what's discoverable, what's collected, what has no price
agentabacus collect             # incremental; safe to run repeatedly

Collect automatically (Claude Code plugin)

Transcripts get garbage-collected, so collection has to happen without you remembering. The plugin registers a SessionEnd hook that archives each session as it closes:

/plugin marketplace add tripleaceme/agentabacus
/plugin install agentabacus@agentabacus

The CLI must be on your PATH (pipx install agentabacus). No daemon, no cron entry.

Commands

agentabacus report --since 30d --by model      # or: source project branch day effort speed thread
agentabacus top --limit 10                     # most expensive sessions
agentabacus cache                              # read share and the 1h/5m write split, priced
agentabacus tools                              # tool-call volume and error rate
agentabacus doctor                             # health + pricing gaps
agentabacus export --format parquet            # hand the tables to dbt / Metabase
agentabacus sql "select ..."                   # the schema is yours

--by thread splits main-loop spend from subagent spend — the number most tools can't show you at all.

Where the data lives

~/.agentabacus/agentabacus.duckdb     # the archive: everything, all time

Override with AGENTABACUS_HOME. The collector is incremental: it records a byte offset per file and re-reads nothing, so a repeat run over a 350 MB corpus costs one stat() per file.

This matters more than it sounds. Claude Code garbage-collects old transcripts. Project directories with a memory/ folder and zero .jsonl files are what that looks like afterwards — that history is gone permanently. Once cleanup runs, this database is the only copy. agentabacus is an archive with a dashboard on top, not a dashboard.

Privacy

Prompt and response bodies never enter the pipeline. The prompts table stores a SHA-256 and a character count; there is no column for the text. That's a schema property, not a filter you have to trust — "does this leak my code?" is answerable by reading schema.py.

Nothing is uploaded anywhere. There is no telemetry.

Pricing

src/agentabacus/data/pricing.csv — effective-dated, one row per model per speed tier:

model_id,speed,valid_from,valid_to,input_per_mtok,output_per_mtok,cache_read_per_mtok,cache_write_5m_per_mtok,cache_write_1h_per_mtok,source_note
claude-opus-5,standard,2020-01-01,,5.00,25.00,0.50,6.25,10.00,anthropic list price

Cost is computed as tokens × price-at-event-timestamp, via the turns_costed view. Joining against a "current price" table would silently reprice last quarter's sessions.

agentabacus doctor lists any model seen in your data that has no pricing row — that's the alarm for "a new model shipped and the table is stale", which is otherwise a silent undercount.

Adding a model is a one-line CSV edit. Dates currently use an early valid_from so historical sessions price at today's rate; real effective dates are welcome as PRs.

Contributing an adapter

One module exposing parse(path, kind, start_offset) -> Batch, a walker in discovery.py, one line in adapters/__init__.py. See adapters/claude_code.py for the reference and adapters/codex.py for the minimal template.

The rule: be a tolerant parser. These formats are undocumented and change without notice. Route on known shapes, count what you skipped, never raise — a vendor's routine release must not become a crash for every user. Strictness belongs in schema.py, not at the edges.

python tests/test_dedupe.py    # pins the dedupe contract, the TTL split, and torn-line handling

Status

Source State
Claude Code verified against real transcripts
Codex CLI shape-agnostic, unverified — needs someone with real rollout files
Gemini CLI, Cursor, Aider, Cline not yet written

Roadmap

  • Edit-survival metric from file-history-snapshot.trackedFileBackups (pre-edit backups are already in the transcript, so no git join is needed for Claude Code)
  • More adapters
  • agentabacus dash — local static dashboard
  • Teams: warehouse sinks (Postgres/Snowflake/BigQuery), redaction policy in version control, a GitHub Action for rollups
  • dbt_agentabacus: staging models over the parquet export, pricing as a seed, tests as drift detection

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentabacus-0.1.0.tar.gz (29.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentabacus-0.1.0-py3-none-any.whl (30.8 kB view details)

Uploaded Python 3

File details

Details for the file agentabacus-0.1.0.tar.gz.

File metadata

  • Download URL: agentabacus-0.1.0.tar.gz
  • Upload date:
  • Size: 29.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentabacus-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3f1387114ae4f89901a141654a3de8e5adbbd6fb2dbfa00f133640e00308c3ba
MD5 a8a7cbd6c142a99fc1f4df7a619f6b40
BLAKE2b-256 b5b129c0363edb1af71b66fbf2ebb0d571de9f33381cd6d1db67694dc71c9890

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentabacus-0.1.0.tar.gz:

Publisher: release.yml on tripleaceme/agentabacus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agentabacus-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: agentabacus-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agentabacus-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3fee10df8fb35947e882e452206dc9524a6bf6e9ee6486314f29ff157ee5599b
MD5 f2ab9c439d151d011aaa52e57dc9d11f
BLAKE2b-256 5572724a45cb804b1e84d1ff4e49596e2a0008f320814bcca7d24cb5484cc613

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentabacus-0.1.0-py3-none-any.whl:

Publisher: release.yml on tripleaceme/agentabacus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page