Copied to clipboard

Architecture

tapes consists of three main components:

Proxy Server Intercepts LLM requests, forwards to upstream provider, and stores conversation turns in the Merkle DAG
API Server Provides HTTP endpoints for inspecting and querying the stored conversation data, plus Prometheus /metrics
Ingest Server Sidecar HTTP endpoint that accepts completed conversation turns when an external gateway handles upstream LLM traffic

All three servers share the same PostgreSQL database (with pg_duckdb + pgvector) when run together via tapes serve.

Data Flow


  ┌─────────────┐         ┌──────────────────┐         ┌──────────────────┐
  │             │         │                  │         │                  │
  │  Claude Code│────────▶│   Proxy :8080    │────────▶│   Upstream LLM   │
  │  Ollama CLI │◀────────│                  │◀────────│  (Anthropic,     │
  │  AI SDK     │         │  intercept +     │         │   Ollama, etc.)  │
  │  curl ...   │         │  forward         │         │                  │
  │             │         └────────┬─────────┘         └──────────────────┘
  └─────────────┘                  │
                                   │ store
                                   ▼
                          ┌──────────────────┐
                          │                  │
                          │  PostgreSQL      │
                          │  ┌────────────┐  │
                          │  │ pg_duckdb  │  │  ← Merkle DAG
                          │  │ pgvector   │  │  ← embeddings
                          │  └────────────┘  │
                          │                  │
                          └────────┬─────────┘
                                   │
                                   │ query
                                   ▼
  ┌─────────────┐         ┌──────────────────┐
  │             │         │                  │
  │  Deck TUI   │◀───────▶│   API :8081      │
  │  tapes CLI  │         │                  │
  │  MCP clients│         │  /v1/sessions    │
  │  Prometheus │         │  /v1/stems       │
  │             │         │  /v1/stats       │
  │             │         │  /v1/search      │
  │             │         │  /v1/mcp         │
  │             │         │  /metrics        │
  └─────────────┘         │  /swagger        │
                          │                  │
                          └──────────────────┘

Requests flow through the proxy, which forwards to your upstream LLM and stores each conversation turn as a hashed node in the Merkle DAG. The API server reads from the same storage to serve session, search, and MCP queries — and self-documents at /swagger via Scalar.

Merkle DAG

Each conversation turn is hashed and linked to its parent, forming an append-only directed acyclic graph:


  (root)
    │
    ▼
  ┌──────┐     ┌──────┐
  │ req  │────▶│ res  │   Session A
  │ a1b2 │     │ c3d4 │
  └──────┘     └──┬───┘
                  │
                  ▼
              ┌──────┐     ┌──────┐
              │ req  │────▶│ res  │   Turn 2
              │ e5f6 │     │ 7g8h │
              └──────┘     └──┬───┘
                              │
                              ├──────────────┐
                              ▼              ▼
                          ┌──────┐       ┌──────┐
                          │ req  │       │ req  │  Branched
                          │ i9j0 │       │ k1l2 │  (checkout)
                          └──────┘       └──────┘

Every node contains a content hash of the message, model, and parent reference. This enables cryptographic verification of conversation history and branching via tapes checkout.

Last updated: