# The Log is the Agent

Yohei Nakajima's paper on ActiveGraph (arXiv 2605.21997, 21 May 2026), a runtime that reverses how agent frameworks are normally assembled. The usual build order is accretive: start with a chat loop because conversation is the interface the model was trained for, add tools when it needs to act, add rules when behavior drifts, add logging because production demands it, and store some compressed form of the interaction so the agent can "remember." In that arrangement the log is exhaust — an audit artifact written alongside the real computation.

ActiveGraph makes the log the computation. The append-only event stream is the source of truth, the working graph is a deterministic fold over it, and behaviors react to graph changes and emit new events. The paper is explicit about being a systems contribution: it makes no claim that any of this improves task accuracy, and reports no benchmark against any baseline. The runtime is Apache-2.0 and installable — see [[activegraph]] for the software side.

## The substrate

Everything an agent's state consists of becomes one kind of thing. The objective, the rules it operates under (including changes to those rules mid-run), the tools available, each call and its response, the reasoning trace, and every artifact produced are all events in one ordered log. Conventionally these live in six different places: a prompt, a system message, framework internals, a transcript, a database, and a lossy similarity-queried memory store. Collapsing them turns three otherwise awkward questions into ordinary queries — why is this fact in the working set, what did the agent believe before rule R changed, and what would have happened had it branched differently at step 42.

An event carries an id, a type, a payload, the actor that produced it, an optional `caused_by` pointer to the event that triggered it, and a timestamp. Graph state, meaning typed objects and relations, is never mutated by external code; it is recomputed by folding events forward. Every object carries a provenance block naming the behavior that created it and the event that caused it, so nothing exists without a traceable origin. Loading a run, forking it, and validating it all invoke that same replay operation.

A behavior is a reaction, not a step. It declares a subscription — an event type plus an optional predicate and a graph-shape pattern written in a Cypher subset — and a body. Bodies come in four forms: a plain function, a class for behaviors carrying configuration, an LLM-backed routine whose request and response are themselves logged events, and a *relation-behavior*, which is logic attached to a typed edge so that the act of relating two objects carries computation.

## Why a graph and not just a log

The paper defends the graph separately, which is the part most likely to be skipped and shouldn't be. Event sourcing alone gives a log and a flat projection of current values. Three things need topology. Subscriptions are shape patterns, so a behavior can fire on "a claim that addresses an unanswered question," a predicate a flat event stream cannot express unless the consumer rebuilds the graph itself. Relation-behaviors need typed edges to be first-class, and a key-value projection has nowhere to hang them. And the structural diff between two runs is a diff over topology — which objects, relations, and patches differ — which is only well-defined because the projection is a graph rather than an opaque blob. The log is what makes state reproducible; the graph is what makes reactivity and comparison expressible.

There is no orchestration script. Control flow is whatever falls out of which events match which subscriptions: a planner reacts to a goal by creating a company, a question-generator reacts to the company, a researcher reacts to each question. The paper does not oversell this. Coordination has not vanished, it has moved from an explicit control-flow script into implicit, data-driven coordination through the shared graph, and the argued payoff is that every coordinating decision is now itself an event rather than a position in some external program counter.

## The determinism contract

A fold over a log is only sound if behavior bodies are deterministic functions of their inputs, so the runtime imposes a contract. A body must not read randomness, wall-clock time, or fresh UUIDs directly — it takes the timestamp from the event and ids from the runtime's deterministic generator. It must not perform I/O outside the framework's tool and model primitives. It must not depend on mutable global state that changes between fires.

The contract is not statically enforced. A violating behavior runs correctly the first time and is caught later, at replay or fork, as a divergence error pinned to the first event that fails to reproduce.

The exception is the case that matters. A model call is not a deterministic function of its inputs, so an LLM-backed behavior does not satisfy the contract at first execution, and the framework does not ask it to. The call goes out live and the response is recorded as an event; the contract applies to *replay*, where that recorded response is served from cache. The sentence worth keeping is that determinism here is a property of re-projecting a log that already exists, never a claim that running the agent is reproducible. That is the honest version of a guarantee usually overstated, and it is how the design survives the variance described in [[llm-output-variance]] — the runtime does not try to reproduce model outputs, it refuses to ask for them twice.

