ActiveGraph

title
ActiveGraph
type
toolbox
summary
Event-sourced Python agent runtime where the graph is a replayable fold over an append-only log
tags
python, ai-agents, event-sourcing, architecture, watchlist
language
Python
license
Apache-2.0
created
2026-07-23
updated
2026-07-23

The runtime behind Nakajima's paper log-is-the-agent, released under Apache-2.0. You write behaviors that subscribe to patterns over a typed graph; the runtime folds an append-only event log into that graph, fires matching behaviors, and records everything they do β€” including every model request and response β€” back into the log. What you get in exchange for giving up an orchestration script is replay, forking, and provenance on every object.

pip install activegraph
activegraph quickstart

The quickstart runs the bundled investment-diligence pack against recorded fixtures: three companies, no API key, offline, under thirty seconds, byte-identical logs on repeat runs. It reportedly produces 671 events, 93 objects, and 76 relations from 103 model calls and 48 tool calls without any orchestration code. The examples/ directory holds smaller demos that exercise different parts of the runtime β€” live-API runs, a fork walkthrough, single-behavior claim extraction.

The pieces you actually write

A pack is the unit of domain packaging: object types, behaviors, tools, prompts, and policies bundled together. The shipped diligence pack declares types like company, document, question, and claim, and behaviors like diligence.company_planner and diligence.question_generator.

A behavior is a subscription plus a body. The subscription is an event type with an optional predicate and a graph-shape pattern in a Cypher subset, which is what lets a behavior fire on a topological condition such as "a claim that addresses an unanswered question" rather than only on an event type. Bodies come in four shapes: a plain function, a class when the behavior needs configuration, an LLM-backed routine whose request and response become logged events, and a relation-behavior attached to a typed edge, so relating two objects can carry computation of its own.

Everything the runtime does is visible as JSON in the log. An object-creation event carries the provenance inline:

{
  "id": "evt_004",
  "type": "object.created",
  "actor": "diligence.company_planner",
  "caused_by": "evt_002",
  "payload": {
    "object": {
      "id": "company#1",
      "type": "company",
      "provenance": {
        "created_by": "diligence.company_planner",
        "caused_by_event": "evt_002"
      }
    }
  }
}

What you have to obey

Behavior bodies must not read randomness, wall-clock time, or fresh UUIDs directly, must not do I/O outside the framework's tool and model primitives, and must not depend on mutable global state that changes between fires. Timestamps come from the triggering event and ids from the runtime's deterministic generator.

None of this is checked at write time. A violating behavior works fine on the first run and blows up later during a strict replay, as a divergence error pinned to the first event that failed to reproduce. Permissive replay, the default when loading a run, will not catch it. Budget for the debugging session where a behavior that quietly called datetime.now() six months ago is what makes a fork refuse to reproduce.

Model nondeterminism is handled by recording rather than by pretending. Responses go into a content-addressed cache keyed on a hash of the whole request β€” system message, user messages, model id, tool definitions, output schema β€” so a replay or a fork serves them from the log instead of calling out again. Edit a prompt and its hash stops matching, so those calls re-execute and get billed.

Limits

No checkpointing or compaction exists yet, and replay cost grows linearly with log length: a million-event run is replayed in full today. Store space is proportional to run size, because the point is that nothing gets thrown away. Schema evolution after events with the old shape are already on disk has migration tooling but stays an operational chore. Tools with real-world side effects are only replay-safe in the sense that the record replays β€” the first execution still sent the email. Concurrent or distributed writers, and multiple agents contending over one graph, are explicitly unresolved; ordering is only well-defined inside a single run's log. Runaway behavior cascades are bounded by a per-run budget over events, behavior calls, model calls, patches, recursion depth, wall-clock time, and cost, which the paper itself calls blunt rather than a termination guarantee.

Tracked on watchlist: a single-author research project published alongside its paper, with compaction, concurrency, and any measured task-performance result all listed as future work.

log-is-the-agent is the argument and the architecture in full. The systems it positions against are the ones in agent-memory-anatomy and agent-memory-components β€” Mem0, Graphiti/Zep, Letta β€” with the difference being that those treat memory as derived state layered onto an agent whose real representation lives elsewhere. behavior-tree shares the blackboard coordination pattern at a much smaller scale. For the agent-memory products in this vault built the way ActiveGraph argues against, see agentmemory, hippo-memory, stash, and mempalace; for the empirical case that none of it helps on coding work, memorizing-session-transcripts.

Repo: yoheinakajima/activegraph, Apache-2.0, docs at docs.activegraph.ai. Star count not recorded at ingest.