Crosshire
Tech·Developer tools·9 min read·19 July 2026

Spend, with receipts.

Every coding session with an AI agent leaves a perfect paper trail — a JSONL transcript of every model call and every tool it ran. AURA reads that trail and hands you the itemized bill: what you spent, on which model, for which task. Local-first, open source, and honest about how fresh its own numbers are.

If you use Claude Code — or Cursor, Aider, or any agentic coding assistant — you are already producing a goldmine of structured data on how you and your team think, debug, and ship. It sits, unread, in ~/.claude/projects/**/*.jsonl. AURA — Agent Usage & Resource Analytics — turns that exhaust into a usable record: a local dashboard that shows every dollar broken down by model, agent, and project, and reconciles to the same total on every page it appears. Nothing is uploaded anywhere. This is the tour of what it does and how it stays honest.

The top of the AURA dashboard: the 'Spend, with receipts.' headline, a 30-day spend total with its daily chart, and a KPI strip — active sessions, cache hit rate, tool calls, commits, errors, and a 30-day projection.
The top of the dashboard — one headline number, its daily chart, and the KPI strip. Every figure on the page reconciles to the same source.
01What it is

Your transcript exhaust, read back to you

AURA answers three questions from the data your agent already writes: what did the agents do today, where is the money going, and is the pipeline telling me the truth. It is built for the individual first and the team second — the same local stack, plumbed so that each developer's processed, masked marts (never raw conversations) can later roll up to one shared dashboard.

For you
Introspection

Run it on your own machine, against your own transcripts. See which tasks you over-spend on, when you reached for Opus to fix a typo, your cache hit rate, and where the tokens and time actually go — attributed down to the files you touched.

Runs today
For your team
Honest agent ROI

The schema already carries a tenant_id per machine. Each laptop ships its masked, aggregate marts to a central store; one team dashboard reads the union — cost and throughput per project and per machine. Full detail stays private and local; only aggregates travel.

Designed, plumbed
02The pipeline

Two independent stages, one medallion

AURA is a small data platform in a trench coat. Raw JSONL becomes bronze; bronze becomes marts. The two stages never wait on each other — dbt transforms whatever is already in raw_events the moment its clock fires, so the dashboard fills in progressively after a cold start instead of blocking on a full backfill.

01 Watch
Watcher (Python)
A polling observer tails every .jsonl under your logs dir, redacts secrets, and inserts one row per event. Polling — not inotify — because filesystem events drop silently on Windows and Docker bind-mounts.
02 Bronze
DuckDB, append-only
raw_events plus session, skills, and MCP tables. Byte offsets are tracked in ingest_checkpoints, so a re-run never double-writes and settled bytes are never re-read.
03 Transform
dbt, every cycle
Staging → intermediate → marts. Source-freshness, seed, run, and test on a fixed interval. Cost is priced from an SCD-style seed joined on the timestamp of the model call, so old sessions stay correctly priced when rates change.
04 Serve
Next.js, read-only
Server components query a read-only snapshot of the DuckDB file. The connection layer checks the file's inode on every query and reopens transparently the instant the snapshot is atomically replaced — so a page never serves stale bytes.
The invariant that makes it safe DuckDB allows exactly one writer per file. AURA enforces it as a rule: only the watcher ever opens the write database. dbt runs as a subprocess; the frontend reads a snapshot copy; the dashboard's "mark this session wrong" verdicts arrive through an append-only inbox file the watcher drains — never a second writer. One writer, no lock conflicts, no torn reads.
03What you see

Eight screens, one number

Every page shares a range filter (today / 7d / 30d / all) and, where it shows a cost, the same cost. Here is the map.

Dashboard
The headline

Spend for the range, a KPI strip (active sessions, cache hit rate, tool calls, commits, errors, projection), the daily-spend chart, and ledgers for apps, projects, and agents.

Sessions
The ledger

Every session with title, model, turns, cost, and agent. Click one for a per-turn breakdown with tabs for agents, errors, files, tokens, tools, and git.

Agents
Real attribution

Every subagent × app row with its true cost — technical-writer, code-reviewer, and friends no longer lump under one giant claude bucket. The same agent name in two projects shows as two rows.

Skills & MCPs
What loaded

Which skills and MCP servers each session, app, and agent pulled in — surfaced as top-ten lists, so you can see what your agents actually reach for, and what it costs when they do.

Apps & Tokens
Where it goes

Cost per working directory and per project; token spend sliced by type, provider, model, and agent, with a fixed palette that makes the expensive output and cache-write tokens legible at a glance.

