# Overview

> What tapes captures, which binary owns the database, default listen ports, and the first docs routes after install.

- Repository: papercomputeco/tapes
- GitHub: https://github.com/papercomputeco/tapes
- Human docs: https://grok-wiki.com/public/docs/papercomputeco-tapes-020596f21750
- Complete Markdown: https://grok-wiki.com/public/docs/papercomputeco-tapes-020596f21750/llms-full.txt

## Source Files

- `README.md`
- `cmd/tapes/tapes.go`
- `cmd/tapes/serve/serve.go`
- `docs/introduction.md`
- `AGENTS.md`
- `go.mod`

---

---
title: "Overview"
description: "What tapes captures, which binary owns the database, default listen ports, and the first docs routes after install."
---

`tapes` is the Go server for this repository (`github.com/papercomputeco/tapes`, Go 1.26+). It owns PostgreSQL, runs the capture and derive pipeline, and serves the sealed read and ingest contracts. It does not launch agents or read sessions back: that is [`tapesctl`](https://github.com/papercomputeco/tapesctl), a separate client.

## What tapes captures

Capture is append-only. A transparent proxy (or a trusted ingest write) intercepts completed LLM turns and persists them in `raw_turns`. Each turn is stored twice:

| Column | Role |
| --- | --- |
| `raw_response` | Upstream bytes, verbatim |
| `response` | Lossy reduction produced by the capture adapter |

A pure, idempotent **deriver** projects that log into the read model **sessions → traces → spans**. Re-derive reproduces the same projection and prunes derived rows that are no longer present. Derived IDs are deterministic. Content addressing (`merkle.ProjectContent`) runs in memory at derive time for identity and dedup; the persisted merkle `nodes` table is gone and is not a browsing surface.

Reads go through the derived surface: `/v1/sessions`, `/v1/traces`, `/v1/stats`, `/v1/search/spans`, and the original capture at `/v1/sessions/{id}/raw_turns`.

The in-repo proxy understands Anthropic, OpenAI, and Ollama request shapes. Gateway capture uses `tapes-extproc` (Envoy ext_proc), a separate image that POSTs completed turns to ingest and must not depend on the API, the database, or the derive worker being healthy.

## Two binaries

| Binary | Owns | Does not own |
| --- | --- | --- |
| `tapes` | Services, PostgreSQL (with pgvector), operator CLI (`init`, `local`, `serve`, `status`, `auth`, `config`, `backfill`, `raw`, `dev`, `version`) | Agent launch, session list/export/search/skill client commands |
| `tapesctl` | Capture and read against a running server | The database, listen sockets, workers |

Commands that used to live here moved with the client: `tapes start` → `tapesctl start`, `tapes export` → `tapesctl export`, `tapes seed` → `tapesctl seed`, `tapes sessions` → `tapesctl sessions list`, `tapes search` → `tapesctl search`, `tapes skill` → `tapesctl skill`. Do not re-add them to this binary. `tapes chat` is removed. Span search stays server-side (`GET /v1/search/spans` plus the embed worker).

<Warning>
`tapesctl` never guesses a server. Configure the read API once (`tapesctl config set tapes-url http://localhost:8081`). Capture (`start`, `capture`, `sync`) must target ingest on `:8082`. A capture pointed at the read port reports success and stores nothing.
</Warning>

## Default listen ports

Defaults come from `NewDefaultConfig()`:

| Address | Config key | Surface |
| --- | --- | --- |
| `:8080` | `proxy.listen` | Provider-compatible capture proxy. Forwards to `proxy.upstream` (default `http://localhost:11434`) as `proxy.provider` (default `ollama`). |
| `:8081` | `api.listen` | Public read API: health, derived sessions/traces/spans, search, skills, admin, MCP, cassette proxy, compiled `GET /openapi`. |
| `:8082` | `ingest.listen` | Private in-cluster write path: `POST /v1/ingest`, `POST /v1/ingest/transcript`, `GET /ping`. |

Client-side defaults in this binary's config are `client.proxy_target = http://localhost:8080` and `client.api_target = http://localhost:8081`. The client you actually run (`tapesctl`) uses `tapes-url` / `TAPES_URL` / `--tapes-url` instead.

| Port | `tapesctl` commands |
| --- | --- |
| `:8081` | `sessions`, `traces`, `spans`, `search`, `export`, `seed` (`POST /v1/admin/seed/demo` on the API, which replays bundled corpora through ingest + derive) |
| `:8082` | `start`, `capture`, `sync` |

`GET /` on the API is off unless you pass `--api-web-ui` (`api.web_ui`, default `false`). Do not infer production auth, TLS, or exposure from these listen defaults.

## All-in-one runtime

```bash
tapes local up    # Docker: Postgres+pgvector (and Ollama unless a native server is already up)
tapes serve
```

`tapes serve` starts, in one process:

- proxy, read API, and ingest HTTP servers
- in-process derive worker (2s debounce)
- in-process embed worker (10s interval) unless `--embed-spans=false`

Embedding defaults: `embedding.provider = ollama`, `embedding.model = embeddinggemma`, `embedding.dimensions = 768`, `embedding.target = http://localhost:11434`. A down embedding backend disables search; it does not fail the stack. Split the same roles with `tapes serve proxy|api|ingest|derive-worker|embed-worker`.

```mermaid
flowchart LR
  subgraph client["tapesctl"]
    startCmd["start / capture"]
    readCmd["sessions / search / export / seed"]
  end

  subgraph serve["tapes serve"]
    proxy[":8080 proxy"]
    ingest[":8082 ingest"]
    api[":8081 read API"]
    derive["derive worker"]
    embed["embed worker"]
  end

  subgraph store["PostgreSQL"]
    raw["raw_turns"]
    derived["sessions / traces / spans"]
    vec["pgvector span embeddings"]
  end

  agent["agent or provider client"] --> proxy
  proxy --> upstream["upstream LLM"]
  proxy --> raw
  startCmd --> ingest
  ingest --> raw
  raw --> derive --> derived
  derived --> embed --> vec
  derived --> api
  vec --> api
  readCmd --> api
```

## First docs routes after install

Install both binaries, then follow these pages in order. They are the first routes after this overview.

<Steps>
<Step title="Install and bootstrap">
Install `tapes` and `tapesctl`, run `tapes local up`, and confirm with `tapes version` and `tapes local status`. See [Installation](/installation).
</Step>
<Step title="Serve, seed, capture">
Run `tapes serve`, point `tapesctl` at `http://localhost:8081`, seed demo data, list sessions, then capture a real agent against `:8082`. See [Quickstart](/quickstart).
</Step>
</Steps>

<CodeGroup>

```bash title="Install the server"
curl -fsSL https://download.tapes.dev/install | bash
tapes version
```

```bash title="Install the client"
curl -sSfL https://download.tapes.dev/tapesctl/install | bash
tapesctl version
```

</CodeGroup>

After `tapes serve`, a live check of the read API:

```bash
curl http://localhost:8081/ping
tapes status
```

`tapesctl seed` is idempotent: raw-turn dedup is `(org_id, request_id)`, transcript rows hash their content, and derive upserts the same projection. Seeded sessions are tagged project `demo`.

## Operator surface on this binary

| Command | Role |
| --- | --- |
| `tapes init [--preset openai\|anthropic\|ollama]` | Create `.tapes/` |
| `tapes local up\|status\|down` | Local Postgres and Ollama. `down --wipe` deletes captured data. |
| `tapes serve` | Full local stack |
| `tapes status` | Config, upstream, API reachability, capture summary |
| `tapes auth` | Provider keys in `.tapes/credentials.toml` (embedding / skill generation — not agent capture) |
| `tapes config get\|set\|list` | Scalar settings. Precedence: flag, then `TAPES_…`, then `config.toml`, then defaults. |
| `tapes raw equivalence` | Compare stored `raw_response` re-reductions against stored `response` |
| `tapes version` | `Version`, `Sha`, `Built at` |

## What this repo does not do

- Host chat. Capture and derive only.
- Ship the client CLI. `tapesctl` is a different repository.
- Persist a merkle browsing graph.
- Replace the console for ROI / session browsing. The deck TUI is removed; enable `--api-web-ui` only for the minimal API HTML UI.

## Next

<CardGroup>
<Card title="Installation" href="/installation">
Install tapes and tapesctl, bootstrap local PostgreSQL and Ollama, verify with tapes version and tapes local status.
</Card>
<Card title="Quickstart" href="/quickstart">
Start tapes serve, point tapesctl at :8081, seed demo data, then capture one agent against :8082.
</Card>
<Card title="Capture and derive" href="/capture-and-derive">
Append-only raw_turns, the lossy reduction beside raw_response, and the idempotent deriver.
</Card>
<Card title="Read API vs ingest" href="/read-vs-ingest">
Two sealed contracts and the :8081 / :8082 trust boundary.
</Card>
</CardGroup>
