Projections & the catalog
Everything you read from teaspill — timelines, the entity registry — is a projection: a one-way copy flowing out of the agents to the places you read from. This page explains the read side, and the catalog in particular.
Write side, read side
Agents do their work inside their own handlers, against their own durable state. Everything readable — the timeline stream, the catalog rows — is copied outward from there, and nothing is ever read back in to make a decision. The arrow points one way.
This is why readers can never hurt writers: a dashboard polling a thousand catalog rows, a browser replaying a year-old timeline — none of it touches a running agent. It also means what you read is a consequence of what agents did, never an input to it.
Exactly-once, in one sentence
Every event an agent produces lands in its timeline exactly once, in order, even across crashes and retries on either side. The mechanism that guarantees this is called the outbox — you'll only care about the name if you work on teaspill itself.
Events are staged inside the agent's own transaction, numbered by the single writer, then flushed to the history store through an idempotent producer keyed on (entityId, seq). A crash between flush and confirmation replays the flush; the store recognizes the already-appended numbers and treats them as no-ops. The same flush updates the catalog row's head_seq, so the registry's "how far along is this entity" answer tracks the timeline it summarizes.
The catalog
The catalog is the Postgres registry of every entity — type, status, parent, tags — that your UI subscribes to as live-updating queries. One row per entity, keyed by its entity URL, carrying its current status (active, idle, or archived), its parent's URL if it has one, its tags, and head_seq — the number of the last event confirmed onto its timeline.
The catalog syncs to browsers through Electric, an open-source Postgres sync engine: a client subscribes to a filtered view — all entities of a type, the children of a parent, everything with a given status — and receives changes live, without polling. A dashboard of running agents is a catalog subscription and nothing more.
What to build on what
Three reads-and-writes cover every UI:
| You want | Build on |
|---|---|
| Lists, dashboards, org charts of agents | The catalog — subscribe to filtered rows |
| Conversation detail, activity feeds | The timeline — replay + live-follow one entity |
| Buttons that do things (spawn, send, control) | The gateway API — commands go through your backend |
Lists come from the catalog; depth comes from timelines; writes go through the gateway. Mixing these up — say, building a list by scanning timelines — works, but fights the grain: the catalog already maintains exactly that answer, live.
@teaspill/frontend-sdk. For how the pieces fit inside the platform, see the package map.Next steps
So far, agents think and talk. For agents that run commands and touch files, they need somewhere safe to do it: Workspaces & execution.