CLI tool
yoheinakajima/activegraph avatar
yoheinakajima/activegraph

Active Graph: an event-sourced runtime where the trace is the audit trail

Event-sourced graph runtime for durable and stateful agents

644 stars58 forksPythonApache-2.0

At a glance

What is it?
Active Graph is a Python runtime that replaces conversational agent loops with a shared, append-only graph of events. It is aimed at teams that need resumable, forkable runs and a defensible record of what an agent did, but the pack format and the event log are the parts you have to accept before anything else works.
Who is it for?
Adopt Active Graph if your agents run long enough that losing the process is a real cost, or if you need to branch a run, change one input, and compare the two traces structurally. Do not adopt it if you want a thin wrapper over a chat completion call, or if your team will not maintain a pack of object types and behaviors.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 17 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The failure mode Active Graph is built around

Most agent code is a loop that holds state in variables and a message list. When the process dies, the state is gone. When the answer is wrong, the only artifact left is a transcript, and a transcript does not tell you which step changed the world. Active Graph targets that gap. The README frames it as an event-sourced reactive graph runtime for long-running, auditable agentic systems, and the tagline is blunt about the priority: the graph is the world, behaviors are physics, the trace is the proof. The intended reader is someone building an agent that runs for hours or days, touches shared data, and has to be explainable afterwards. The README contrasts this with chat-based agents directly, describing them as a group conversation and Active Graph as a shared workspace where everyone can see what changed, who changed it, and why. That comparison is the whole positioning. If your agent answers one question and exits, the event log is overhead you will pay for and never read.

Objects, typed relations, and behaviors that subscribe instead of call

The runtime holds objects and typed relations, and every mutation to that graph is appended as an event. Behaviors do not call each other. They subscribe to the graph, and the README lists the subscription surface as event type plus predicate plus a Cypher subset for graph-shape patterns. So a behavior can fire because a particular relation appeared between two object types, not because some upstream function decided to invoke it. Behaviors come in four shapes according to the README: function, class, LLM-backed, and edge-attached. The edge-attached case is called the relation-behavior primitive, described as edges with logic. That is the design choice worth pausing on. Logic living on a relation means the rule is scoped to a pair of objects rather than to a global handler, which keeps the world model and the reaction model in the same place. It also means your behavior graph and your data graph are the same artifact, so a change to one is a change to the other. The README states there are twelve primitives in total and links each to a concept page on the documentation site, so the repository itself is not the full specification.

Fork-and-diff, and why cache replay matters more than the branch

The README calls fork-and-diff the framework's most differentiated capability and says most agent frameworks cannot do it. The mechanism: branch any run at any event into an independent fork, configure the fork differently, and structurally diff the result against the parent. The part that makes this affordable is cache replay. Because the shared prefix of the two runs is already in the event log, that prefix does not re-execute, and the README states explicitly that this means no new LLM calls for the shared portion. Without that, forking a long run would mean paying again for every step you did not change, and the feature would be unusable in practice. Two caveats follow from the same design. First, the diff is structural, so the comparison is over graph state and events, not over prose. Second, a fork is only as reproducible as the behaviors in it. An LLM-backed behavior that is not pinned to a recorded fixture or a fixed provider configuration can diverge in the forked region for reasons the event log will not explain.

Install, quickstart, and the extras that decide your deployment

The core install is one command: pip install activegraph. The README says that pulls the core runtime, a SQLite store, and the bundled Diligence pack. The fastest way to see the framework is activegraph quickstart, which runs the Diligence pack against recorded fixtures with no API key and no configuration, and the README describes the output as byte-deterministic. A longer path is activegraph quickstart --interactive, which the README says scaffolds a behavior, runs it against the same fixtures, and ends with the fork-and-diff workflow. Everything beyond the core is an extra: activegraph[llm] for the Anthropic and OpenAI providers, activegraph[anthropic] or activegraph[openai] for one at a time, activegraph[postgres] for a Postgres-backed event store, and activegraph[prometheus] or activegraph[opentelemetry] for metrics. There is an activegraph[all]. The README states both LLM providers expose the same LLMProvider Protocol surface, so swapping one for the other does not require editing @llm_behavior definitions. Python 3.11 or newer is required, and the README names only two hard dependencies, click for the CLI and pydantic for the pack format. That dependency list is unusually small for this category, and it is a deliberate choice: persistence backends and provider integrations are opt-in.

