rubberai records what your AI agents actually do — every prompt, the tokens it cost, the files it changed and the diff — across any IDE, agent or model. One Go binary and a Postgres. No LLM proxy, no Kafka, no cloud account, and nothing leaves your machine unless you say so.
The demo is a read-only view of the real project used to build rubberai — no
signup, nothing to install. Or docker compose up --build for your
own. MIT licensed. Metadata-only collection by default.
A single prompt fans out into dozens of model calls and tool calls. rubberai collapses that back into the turn you actually asked for, with everything it cost and everything it touched.
The activity overview — real data from building rubberai with Claude Code
| your prompt | summary | input | cached | files | cost |
|---|---|---|---|---|---|
| And when I hover on the file changes even though those are unstaged… | 15 t · 12 f · +153 −16 | 8,415,606 | 8,399,205 | 12+153 −16 | USD 14.03 |
| instead of just name of the user | 12 t · 9 f · +75 −16 | 6,430,192 | 6,415,956 | 9+75 −16 | USD 10.91 |
| can we also show device ip address and gmail id… | 1 t | 486,347 | 485,492 | 0 | USD 0.85 |
Click a file count to see every file with its git state and diff. Click a prompt to read the agent's own account of what it did.
Click a file count — every file the turn touched, with its git state and the diff
unstaged modified · +60 −19 · reported as AI
@@ -13,13 +13,30 @@ let group=$state('prompt'),userFilter=$state(''),- let filePop:{x:number;y:number;rows:FileChange[]}|null=$state(null);- function showFiles(event:MouseEvent,rows:FileChange[]|null){- if(!rows||!rows.length){filePop=null;return}+ let changeSet:{label:string;rows:FileChange[]}|null=$state(null);+ function mergeChanges(rows:FileChange[]):FileChange[]{+ // One event is recorded per change, so a file edited twice+ // in a turn arrives twice. Merge by path.+ const byPath=new Map<string,FileChange>(); function closeChanges(){changeSet=null;changeFile=null}
Changes are read from git after every tool call, so an edit made through a shell heredoc or a build is caught the same as one made through an edit tool. Staged, unstaged and untracked are reported separately, never flattened.
Hover a username — who, from which machine
| your prompt | summary | input | cost |
|---|---|---|---|
| instead of just name of the user | 12 t · 9 f · +75 −16 | 6,430,192 | USD 10.91 |
Identity comes from git — the email a developer already signs commits with — plus the host and its LAN address, read from the routing table with no packet sent. All three travel as metadata, which a metadata-only project discards on arrival. Shown here with placeholder values.
What the demo button opens — the real dashboard, read-only
| your prompt | summary | cached | files | cost |
|---|---|---|---|---|
| could you add some verification of the gmail address… | 15 t · 12 f · +153 −16 | 8,399,205 | 12 | USD 14.03 |
| leave it just implement dark mode | 12 t · 8 f · +130 −70 | 7,012,142 | 8 | USD 11.76 |
| And I also want to put summary of that particular prompt… | 2 t | 1,645,296 | 0 | USD 2.73 |
Everything is clickable — file changes, diffs, the agent's own summaries. Nothing is editable.
How it stays safe: the button opens /demo on the server, which issues a short-lived session that can only read one designated project. There is no password in the page, no shared login, and the session cannot create keys, change settings or write events. Visitors who want their own data create a workspace of their own.
sed, a heredoc or a build is caught the same as an edit tool. With the diff.A new project collects metadata only: counts, timings, identifiers. Prompt text, diffs and personal data are discarded on arrival unless you switch the project to full collection. Nothing is inferred — an AI change without evidence is recorded as unknown, not claimed. Usage is not a developer performance score, and the dashboard says so.
Any language, no SDK required. This is the whole contract:
# one event; batches of up to 100 are atomic curl https://rubberai.example/api/v1/events \ -H "Authorization: Bearer $RUBBERAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event_id":"evt_1","event_type":"llm.request.completed", "project_id":"prj_…","timestamp":"2026-09-12T10:00:00Z", "model":{"provider":"anthropic","name":"claude-sonnet-5"}, "usage":{"input_tokens":1200,"output_tokens":300,"cached_tokens":900}}' → {"accepted":1,"duplicates":0}
Examples in curl, Python, JavaScript and Java. A durable local collector buffers events to disk and retries, so a server restart never loses a turn.
Every field, every event type, retry and idempotency rules.
ArchitectureWhy one binary and a Postgres, and what that deliberately leaves out.
Claude Code adapterHow prompts, tokens and diffs are captured from hooks and transcripts.
SpecificationThe full product spec the implementation is held to.
Free. Self-hosted. MIT.
There is no hosted version and no plan to sell one. Run it on a laptop, a VPS or a container platform — it needs a Go binary and a Postgres and nothing else. Your data stays wherever you put it.