Easy AI coding observability. No guessing who did what.

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.

Try the live demo → Start locally Read the source

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.

One row per prompt you typed

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 promptsprompt ▾
your promptsummaryinput cachedfilescost
And when I hover on the file changes even though those are unstaged… gaurav-mishra · vscode · claude-codeclaude-opus-5 15 t · 12 f · +153 −16 8,415,6068,399,205 12+153 −16 USD 14.03
instead of just name of the user gaurav-mishra · vscode · claude-codeclaude-opus-5 12 t · 9 f · +75 −16 6,430,1926,415,956 9+75 −16 USD 10.91
can we also show device ip address and gmail id… gaurav-mishra · vscode · claude-codeclaude-opus-5 1 t 486,347485,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

Files changedAnd when I hover on the file changes even though those are unstaged…
Close
  • unstaged modifiedweb/src/App.svelte+60 −19
  • unstaged modifiedweb/src/style.css+40 −39
  • staged modifiedinternal/platform/ingest.go+6 −0
  • unstaged deletedinternal/platform/web/assets/index-BKz1vJvD.js+0 −9
  • untrackedinternal/platform/web/assets/index-GtfH5yZ6.js+12 −0

web/src/App.svelte

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 promptsummaryinputcost
instead of just name of the user gaurav-mishra emailgaurav@example.com
ip10.0.4.17
hostdev-laptop
· vscode · claude-codeclaude-opus-5
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

Demo · read-only view of the rubberai project · expires in 1 hour Create your own workspace · Leave demo
OBSERVE / OVERVIEWFull collection
Prompts29
Reported total tokens121.9M
Traces29
Files changed12
your promptsummarycachedfilescost
could you add some verification of the gmail address…gaurav-mishra · vscode · claude-code15 t · 12 f · +153 −168,399,20512USD 14.03
leave it just implement dark modegaurav-mishra · vscode · claude-code12 t · 8 f · +130 −707,012,1428USD 11.76
And I also want to put summary of that particular prompt…gaurav-mishra · vscode · claude-code2 t1,645,2960USD 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.

What it records

Privacy first, by default

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.

Integrate in one request

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.

Read more

API contract

Every field, every event type, retry and idempotency rules.

Architecture

Why one binary and a Postgres, and what that deliberately leaves out.

Claude Code adapter

How prompts, tokens and diffs are captured from hooks and transcripts.

Specification

The full product spec the implementation is held to.

Pricing

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.