Sessionly

A ledger for AI coding agents

What your coding agents did, what it cost, and how much of it survived.

Sessionly records every Claude Code, Cursor and Grok session: what was asked, which tools ran, which files changed and what it cost. On each developer's machine first, and for the whole team once you connect a server.

Open source under Apache-2.0. Nothing leaves a machine until you connect it to a server, and the default upload contains no text from prompts, commands or files.

shell
$ sessionly summary --by tool --since 30d
TOOL         SESSIONS       COST    ACTIVE  PROMPTS  TOOLS (FAILED)  FILES           LINES      REWRITTEN  LINES KEPT
Claude Code        64    $412.80   38h 12m      702     15310 (291)    348    +21480 -3112  121/344 (35%)         67%
Cursor             41     $96.40   11h 05m      389        6204 (0)    183     +7498 -1431   28/178 (16%)         91%
Grok                9     $18.75    4h 31m       61       1740 (22)     52      +3120 -604    17/52 (33%)         58%
---------------------------------------------------------------------------------------------------------------------
total             114    $527.95   53h 48m     1152     23254 (313)    583    +32098 -5147  166/574 (29%)         72%
Local first Capture, parsing and redaction happen on the developer's machine. The command line works without any server.
Three agents, one record Claude Code, Cursor and Grok sessions sit in the same ledger, so a row means the same thing whichever agent produced it.
Survival, not volume Counts how many of an agent's lines are still in the file later, and still in the pull request after review.

How it works

A small local program does the work. A server is optional.

The sessionly binary sits beside your agents and keeps a ledger in ~/.sessionly. If your team runs a Sessionly server, the same records are uploaded there and shown in a dashboard. What an upload may contain is on the security page.

  1. Capture

    A hook appends each agent event to a local file in 2–4 ms. It only observes: it cannot block or change a session.

  2. Read

    Tokens, models and cost come from the transcripts and session files the agents keep themselves.

  3. Normalize

    Both become one record per session in a local SQLite ledger: prompts, tool calls, files, subagents, cost.

  4. Measure

    On every sync, the lines each session added are counted again in the files as they are now.

  5. Upload

    Only if you connect a server. Paths are made relative and the content level you chose is applied first.

agent → hook and transcripts → sessionly → ~/.sessionly, then, if connected, upload → Sessionly server → team dashboard.

The ledger is derived data: delete it and sessionly sync --force rebuilds it from the raw capture.

What you get

The session, the cost, and what became of the code.

Cost you can trace

Tokens and cost per session, model and subagent, summed per person, repository, model, agent or day. The agent's own recorded figure is used where there is one; an estimate is marked as an estimate.

Rewrite rate

For every file a session changed, Sessionly keeps hashes of the lines the agent added and counts how many are still there later. Moved or re-indented code counts as kept.

Search from the terminal

sessionly list, summary and show filter by repository, person, model, agent, file, date and cost, and search prompts and commands. Every command takes --json.

Team dashboard

Cost per day; totals by agent, person, repository and model; the files agents changed in each repository; and every session down to its prompts, tools and subagents.

Past sessions

sessionly import rebuilds sessions from the files the agents still keep, so the ledger does not start empty. On one machine, 100 sessions in 2.5 GB of transcripts took about a minute.

A hook that stays out of the way

The capture hook appends one line and exits. It never prints and always exits 0, whatever its input, so a capture failure cannot block or change your session.

You choose what is uploaded

The default upload has counts, timings and relative paths but no text at all. Previews are opt-in, and sessionly export shows the exact payload before anything is sent.

Tokens and roles

Each token belongs to one person. A member sees their own sessions, an admin sees the team, and a ci token can only report pull requests. Only a hash of each token is stored.

An open record

One session record with a published JSON Schema is the contract between the binary and any server. A test fails if the schema in the repository is stale.

Agents

Claude Code, Cursor and Grok, side by side.

Each agent's tools are mapped to common names (Read, Edit, Write, Bash, Grep, Glob), and each agent's sessions are read from where that agent keeps them. Where an agent does not record something, Sessionly says so instead of filling it in.

Claude Code Cursor Grok
How sessions arrive Hooks as they happen; transcripts for past sessions Its transcript files, plus the hooks, which Cursor also runs Its session files, plus the hooks, which Grok also runs
Prompts, tool calls, files and lines changed Yes Yes Yes
Subagents Yes Yes Not recorded by Grok
Model and tokens Per request Per turn, for turns the hooks saw Yes
Cost Claude Code's recorded total, with an estimate for what it leaves out An estimate at API list prices for turns the hooks saw. Not what Cursor bills Grok's own figure
Rewrite rate Yes Yes Yes

Checked with Cursor 3.27 and Grok 1.0.77. Sign-in files of either agent are never opened.

Pull requests

