tracks01 / 04 aifor agents

give your agents a live world.

Rindle is the data engine that streams cache-coherent semantic diffs to agents — and lets them branch reality before committing to it. A standing query is a world model: named, live, exact, and cheap to watch. Your agent stops re-reading the world and starts reading what changed.

01 · semantic diffs

one view narrates the whole document.

A Rindle view isn't a table dump — it's a named query, and a named query is a tree. Its delta stream narrates at every level of that tree in your domain's own words: the deck retitled at the root, a slide reworded under slides, a chart added under components — all off the one view your UI already renders. The @rindle/narrator layer renders those into salience-tagged events (alert / info / ambient), per view and netted, so a correctly predicted optimistic write settles to no noise at all.

// one registry per query: `root` for the entity, `related` by relationshipconst NARRATORS: NarratorRegistry = { deck: { salience: "info", root: { edit: ({ row, old }) => `Renamed the deck to "${row.name}".` }, related: { slides: { edit: ({ row }) => `Reworded slide "${row.title}".` }, components: { salience: "ambient", add: ({ row, parent }) => `Added a ${row.kind} to "${parent?.title}".` }, }, },};

The engine emits the diffs; the narrator names each row against its level's wire schema, matches your small per-level templates — the digest above is exactly what the registry beside it produces — and folds a batch into one prompt-ready block. One subscription, the whole document, in domain language — not a re-serialized snapshot.

02 · prefix cache coherence

context that appends, never rebuilds.

An agent's context over a view is hydrate once, then deltas — ordered, minimal, append-only. The prompt prefix never changes, so provider prefix caches stay hot turn after turn. Re-fetching state and re-rendering it into the prompt busts the cache on every turn; appending a semantic diff doesn't.

re-fetch the world each turn

  • Re-query, re-serialize, re-insert the state block.
  • The prefix shifts → prefix cache busted every turn.
  • The model re-reads O(world) tokens to find the change.
  • "What's different from last turn?" is the agent's problem.

subscribe to a view

  • Hydrate once; every turn appends the view's digest.
  • Stable prefix → prefix cache hot, turn after turn.
  • The model reads O(change) tokens, already named.
  • "What changed" arrives answered — named, netted, ready to append.

03 · coordination

a fleet that sleeps until it matters.

Agents coordinate the way your UI components do: each one subscribes to the views it is responsible for. The engine computes deltas per query, so an agent is woken only when relevant information changes — not on every write to the database, and never by a polling loop.

04 · speculative planning

branch reality. commit or snap back.

Predicted mutators are speculative branches: an agent applies a plan locally, every affected view updates, and it reads the world that plan would create — before anything is committed. Server confirmation rebases the branch onto authoritative state; rejection snaps it back, with no hand-written rollback. Under the hood the store is a copy-on-write tree, so forking state is O(1).

// branch: the plan applies locally, immediatelymutate.assignCourier({ order: 812, courier: "c-42" }); // read the world the plan creates — every view is already updatedconst load = store.query.courier.where.id("c-42").sub("stops", rels.courierStops).materialize(); // commit → the engine rebases it onto authoritative state// reject → it snaps back; no rollback code exists to get wrong

Plan → simulate → observe → commit, on the same engine that maintains production state. Deterministic mutators re-run against whatever the authority confirms, so read-dependent plans recompute correctly instead of drifting. This is the ui track's optimistic-write machinery, pointed at plans instead of pixels — one engine, two audiences.

05 · ship it

your docs path: build a synced app.

An agent is another subscriber — the stack it plugs into is the same synced-app stack the docs walk end to end: the rindled daemon holding the live queries, a stateless authority resolving named queries and running mutators, a client store on top. The narrator is one small layer over a view's change stream:

// the agent loop: bind one view; each commit appends a netted digestconst narrator = createNarrator(NARRATORS);store.materialize(unseatedGuests({ eventId }), { onChanges: (changes, phase, schema) => { const events = narrator.narrate("unseatedGuests", schema, changes, phase, ctx); if (events.length) agentContext.append(narrator.digest(events)); // salience-ranked },}); // React: `useNarration(query, NARRATORS)` wires this for you