The cache is content-addressed. A model response is keyed on a hash of the entire request: system message, user messages, model identifier, tool definitions, and output schema. A tool response is keyed on the tool name and a deterministic hash of its arguments. On replay, a re-firing behavior whose request hash matches gets the recorded `llm.responded` or `tool.responded` payload and no new call goes out. The cost is disk, bounded by the size of the run. The sample `llm.requested` event in the paper pins temperature to 0.0 and `top_p` to 1.0, carries the prompt hash and a `cache_hit` flag, and records an estimated cost in dollars.

Replay runs in two modes. Permissive is the default when loading a run: the cache serves any request whose hash matches, and behaviors whose hashes no longer match, because someone edited a prompt, get fresh calls that land as new events. Strict mode re-fires behaviors and compares the live event stream against the recorded one event by event, raising a divergence error pinned to the first difference. A green strict replay is a proof that the run is reproducible, and it is also how the unenforced contract gets policed: a behavior that reads the wall clock passes permissive replay and fails strict, naming the offending event.

## Forking

A fork branches a run at a chosen event by copying the parent's events up to and including the cutoff, then proceeding on its own log. The prefix is not recomputed by re-running behaviors. It is replayed against the fork's in-memory graph with every model and tool response served from cache, and live execution resumes only at the cutoff. Forking a 200-step run to change one setting at step 150 pays for steps 150 onward and gets the first 149, model calls included, for free. Most agent frameworks cannot fork at all because their state is not reconstructable, and those that can generally re-run the prefix and pay for it again.

The lineage is verifiable rather than asserted: the fork's events 1 through k *are* the parent's events 1 through k, same ids, checkable by reading both logs. After the cutoff the fork gets its own monotonic id space so ids don't collide, and a structural diff then reports exactly which objects, relations, and patches differ as a consequence of the change at the fork point.

A lighter in-run primitive, the *frame*, handles parallel sub-contexts that reconverge inside a single run and share its log. The decision rule is durability — fork if branches might diverge permanently or need independent persistence and diffing, frame if they are short-lived and reconverge. The suggested pattern is to explore in frames and fork only the branches worth keeping.

## The worked example

The runtime ships a diligence *pack*: a bundle of object types, behaviors, tools, prompts, and policies for one domain. From a company name it generates research questions, researches each against a document store, extracts claims with supporting evidence, detects contradictions, identifies risks, and writes a memo. It ships with recorded fixtures, so `activegraph quickstart` runs offline with no API key in under thirty seconds and produces byte-identical logs across runs.

The reported figures: 671 events, 93 objects (3 companies, 24 questions, 9 documents, 25 claims, 25 evidence items, 1 contradiction, 3 risks, 3 memos), 76 relations, from 103 model calls and 48 tool calls, with no orchestration code anywhere.

The memo is not the point. A claim object like "Northwind Q3 revenue grew 28% YoY to $42M" carries provenance naming the behavior that created it (`document_researcher`), the event that caused it, and the specific model request event that produced it, and it is joined by typed relations to the question it *addresses*, the document it is *derived_from*, and the evidence that *supports* it. For diligence, compliance, or scientific work, that recoverable chain from goal to output is the deliverable.

## Self-improvement, stated as an affordance only

Section 7 is carefully fenced: the architecture removes specific obstacles to self-improvement, and the paper neither presents nor measures a self-improving agent. The obstacle it removes is that self-modification on a conventional runtime is invisible and irreversible, whereas here a rule change is an event, so a run can be replayed as it was before the change and a strict replay shows exactly how behavior diverged after it. The stronger affordance is fork-and-diff as an evaluation primitive: propose a change, fork at the point of proposal, apply it in the fork, run forward, and structurally diff against the parent. Because the shared prefix comes from cache, each candidate improvement is evaluated without re-paying for the history preceding it.

## Related work, and the blackboard argument

