Capsule Architecture
A capsule is Rohrpost’s unit of raw knowledge — a prompt, a response, a diff, an error, or a note, exactly as it happened. Capsules are the immutable source of truth; everything else (chunks, embeddings, graph entities, summaries) is derived from them by the distillation pipeline, and can be rebuilt from the capsule if a downstream index ever needs to be recomputed.
What a capsule holds
Each capsule stores:
| Field | Purpose |
|---|---|
| Source | Where it came from — an MCP client, the CLI, the OpenAI-compatible proxy, an IDE plugin |
| Kind | prompt, response, tool_call, diff, error, or note |
| Content | The raw text |
| Metadata | Arbitrary tags — project, session ID, affect, and other structured fields used by ranking and filtering |
| Created at | Timestamp, used for recency scoring and decay |
Capsules are written once to Postgres and archived as immutable JSON in Garage (S3-compatible object storage) for audit and replay.
The distillation pipeline
Every capsule flows through the same pipeline, asynchronously, via NATS JetStream:
- Capture — the gateway authenticates the request, attaches the tenant, and publishes the capsule to NATS the moment it arrives
- Chunk — a distiller worker splits the content into semantically coherent chunks
- Embed — each chunk gets a vector embedding (via a local Ollama model —
nomic-embed-textby default) and is indexed for both vector similarity search (pgvector) and BM25 keyword search (Tantivy) - Extract — entities and relationships mentioned in the chunk (files, functions, decisions, people, tools) are extracted and written into the knowledge graph (Apache AGE)
- Summarize (periodic, not per-capsule) — once a session or feature scope accumulates enough capsules, a hierarchical summary is generated and stored separately for fast high-level recall
None of this blocks the original request — NATS JetStream guarantees the capsule is durably queued even if a distiller worker is temporarily down, so nothing captured is ever lost to a crash mid-pipeline.
Recall
A query runs vector search, BM25, and (when the query mentions or resolves to a known entity) one-hop graph expansion in parallel, merges the results with Reciprocal Rank Fusion, optionally reranks with a cross-encoder if one is configured, and packs the top hits into a markdown brief sized to your token budget. The brief only ever includes what’s relevant to the query — not the full accumulated history — which is what keeps token usage bounded as your knowledge base grows.
Multi-tenant isolation
Capsules are scoped to a tenant, and optionally a project within that tenant. Isolation is enforced at the storage layer, not just in application logic: each tenant gets its own Postgres schema, so a query in one tenant’s scope cannot surface another tenant’s capsules even under a bug in a shared query path.