Observed since 20 Oct, 18:36 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
An event-sourced reactive graph runtime for long-running, auditable, agentic systems.
The graph is the world. Behaviors are physics. The trace is the proof.
An event-sourced reactive graph runtime for long-running, auditable, agentic systems. Behaviors react to a shared graph instead of talking to each other. Every change is traceable. Every run is resumable, forkable, and diff-able from its event log.
If chat-based agents are a group conversation, Active Graph is a shared workspace where everyone can see what changed, who changed it, and why.
🎥 New: Watch the AI Engineer talk — Active Graph introduced by its author in one sitting. The fastest way to get the mental model before you read further.
This repo is the runtime; the project is spread across a few sites, papers, and sibling repos. Whether you are a person evaluating the framework or an AI assistant gathering context, these are the canonical entry points:
| Resource | What it is |
|---|---|
| activegraph.ai | Project home — the pitch in one page |
| The AI Engineer talk | Video introduction from the author |
| docs.activegraph.ai | Full documentation: concepts, guides, cookbook, CLI + API reference, per-error catalog |
| learn.activegraph.ai | Interactive tutorials — refactor a familiar agent loop onto the runtime, one substitution at a time |
| Blog | Release write-ups and research notes from the project |
| "The Log is the Agent" (arXiv:2605.21997) | The paper — the design argument for event-sourced agents |
| "Regimes" (arXiv:2606.10241) | Follow-up research paper; code at yoheinakajima/regimes |
| activegraph-packs | Open pack library: ~20 packs, demo bundles, a demo server, a React Inspector UI |
| activegraph-lab | Self-hosted research agent running on the runtime in production |
| llms.txt · llms-full.txt | Machine-readable docs for AI coding assistants |
| Status · CHANGELOG.md | Where the project stands right now |
The ecosystem and research sections below say more about each.
pip install activegraph
activegraph quickstart
The bundled Diligence pack runs against recorded fixtures: no API key, no configuration, byte-deterministic output. You see what the framework does before you read about how it does it.
Then walk the 10-minute tutorial:
activegraph quickstart --interactive
It scaffolds a behavior, runs it against the same fixtures, and ends with the fork-and-diff workflow — the framework's most differentiated capability.
pip install activegraph # core runtime + SQLite store + Diligence pack
pip install "activegraph[llm]" # Anthropic + OpenAI providers
pip install "activegraph[anthropic]" # Anthropic provider only
pip install "activegraph[openai]" # OpenAI provider only (+ tiktoken)
pip install "activegraph[postgres]" # Postgres-backed event store
pip install "activegraph[prometheus]" # Prometheus metrics
pip install "activegraph[opentelemetry]" # OpenTelemetry metrics
pip install "activegraph[all]" # everything
Both LLM providers expose the same LLMProvider Protocol surface;
swap one for the other without touching @llm_behavior definitions.
The LLM providers reference
covers the side-by-side surface, including tool use and provider-specific
token counting.
Python 3.11+. Two hard dependencies (click for the CLI, pydantic
for the pack format); persistence backends and provider integrations
are opt-in extras.
EventSink streams accepted live events
through a bounded per-sink worker without putting adapter I/O on the
runtime hot path. JSONLEventSink is the first-party adapter; drops,
queue depth, and failures are explicit in status and metrics, and
normal replay never redelivers history.Runtime.run_quantum(max_queue_events=25, max_seconds=0.25). A
yielded quantum never writes a false runtime.idle; repeated quanta
are byte-identical to one run_until_idle() under the same
deterministic inputs (CONTRACT v1.10 #3).More: link to a page that explains when it fires, why, and how to
fix it. Catalog at docs.activegraph.ai/reference/errors.The framework's twelve primitives, in roughly the order you meet them when reading a trace. Each links to its concept page on the doc site; read those when you want depth on one piece.
NOT EXISTS
and temporal predicates. → concepts/patternsbehavior.failed
event, not an exception. The audit trail captures failures as
first-class history. Exceptions live at runtime entry points only.
→ concepts/failure-modelWhat's fixed and what's yours. The framework speaks a small vocabulary of event types — the verbs of what happened. The nouns and edges of your domain are strings you choose.
Event types — fixed. The runtime emits these; the trace, replay, and observability surfaces all key off them.
goal.created, runtime.idle, runtime.budget_exhaustedobject.created, object.removed, relation.created, relation.removedbehavior.scheduled, behavior.started, behavior.completed, behavior.failed, relation_behavior.startedpattern.matchedllm.requested, llm.respondedtool.requested, tool.respondedpatch.proposed, patch.applied, patch.rejectedapproval.proposed, approval.grantedpack.loadedBehaviors can also emit custom event types — any string. The
task.completed signal in the example below is one: an
application-level event the unblock relation behavior subscribes
to, flowing through the same log alongside the framework's own.
Object and relation types — yours. Any string works. There is no
central schema, no registration step, no enum to extend.
graph.add_object("claim", {...}) creates a claim because you said
claim; graph.add_relation(a, b, "depends_on") makes a
depends_on edge because you said depends_on. Packs can attach
optional Pydantic validation per type; absent a pack, the data passes
through unchanged. The Diligence pack's object types (claim,
evidence, risk, memo, …) and relation types (supports,
contradicts, references, …) are an example ontology, not framework
base types — you design your own for your domain.
Patch states — fixed. proposed → applied | rejected. Three
values, two of them terminal.
The full model — composition, ontology design guidance, the Diligence pack as a worked example — lives at → concepts/type-system.
The relation-behavior primitive — coordination logic on the edge, not on either endpoint:
from activegraph import Graph, Runtime, behavior, relation_behavior
graph = Graph()
runtime = Runtime(graph, budget={"max_events": 200, "max_seconds": 60})
@behavior(name="planner", on=["goal.created"])
def planner(event, graph, ctx):
research = graph.add_object("task", {"title": "Research", "status": "open"})
memo = graph.add_object("task", {"title": "Draft memo", "status": "blocked"})
graph.add_relation(research.id, memo.id, "depends_on")
@behavior(name="researcher", on=["object.created"], where={"object.type": "task"})
def researcher(event, graph, ctx):
task = event.payload["object"]
if task["data"]["status"] != "open" or "Research" not in task["data"]["title"]:
return
graph.add_object("claim", {"text": "Market early but growing.", "confidence": 0.7})
graph.emit("task.completed", {"task_id": task["id"]})
@relation_behavior(name="unblock", relation_type="depends_on", on=["task.completed"])
def unblock(relation, event, graph, ctx):
if event.payload["task_id"] == relation.source:
graph.patch_object(relation.target, {"status": "open"})
runtime.run_goal("Evaluate this startup idea")
runtime.print_trace()
The unblock relation behavior fires only for events touching one of
its edge endpoints. The conceptual deep-dive on edges-with-logic is
in docs/concepts/relations.md.
diligence_real_run.py,
resume_and_fork.py,
llm_claim_extraction.py,
diligence_with_tools.py,
operate_a_run.py,
babyagi.py — BabyAGI's autonomous agent loop,
rebuilt as three reactive behaviors over a shared graph.Active Graph is one repo in a small open-source constellation. The siblings are where the runtime gets exercised for real — and they are good additional context to hand an AI assistant alongside this repo.
GraphStore backend
(native edges, Cypher push-down), contributed by
@dudizimber. See the
FalkorDB guide
and FalkorDB's write-up.EventStore protocol; the
materialized graph lives behind the GraphStore protocol —
in-memory by default, or FalkorDB
for a real, traversable graph backend. For a different
high-throughput store, plug one in behind either protocol.v1.12.0 (2026-09). v1.0 shipped in May 2026 after a three-rc external user-test gate per CONTRACT v1.0 #C4; the v1.1–v1.12 line followed, driven by a downstream self-modification stack — the activegraph-packs library and a governed fork→test→promote assistant — and hardened against findings from production deployments built on the runtime. See CHANGELOG.md for the full v0 → v1.12 history and per-version migration notes.
Major shipped milestones:
ObjectQuery plan
(GraphStore.query_objects), existence checks avoid full
materialization, and optional FalkorDBGraphStore(indexed_fields=...)
scalar indexes stay explicit projection configuration. Ships together
with the staged v1.11 line below; there is no separate 1.11.0 release.
Upgrades from 1.10.0 also get that line's integrity changes
(ConcurrentWriterError, InvalidPatchOperation, detached events,
single-writer runs).Runtime(trace_context_reads=True) — each
behavior execution commits one batched context.read event
recording what it looked at), reserved-field collisions fail loud
with ReservedFieldError, and Runtime.run_quantum cooperative
bounded drains. Default-configuration runs stay byte-identical.EventSink delivery; runtime-owned embedding record/replay;
fail-closed direct web_fetch; deterministic wall-stop replay; and
the provider-neutral TrialExecutor seam with the existing local
subprocess as its honest, non-security-sandbox default; plus
explicit, log-backed dev.override receipts bounded below
governance authority.extra_packs for cross-pack interaction trials, the child's stderr
captured into the trial report, code discovery made an explicit
computed-PYTHONPATH channel (the env allow-list stays closed),
sandbox.preflight(), and portable resource limits — RLIMIT_AS
enforced on Linux, announced-off (not crashed) on macOS.load_pack (structured, once per pack, never an error before 2.0);
the fork-tail-removal promote invariant pinned as contract.run_forked_trial: a
fresh-interpreter child against a fork, artifacts pinned by bundle
hash) and compaction phase 1 (snapshot + archive tier + the
retention pin set, never deletion).load_manifest,
verify_surface, content + bundle hashes), declarative
Pack.capabilities, and disable_pack deregistration.promote: apply a fork's net structural delta back to
its parent, fail-closed on conflicts (the fork→test→promote loop);
provider-compatibility hardening; traceback/DX surfacing; the
EmbeddingProvider seam.GraphStore seam: the materialized projection
becomes pluggable, with FalkorDBGraphStore (native edges, Cypher
query push-down) as the first external backend, contributed by
@dudizimber; the test suite
becomes a CI gate.inspect --memo / inspect --search, fork --set, OpenAI
tool-shape parity, OpenTelemetryMetrics, and the
spec-vs-impl drift gates.activegraph quickstart command, mypy --strict and docstring
coverage CI gates, wheel-completeness and deploy-verification CI
gates.runtime.status(), full activegraph CLI,
PostgresEventStore.@tool decorator, Cypher-subset pattern subscriptions,
temporal predicates.@llm_behavior with structured output, frame-aware
prompt construction, cost accounting.ROADMAP.md preserves the v1.3-cycle plan as a dated artifact (that line has since shipped — see its header note); CHANGELOG.md is the authoritative record of what landed. Unscheduled candidates live in FUTURE_IDEAS.md.
Active Graph is licensed under the Apache License 2.0. See LICENSE for the full text and NOTICE for the attribution that downstream redistributors must preserve.
See CONTRIBUTING.md for the current contribution
policy and TRIAGE.md for the invariant-first path from a report to
a decision, milestone, and status: ready-for-pr. The framework is in its
early public phase: issues are open, documentation PRs are welcome, and
non-trivial code changes pass through the issue-first discussion gate.
Test discipline: tests must remain deterministic. No live network
calls in CI. LLM and tool tests use recorded fixtures
(RecordedLLMProvider, RecordedToolProvider). If a contribution
adds a test that would only pass with a live API key or live HTTP,
it cannot land.
The graph is the world. Behaviors are physics. The trace is the proof.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.12.0 | 26 Sept 2026 | 17 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-21 | 66 | 2026-10-21T12:10:21.1472519Z |
Observed since 20 Oct, 18:36 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:7fac0c347bb3f0270747e04321c2b5044577eb83346a79078f752e80e83ccd17