The memory-systems section answers the cluster this vault already tracks. MemGPT/Letta pages context in and out of a fixed window in the style of virtual memory. Zep's Graphiti maintains a temporal knowledge graph. Mem0 targets production extraction and retrieval. Hindsight comes closest to ActiveGraph's stance, arguing for memory as a "first-class substrate" with observation separated from inference and an auditable update process, but it remains a memory *layer* feeding an otherwise stateless model. The shared premise Nakajima objects to is that memory is derived state layered onto an agent whose primary representation lives somewhere else, which leaves provenance partial at best. He notes that his own earlier graph-memory research is what motivated the inversion: layered memory architectures kept running into the absence of a single authoritative history to project from. [[agent-memory-anatomy]] covers Mem0, Graphiti, and Letta from the vocabulary angle, and [[agent-memory-components]] is the extractor/store/retriever frame those systems share.

The best section is on blackboard architectures. Nii's 1970s and 80s systems organized problem solving around a shared knowledge structure that independent knowledge sources read from and wrote back to, with no direct calls between them, which is structurally what behaviors reacting to a shared graph are. Two era-specific problems killed the model: the knowledge sources were brittle hand-built expert-system components, and the control logic deciding which source acted next had to be authored by hand. LLMs dissolve both, since a behavior can be a general model-backed routine and the coordinating logic can be written in natural language or generated. Nakajima goes further and suggests the blackboard's react-and-write-back model may suit LLMs better than the conversational loop they are usually wrapped in, calling ActiveGraph less a new idea than a vindication of an old one, with the substrate the original never had. The same shared-data-store pattern appears in [[behavior-tree]], where a blackboard decouples condition nodes from the actions that wrote the values they read.

The BabyAGI lineage is stated plainly. BabyAGI kept state in a global list mutated by a loop; ActiveGraph makes state a projection of an append-only log mutated only through events, preserving the task-generating, self-extending character while making each step durable.

## Limitations the paper names itself

Because behaviors emit events that trigger behaviors, a run can diverge or loop. The only defense is a per-run budget capping events, behavior calls, model calls, patches, recursion depth, wall-clock time, and cost, and the paper calls this a blunt instrument rather than a static guarantee of termination. Replay cost grows with log length and there is no checkpointing or compaction yet — a million-event run is replayed in full today. Schema evolution has migration tooling but stays an operational burden. External tools with side effects are replay-safe only in the sense that the *record* of the mutation replays; the world still got mutated on first execution. Concurrency is the largest open question: ordering is well-defined within one run's append-only log, and concurrent writers or multi-agent contention over a shared graph are explicitly unresolved.

The determinism contract also puts a real burden on behavior authors while surfacing violations at replay rather than at write time, recording responses consumes store space proportional to run size, and a fork that edits a prompt has to re-execute the affected calls.

## Where it sits in the vault

The most useful contrast is with [[memorizing-session-transcripts]], which argues that keeping and searching the record of what an agent did produces worse outcomes than distilling it into artifacts. These are less opposed than they first look. theahura's target is transcript text behind a similarity index, and his mechanism is that agents re-read scratch-pad reasoning they correctly discarded. ActiveGraph never puts the log in front of the model as retrieval — the model sees the graph projection, and the log exists for replay, forking, and lineage. His other complaint, that agents cannot remove context and treat every token as intent, is orthogonal to this design and arguably answered by it: a typed causal graph with provenance on every object is the structure that makes "who asserted this, caused by what, on which evidence" answerable, which is the check he says is missing.

[[agent-memory-anatomy]] already argues that agents should not imitate biological forgetting, because disk is cheap and keeping everything enables auditability. That is the same position from the memory side, and it sits in the same unresolved tension with [[agent-memory-decay]] that this paper implicitly takes a side in. [[memory-conflict-detection]] is the narrower version of what the diligence pack does with a contradiction-detecting behavior.

Cheap branching that reuses a shared prefix is the same economics [[oak]] pursues in version control, from the other end: Oak makes branching a working tree cheap, ActiveGraph makes branching a *run* cheap. [[agent-identity-attribution]] gets attribution from a related structure, an append-only signed event trail, and would compose with this. The reactive half of the design, where derived state recomputes when its inputs change, is the principle behind [[reactive-signals]] applied to a much larger object.