How much of this pull request did an agent write, and how did it fare?

A GitHub Action reports each pull request to your server, which matches the lines it adds against the lines agents added in uploaded sessions. Both sides send hashes: no source code leaves GitHub or anyone's machine.

  • Per pull request: lines added, how many an agent wrote and with which agent and model, review rounds, and comments by people and by review bots.
  • By model: the same, summed, so you can see whose lines get through review as written and whose take several rounds.
  • A floor, not a guess: a line counts as an agent's only when a session by someone who committed to the pull request added that line to that file.
  • Quiet by default: figures go to the run's summary and to a page for admins. A comment on the pull request is yours to switch on.
run summary
Sessionly

78% of the lines this pull request adds were written by a coding agent (1,806 of 2,315).

Tool          Model              Lines
Claude Code   claude-opus-5-5    1,204
Cursor        not known            602

Of the 1,790 agent lines it had when it was opened, 1,647 are still there (92%).

Counts added lines that have a letter or digit. Everything not matched to an uploaded session, including agents nobody captured, counts as not an agent's.

What is uploaded

Full content stays on the machine. The default upload carries no text.

Each developer's machine decides what a server receives. There are two content levels, and sessionly export <session> prints exactly what would be sent, connected or not.

On the machine Uploaded: metadata (default) Uploaded: previews (opt in)
Full prompts, file contents, command output In the raw capture, readable only by you Never Never
Prompts Length, hash, first 200 characters Length only First 200 characters and the hash
Commands, search patterns, URLs, errors One line each, up to 200 characters No text One line each, up to 200 characters
File paths Absolute Relative to the repository, or to ~/ Relative to the repository, or to ~/
Counts, timings, tool names, models, tokens, cost Yes Yes Yes
Git name, email and remote Yes Yes Yes
Hashes of the lines an agent added Yes Only if switched on Only if switched on

A preview can contain anything that was typed or run, including a secret. Line hashes are what pull request attribution needs; a hash does not give the line back, but a short or common line can be guessed and checked against it.

Editions

Open source at the core. Self-hosted today.

Everything on this page is in the open-source edition. It never needs a license key.

Business and Enterprise

By quote

A signed license file for your self-hosted server.

  • Everything in the open-source edition
  • Content policy: the organisation sets what uploads from its engineers should contain. The server stores and serves it; the binary does not apply it yet
  • Checked offline: the license never phones home
  • After expiry, 14 days of grace, then read-only. The core never stops
Ask about a license

Hosted

Not open yet

The same server, run for you.

  • The same code as the self-hosted server
  • The same content levels: metadata by default, previews opt-in
  • Until it opens, self-hosting is how a team runs Sessionly
Tell me when it opens

Sessionly is early. There are no packaged releases yet (you build the binary with Cargo), and sign-in to the dashboard is by token. The README says what works today.

Get started

On your own machine in a few minutes.

Build the binary, install the hooks and import the sessions your agents still have. Listing, search, summaries and the rewrite rate all work without a server.

  • Careful with your settings. Only Sessionly's own hook entries are added or removed, and the settings file as it was is saved beside it.
  • Easy to undo. sessionly uninstall takes the hooks out again.
  • Try it on one project. sessionly install --project DIR writes to that project's settings only.
one machine
$ git clone https://github.com/KIvanow/sessionly && cd sessionly
$ cargo install --path crates/sessionly   # Rust 1.89 or later

$ sessionly install   # adds hooks to ~/.claude/settings.json
$ sessionly import    # past sessions of all three agents

$ sessionly list
$ sessionly summary --by tool
$ sessionly show <session>

For a team, one Docker Compose file.

It starts the server, the dashboard and Postgres. Each developer connects their machine once; after that, sessions upload on their own when a turn ends.

  • Put it behind HTTPS. The binary refuses plain http:// for anything but a server on the same machine.
  • One token per person. An admin creates and revokes them on the Team page.
  • Nothing phones home. A self-hosted install sends no data to Sessionly.

Read the server guide

a team
# on the server
$ SESSIONLY_ADMIN_TOKEN=choose-a-long-secret \
    docker compose up -d

# on each developer's machine
$ sessionly connect https://sessionly.example.com
$ sessionly upload --dry-run   # count what would be sent
$ sessionly upload

# optional: send previews, or the line hashes pull requests need
$ sessionly settings --content previews
$ sessionly settings --line-hashes on

Read the numbers for what they are.

Cost is the agent's own recorded figure where there is one and an estimate from token counts elsewhere; it is not an invoice. The rewrite rate measures whether lines survived, not whether they were good or why they changed. The agent share of a pull request is a floor. Names and emails come from git config: a label, not a verified identity.

Get started

Start with one machine. Add the team when the numbers are useful.

The code, the session record's schema and the limits of every figure are in the repository.