Concept · 1 of 7

Scroll

A scroll is an append-only, ordered event log. It is the substrate every other weave primitive runs on. If you understand scrolls, you understand 80% of weave.

The event log, included

A scroll is a durable, append-only, ordered event log. Everything the runtime records — tool dispatches, model responses, workflow transitions — lands here.

The operational shape of that decision: you don't deploy a separate event store alongside weave. The server is the event store. One binary, one dependency, one thing to reason about. Running weave doesn't mean standing up Postgres, Redis, and Kafka before you write your first agent.

Scale you won't think about for a while

The scroll server today handles roughly 25,000 events per second per node with strong per-scroll ordering guarantees and durable commits. Because scrolls are narrow — one per run, not one per cluster — throughput bottlenecks sit at the node level, not at a hot topic. A single deployment covers most teams well into production.

When the day comes that you want partitioned consumer groups, cross-region replication, or cheap cold retention, the scroll API is backend-agnostic by design. Postgres, Kafka, or an object-store hybrid can slot in under the same surface. That's a migration, not a rewrite.

Bring your own storage

The scroll contract is thin — append, read, subscribe — so any ordered log can satisfy it. Five backends are officially supported, covering the spectrum from throwaway test to durable production:

In Memory

implemented

Zero dependencies. Fast. Loses state on restart — the right default for tests and scratch scripts.

File System (JSONL)

designed

One line of JSON per event, appended to disk. Durable, inspectable with standard tools, no external process.

SQLite

implemented

Embedded, single-file durability with proper indexes. The default for single-node weave deployments.

Postgres

designed

Multi-node durability and query-able scroll history. Reuses the database you probably already operate.

MongoDB

implemented

Document-native storage for JSON payloads. Good fit when you want to query scrolls as a collection.

Start simple. In Memory covers tests and scratch work; SQLite is the default for single-node production. Reach for MongoDB when you want scrolls as a queryable collection alongside your application's own document data. Postgres and JSONL are on the roadmap.

Anatomy

A scroll is identified by a name (usually a run id). Each entry is an event — a topic, a payload, and an offset assigned at commit time. Ordering is total within a scroll; cross-scroll ordering is not a concept.

scroll: run-abc123
──────────────────
[0]  ai.request      { prompt: "greet the hero" }
[1]  ai.response     { text: "welcome, traveller" }
[2]  tool.dispatch   { name: "speak", args: { text: "welcome, …" } }
[3]  tool.result     { ok: true, duration_ms: 42 }

Four events, one scroll. ai.response and tool.result are external commits — facts the runtime couldn't reproduce without asking the model or calling the handler. The others are derived — recomputable from prior events plus the workflow definition. This split is what makes replay work.

Scope — one scroll per what?

A scroll is scoped to a run. Today that means one scroll per ai.Ask call; when workflows ship, it means one scroll per workflow instance. Keep the scope tight: a scroll's guarantees (ordering, immutability, verifiability) are per-scroll, so scroll boundaries should line up with the unit of work you want to reason about as a whole.

Cross-run coordination happens by subscribing to other scrolls, not by merging them into one firehose. The substrate gives you small, focused logs — not a global event bus.

What you do with it

Most of the time the runtime writes to the scroll on your behalf. When you need direct access, the API is small:

// Appending an event — usually the runtime does this for you.
w.Scroll().Append(ctx, scroll.Event{
    Topic:   "tool.result",
    Payload: result,
})
// Subscribing — live tail plus historical replay from offset 0.
events, err := w.Scroll().Subscribe(ctx, scroll.FromStart)
for e := range events {
    fmt.Printf("[%d] %s  %s\n", e.Offset, e.Topic, e.Payload)
}

Subscribe is both history and tail — pass FromStart and you get every event in order from offset zero through whatever gets appended next, with no separation between "past" and "live."

Status

Scrolls are the most mature primitive in weave — the core guarantees (append, read, subscribe) are real today. Group semantics and cryptographic verifiability are in various stages of design or shim. Here's an honest map:

Append
implemented
Writers — including the runtime itself — can append events. Offsets are assigned monotonically on commit.
Read by offset
implemented
Random access from any offset. Reads are cheap and deterministic.
Subscribe (live tail)
implemented
A single consumer can tail a scroll from any offset through the live head. Ordering is preserved.
Consumer groups
sdk-shimmed
The SDK exposes group semantics (shared cursor, exclusive delivery) but the underlying store is still a single-consumer subscribe. Partitioned delivery lands with the distributed scroll server.
Replay with overrides
sdk-shimmed
Works today for single-call flows: feed a recorded ai.response back in and the runtime skips the network call. Multi-step workflow replay lands with the workflow runner.
Verifiability (hash chain)
designed
Each event hash-chains to its predecessor; mark a scroll verifiable and any edit becomes detectable. The spec is set; the implementation is next milestone.
Retention & compaction
designed
Scrolls live forever by default. Retention policy and cold-storage compaction are on the roadmap but not in the SDK surface yet.

Not to be confused with

  • Kafka. Kafka is a distributed log aimed at throughput across many partitions and many services. A scroll is narrow and scoped — think one log per agent run, not one log per cluster. Scrolls are optimized for reasoning, not volume.
  • A blockchain. Tamper-evidence comes from hash-chaining within a single scroll, not distributed consensus. No miners, no global ledger.
  • A tracing span tree. Traces are derived views reconstructed after the fact. A scroll is the source of truth itself — you can rebuild traces from it, but not the other way around.