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
implementedZero dependencies. Fast. Loses state on restart — the right default for tests and scratch scripts.
File System (JSONL)
designedOne line of JSON per event, appended to disk. Durable, inspectable with standard tools, no external process.
SQLite
implementedEmbedded, single-file durability with proper indexes. The default for single-node weave deployments.
Postgres
designedMulti-node durability and query-able scroll history. Reuses the database you probably already operate.
MongoDB
implementedDocument-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:
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.