Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CLI reference

tapes is the server. It runs the services, owns the database, and carries the operator tooling around them. Capturing a session and reading one back are client concerns and live in tapesctl — see The client CLI below.

Run tapes <command> --help for the complete, version-matched flag list.

CommandUse
tapes init [--preset ...]Create a local .tapes/ configuration directory.
`tapes local [upstatus
tapes serveRun proxy, read API, private ingest API, derive worker, and optional embed worker together.
tapes statusShow active config, provider/upstream, API reachability, and capture summary.
tapes authStore OpenAI or Anthropic credentials in .tapes/credentials.toml.
`tapes config getset
tapes raw equivalenceProve stored capture bytes re-reduce to the stored reduction. See Proving the capture ratchet.
tapes versionPrint version information.

Running services

The common local command is:

tapes serve

It accepts provider/upstream, PostgreSQL, listening, embedding, and project flags. Useful examples:

tapes serve --provider anthropic --upstream https://api.anthropic.com
tapes serve --api-web-ui
tapes serve --embed-spans=false

For split deployments, service subcommands are available:

tapes serve proxy
tapes serve api
tapes serve derive-worker
tapes serve embed-worker
tapes serve ingest

The last three are operator-oriented: the derive worker projects dirty sessions, the independent embed worker populates search vectors, and the private ingest sidecar receives completed turns from a trusted gateway. See HTTP APIs before exposing any endpoint.

The client CLI

Launching an agent under capture, listing sessions, exporting one, and seeding demo data are all client operations against a running server. They live in tapesctl:

curl -sSfL https://download.tapes.dev/tapesctl/install | bash
tapesctl start claude --tapes-url http://localhost:8081
tapesctl sessions list --tapes-url http://localhost:8081
tapesctl export <session-id> --detail spans -o session.jsonl
tapesctl seed --tapes-url http://localhost:8081
tapesctl skill sync <name> --claude

Every tapesctl command takes --tapes-url, falling back to TAPES_URL. Arguments after -- go directly to the agent. See Agent integrations and the tapesctl README for the full surface.

Proving the capture ratchet

raw_turns keeps two views of the same upstream response: raw_response, the bytes exactly as they arrived, and response, the reduced turn a capture adapter produced from them. The reduction is lossy, and while a second reducer runs inside the capture adapter, two capture paths can reduce the same traffic differently.

The fix is to have exactly one reducer, server-side. Getting there is a deliberate three-step ratchet, configured on the capture adapter:

ModeWhat the adapter sendsStored fidelity
offits reduction onlyreduced
dualits reduction and the verbatim bytesraw
rawverbatim bytes only; tapes reducesraw

dual exists to make the middle step provable. It changes nothing an operator sees — ingest keeps the adapter’s reduction — while putting the bytes in the database next to it. That makes the question “would raw have produced this same row?” answerable offline, over real traffic:

tapes raw equivalence --since 24h --limit 5000

For each wire turn in the window that has both halves, the command decodes the stored bytes, re-reduces them through the same server-side path raw would run, and compares the result against the stored reduction. It exits non-zero if anything diverged or failed to reduce, so it can gate the step in CI.

Run it inside the cluster against a tenant’s database:

kubectl exec -n <tenant-ns> deploy/tapes-api -- \
  tapes raw equivalence --since 24h --limit 5000

or locally against a forwarded database, with --json for machine consumption:

tapes raw equivalence \
  --postgres "postgres://user:pass@127.0.0.1:15432/tapes" \
  --since 24h --json

The comparison is read-only, and it never prints response content — a difference is reported as a JSON path plus the shape of what differs, because these are real prompts.

Reading the result

Every examined turn lands in exactly one class. equivalent is the one that supports a ratchet step. divergent, undecodable, unreducible and no_reducer all block it: the last three are worse than a divergence, because under raw those rows would carry no reduction at all. The skipped_* classes describe turns the flip does not affect — no bytes were captured, the bytes were withheld or dropped over a limit, or the turn was already captured raw-only.

Two fields are excluded from the comparison, and the report always prints them:

  • created_at — reducers stamp it at reduction time, so two reductions of identical bytes taken at different instants differ by construction.
  • usage.total_duration_ns — the wall clock from request to fully-assembled response. Only the party that watched the stream can measure it; a reduction of stored bytes cannot.

Everything else is compared strictly, so a third difference is reported rather than absorbed.

Because both excluded fields are ones raw restores from the capture adapter’s meta block rather than from the bytes, the report also counts which stamps would actually have been available. A window can be perfectly equivalent and still lose data on the flip: if usage.total_duration_ns shows fallback, those turns carry no usable meta.elapsed_seconds, and under raw their duration — and the derived span’s duration_ns — would land empty. Check that line before ratcheting, not just the verdict.

Commands not intended as everyday workflow

backfill is for replaying existing capture artifacts into a deployment. dev contains developer maintenance utilities. Consult their --help only when operating those workflows.

Tapes no longer provides chat or checkout commands. It captures external agents; it does not host a chat client or expose history branching.

The start, export, seed, sessions, and skill sync commands have moved to tapesctl; tapes keeps the server and the operator tooling.