Errors & Observability
Does it lie?

Hard errors, warnings, and tool failures in one place — and a live pipeline view (ingestion freshness, dbt run status, source-freshness, watcher failures) that polls every ten seconds so you always know how current a number is.

04The receipts

Why the numbers are trustworthy

"With receipts" is a promise about reconciliation, not decoration. A cost that says something different on two screens is a bug, not a rounding artifact — so AURA is built so it cannot happen.

Six rules the pipeline enforces
  • One source for every dollar. A single pre-aggregated table pivots spend to (date × app / agent / project). The Dashboard, Apps, Agents, and Tokens pages all read it — so the total equals the sum of the parts, always.
  • Cost is anchored to event time. A session that began yesterday and ran into today gets yesterday's tokens on yesterday and today's on today — never bucketed by session-start.
  • Cache hit rate uses the right denominator. Reads over reads-plus-writes, not reads over input tokens — the ratio you'd actually reach for.
  • Pricing is time-travel-correct. The pricing seed carries valid-from / valid-to; each call is priced at the rate in effect when it ran, so history stays honest through rate changes.
  • Overkill is flagged. Each request is scored on complexity and compared to the model tier it drew. Opus for a one-liner gets marked — the cheapest audit of your own habits there is.
  • Subagents keep their spend. When the orchestrator dispatches a task, every event until the result is attributed to that subagent — so delegated cost lands on the delegate, not the parent.
05Privacy

Local-first, and honest about the seam

Everything above runs entirely on your machine — the transcripts never move. The team story is deliberately an export problem, not a hosting one: only the processed, masked gold marts leave a laptop, and the sensitive text columns are masked before they do.

Shipped today
Ingest-time hashing. A flag replaces conversational content with a SHA-256 marker as the line is written to bronze — after secret-redaction, so a leaked credential is scrubbed first, then hashed. Those columns become cryptographically non-recoverable.
Honest trade-off
Turn hashing on and the raw text is gone from bronze for those events — not merely hidden in the UI. Counts, costs, tool names, and timestamps keep working untouched; you choose, per machine.
Plumbed, not hand-wavy
Every table already carries tenant_id; the pricing seed supports per-tenant overrides; the dbt project is warehouse-portable. Point the same frontend at a central replica and it just reads.
Still to build
The exporter itself — the job that pushes masked marts on an interval — plus central-side dedup and dashboard auth. Designed, not yet written. Said plainly, because a roadmap dressed as a feature is its own kind of dishonest number.
06Hard-won

The lessons are in the tuning knobs

AURA was built against a real, growing transcript set, and the interesting parts are the failures it learned from. A few, straight from the repo's troubleshooting notes:

Lock starvationA dbt cycle holds the single write-DB lock for its whole duration; snapshotting a multi-GB file holds it too. Set either interval too low and cycles run back-to-back, starving ingestion for hours. The shipped compose leaves comfortable headroom between cycles on purpose.
Impossible OOMAn Out of Memory ... 16383.9 PiB used is not real exhaustion — it is orphaned spill files from an unclean shutdown poisoning DuckDB's temp accounting. The watcher now purges them on boot; a genuine exhaustion reports a sane figure instead.
Incremental where it countsMost models rebuild fully each cycle — cheap at one developer's scale. The heaviest three (the text-heavy extraction models) went incremental only once their full-history rebuilds outgrew the memory pool, cursored on the ingest checkpoint rather than event time.
Wide text lives in a viewThe full conversational text is exposed through a view, computed on demand for the handful of rows a session page renders — never baked into a table mart, which exhausted the pool on a rebuild. The fact tables stay narrow and cheap.
See your own spend
AURA is MIT-licensed and Dockerized. Clone it, point it at ~/.claude/projects, and in one docker compose up you are looking at your own itemized bill — on your machine, uploaded nowhere.
Two containers · DuckDB + dbt + Next.js · Claude Code today, more adapters on the roadmap.
The architecture, in full
How it works
The one-writer invariant, the inbox-file verdict pattern, the dbt-and-snapshot independence, and the medallion graph end to end — straight from the repository docs.
The sister products
Honest scoring, elsewhere
The same instinct — show the working, name the gaps — applied to hiring and to language learning. Both are working products on Crosshire.

Written from the AURA source and its running local dashboard — the architecture, the reconciliation rules, and the tuning figures are taken from the repository and its docs, not a projection. The screenshots and numbers a reader would see are their own transcripts; none of the author's private spend appears here. — Crosshire.

© 2026 Crosshire Journal · Made in EU Written from an open-source tool