Packs are the unit of adoption, and that is the real cost

A pack bundles object types, behaviors, tools, prompts, and policies for one domain. The bundled Diligence pack is the reference implementation, and the README gives its exact shape: eight object types, seven behaviors, three tools, and recorded fixtures. A separate repository, activegraph-packs, is described as the open pack library with roughly twenty packs, demo bundles, a demo server, and a React Inspector UI. This is where the framework stops being a library and becomes a schema commitment. Before any behavior runs, you have to decide what your objects are, which relations are typed, and which policies apply. The quickstart hides that work behind someone else's domain model. The learn.activegraph.ai tutorials are described as refactoring a familiar agent loop onto the runtime one substitution at a time, which is the honest framing: the migration is incremental, but it is a migration. Teams that cannot name their domain objects in advance will find the pack format fighting them.

Bounded drains, isolated export, and the single-writer constraint

The README documents two operational mechanisms that matter once a run is long. The first is cooperative bounded drains. A single-writer host can keep reads responsive during large derived-work drains by calling Runtime.run_quantum(max_queue_events=25, max_seconds=0.25). The README states that a yielded quantum never writes a false runtime.idle, and that repeated quanta are byte-identical to one run_until_idle() under the same deterministic inputs, citing CONTRACT v1.10 #3. That equivalence claim is the interesting one, because it means you can break work into slices without changing the resulting log. The second is EventSink, which streams accepted live events through a bounded per-sink worker so adapter I/O stays off the runtime hot path. JSONLEventSink is the first-party adapter. The README says drops, queue depth, and failures are explicit in status and metrics, and that normal replay never redelivers history. Read those two together and the constraint is visible: the runtime assumes a single writer, and the escape hatch for throughput is a bounded queue with observable drop behavior, not concurrent mutation. If your workload needs parallel writers to the same graph, this is the wrong tool.

Errors with reference pages, and the maintenance arithmetic

Every error message ends with a More: link to a page explaining when it fires, why, and how to fix it, with a catalog at docs.activegraph.ai/reference/errors. For a runtime whose failures often surface as a malformed event or an unsatisfied subscription predicate, that is more useful than a stack trace alone. On maintenance, the release history in the supplied material shows v1.7.1 on 2026-07-09, v1.9.0 on 2026-07-10, and v1.10.0 on 2026-07-21, with the default branch pushed on 2026-08-30. That is a fast cadence, and the README's own citation of a versioned contract clause for the drain guarantee tells you the maintainers version behavior, not just artifacts. Plan for upgrades that occasionally change documented semantics. The licence is Apache-2.0, which permits commercial use and modification and includes a patent grant; it also requires that you preserve notices and state significant changes. That is a summary of the licence text, not legal advice, and the arXiv preprint cited in the README is a separate work with its own terms. If you fork the runtime, the Apache-2.0 notice obligations travel with your fork, and the pack you write on top is your own to license.

What to compare against, and where the boundary sits

The obvious alternative is a durable execution engine such as Temporal, which also persists a workflow's history and can replay it after a crash. The difference in approach is what gets recorded and what reacts. A durable execution engine persists the steps of a workflow you wrote as code, and the unit of resumption is the function call. Active Graph persists mutations to a graph of objects and typed relations, and the unit of reaction is a subscription over that graph. That means a behavior can be added to a running system without editing the code path that produces the event, which a workflow engine cannot do, because its control flow is explicit. The cost is the inverse: in Active Graph you cannot read the control flow off a single file, because the flow is distributed across subscriptions and predicates. If your team's debugging instinct is to open the orchestrator and read top to bottom, Temporal's model will feel more direct, and Active Graph will feel like the logic is scattered. That is a real trade, not a maturity gap. The README's own framing, that the trace is the proof, tells you which side of it the project has chosen.

Editorial conclusion

Adopt Active Graph if your agents run long enough that losing the process is a real cost, or if you need to branch a run, change one input, and compare the two traces structurally. Do not adopt it if you want a thin wrapper over a chat completion call, or if your team will not maintain a pack of object types and behaviors. Verify first that the bundled Diligence pack's eight object types map onto your domain, that your event volume fits the SQLite store or justifies the postgres extra, and that the fork-and-diff output is something your reviewers will actually read.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. yoheinakajima/activegraph on GitHub
Community notes

Community notes