{"slug": "activegraph-v1-2-0-is-live-x30-speedup", "title": "ActiveGraph v1.2.0 is live – x30 speedup", "summary": "ActiveGraph v1.2.0 is now live, introducing a pluggable graph projection seam with FalkorDB as the first external backend, achieving up to a 30x speedup on structural queries. The release, driven by external contributor @dudizimber, adds native edges, Cypher query push-down, and a conformance suite for future backends, while making the full test suite a CI gate and standardizing on Apache 2.0 licensing.", "body_md": "[← back to blog](/blog)\n\n# Active Graph v1.2.0: The Graph Projection Becomes Pluggable\n\nv1.2.0 makes the materialized graph a pluggable seam with FalkorDB as the first external backend — native edges, Cypher query push-down, a conformance suite for future backends — plus a CI gate for the full test suite and one license everywhere.\n\n- release\n- activegraph\n- graph\n- falkordb\n- community\n- announcement\n\n[Active Graph](https://activegraph.ai) v1.2.0 is now live on [PyPI](https://pypi.org/project/activegraph/).\n\nThis release has a different origin story than the last one. v1.1.0 was a planned tightening pass. v1.2.0 arrived from the outside: an external contributor, [@dudizimber](https://github.com/dudizimber), opened four issues over one week, then shipped the pull requests that answered them. The result is the biggest architectural addition since packs — the materialized graph projection is now a pluggable seam, with FalkorDB as the first external backend.\n\nTL;DR\n\n- New\n`GraphStore`\n\nseam: choose where the current-state graph materializes. The event log remains the source of truth; the projection is now a pluggable, disposable view of it.`FalkorDBGraphStore`\n\nbacks the projection with a real graph database — native edges, Cypher queries, a connected graph you can actually see in FalkorDB Browser.- Structural queries push down into the database. A 2-hop pattern match over 20,000 objects drops from ~8.9 s to ~300 ms, because cost now scales with the result, not the graph.\n`GraphStoreConformance`\n\nis the extension contract: any future backend passes the same executable suite.- The full test suite is now a CI gate, on a Python 3.11 + 3.12 matrix, with the FalkorDB and Postgres conformance suites running instead of skipping.\n- Every architectural decision is locked in\n`CONTRACT.md`\n\n§ v1.2, and one license — Apache 2.0 — now appears everywhere, including the website.\n\nInstall or upgrade:\n\n```\npip install --upgrade activegraph\n```\n\n## Where This Release Came From\n\nActive Graph has always kept the materialized graph — objects, relations, patches — in process memory, rebuilt from the event log on every run. That is the right default. But it left three things hard once a run's current-state view got interesting: you couldn't query it with a graph query language, you couldn't share it across processes, and it had to fit on the heap.\n\nThe event log already had a seam for this — `EventStore`\n\n, with SQLite and Postgres behind it. The projection had no equivalent. Issue #38 named the gap, and the first PR introduced the `GraphStore`\n\nseam: an interface for where the projection lives, with `InMemoryGraphStore`\n\nas the unchanged default and `FalkorDBGraphStore`\n\nas the first external backend.\n\n``` python\nfrom activegraph import Graph, Runtime, FalkorDBGraphStore\n\nstore = FalkorDBGraphStore(host=\"localhost\", port=6379, graph_name=\"run-42\")\ngraph = Graph(graph_store=store)\nrt = Runtime(graph=graph, behaviors=[...])\n\n# or rematerialize a recorded run into FalkorDB:\nrt = Runtime.load(\"runs.db\", run_id=\"run-42\", graph_store=store)\n```\n\nThe invariant that makes this safe: the event log stays the source of truth, and the projection is disposable. Wiping a `GraphStore`\n\nloses nothing — replaying the log rebuilds it. Durability and audit continue to come from the `EventStore`\n\n. That asymmetry is what let the rest of this release move fast.\n\nInstall the backend with `pip install 'activegraph[falkordb]'`\n\n(server client) or `pip install 'activegraph[falkordb-embedded]'`\n\n(embedded engine, Python 3.12+). Neither is pulled in by `[all]`\n\n— opting into a graph database is always explicit.\n\n## Relations Became Real Edges\n\nThe first FalkorDB implementation stored each relation as a standalone node carrying source/target properties. That preserved a subtle Active Graph feature — dangling relations, where a relation can reference objects that don't exist yet — but it defeated the point of a graph database. The Browser rendered a cloud of disconnected nodes. Native traversal and graph algorithms didn't apply. Every hop was a manual property join.\n\nIssue #41 called this out, and the follow-up PR remodeled the store. Relations are now native edges with a single fixed relationship type, carrying the relation's kind as an edge property:\n\n``` php\nMATCH (s:AGObject)-[r:AGRelation {type: 'knows'}]->(t:AGObject)\nRETURN t.id, t.data\n```\n\nDangling relations survive the remodel through a shared `:AGNode`\n\nendpoint label: real objects are `:AGNode:AGObject`\n\n, and a dangling endpoint is a bare `:AGNode`\n\nplaceholder that promotes when its object arrives. The fixed relationship type also keeps every value a bound parameter — relation kinds never enter query text, so there is no injection surface in the write path.\n\nAnd because the projection is disposable, the layout change needed no migration tooling. Point `Runtime.load`\n\nat the event log and it rematerializes in the new shape.\n\n## Queries Push Down Into the Database\n\nBacking the projection with FalkorDB is only useful if queries run there. Initially they didn't: every `Graph`\n\nquery pulled the whole projection out of the database and filtered in Python, so cost scaled with graph size rather than result size. Issues #43 and #45 closed that gap.\n\n`GraphStore`\n\nnow exposes optional query hooks — `find_objects`\n\n, `find_objects_in_types`\n\n, `find_relations`\n\n, `neighborhood`\n\n, and `match_chain`\n\n— with Python defaults that define the semantics. A backend may override a hook to push the work into the database, but results must be identical to the default. On FalkorDB, type filters, relation lookups, neighborhood walks, and whole pattern chains now run as index-backed Cypher. A pattern that used to walk the projection hop-by-hop collapses into a single query.\n\nThe numbers, from the benchmark script that ships in the repo (indicative, one machine, read the ratios): a 2-hop pattern match over 20,000 objects takes ~8.9 s on the in-memory matcher's whole-projection walk and ~300 ms pushed down — roughly 30× — and the gap widens with graph size, because FalkorDB's cost scales with matches, not nodes. In-memory still wins on small graphs and always wins on writes; the FalkorDB guide has the full table and the rule of thumb.\n\nThe parts that can't be translated faithfully stayed in Python on purpose. The `where`\n\npredicate language evaluates over the pushed-down candidate set, because the structured payload is stored as JSON and a faithful translation isn't possible today. Structural filters push down; everything else stays in one place. Native `where`\n\npush-down is named follow-on work in the roadmap.\n\n## A Conformance Suite Is the Extension Contract\n\nHow do you keep two backends — and any future ones — honest about \"results must be identical\"? With an executable contract. `GraphStoreConformance`\n\nis a pytest-collectable suite covering round-trips, cascade deletes, the query-hook semantics, placeholder promotion and demotion, and cycle-safe neighborhood walks. `InMemoryGraphStore`\n\nand `FalkorDBGraphStore`\n\nboth inherit it.\n\nThat is also the door for what comes next. A Neo4j or Postgres-graph backend doesn't need a design debate; it needs to subclass the conformance suite and go green. The contract is the tests, not the prose.\n\n## The Test Suite Is Now a CI Gate\n\nHere is an uncomfortable thing this release surfaced: Active Graph had six CI workflows — docs build, docstring coverage, strict typing, wheel completeness, deploy verification — and none of them ran the test suite. Roughly 700 tests ran only by convention, locally, by whoever was driving. The FalkorDB PRs merged with no automated test execution at all.\n\nThat contradicted the project's own gate philosophy, so v1.2.0 closes it. A new workflow runs the suite on every push and pull request, on a Python 3.11 + 3.12 matrix. The 3.12 leg installs the embedded FalkorDB engine so the store and conformance tests execute instead of skipping, and a Postgres service container does the same for the Postgres event-store tests. The locked invariant: every non-slow test in the repository executes on at least one leg. A new optional-dependency skip that no leg exercises is a gate regression, not a neutral skip.\n\n## Locking Decisions After the Fact, Honestly\n\nActive Graph's development discipline is contract-first: decisions get locked in `CONTRACT.md`\n\nin the same commit as the code. The FalkorDB arc inverted that — the code came from the community at the community's pace, and merging good work mattered more than queueing it behind contract prose.\n\nThe debt got paid before release. `CONTRACT.md`\n\n§ v1.2 locks every architectural decision the arc introduced — the seam and its source-of-truth invariant, the connection model, the native-edge shape, the query-hook semantics down to which hooks promise ordering, and the conformance rule — with a provenance note stating plainly that the lock was written after the code, and why. If a future contribution lands the same way, the pattern is now named: merge, then lock before release.\n\nThe same pass restored the planning cadence around it. The roadmap now scopes the next cycle (type-completeness burndown, native structured-output mode, `where`\n\npush-down design, community surface), every deferred idea carries an explicit revisit trigger so deferrals can't silently expire, and docstring coverage on the public surface reached 100% — `Runtime`\n\n, `View`\n\n, and `Budget`\n\nwere, embarrassingly, among the last symbols without one.\n\n## One License, Everywhere\n\nA sharp-eyed user noticed that the website said MIT while the repository said Apache 2.0 — and asked, reasonably, whether an AI made an accidental edit somewhere.\n\nNo accident, but a real inconsistency. Active Graph switched from MIT to Apache 2.0 before the v1.0 launch, for the explicit patent grant and the precise contribution terms. The repository has been consistent since — `LICENSE`\n\n, `NOTICE`\n\n, wheel metadata, and a CI test that enforces it. The website was the stale artifact, and it now says Apache 2.0 like everything else. If you're building on Active Graph commercially: Apache 2.0, with a patent grant, verified in CI.\n\n## Migration Notes\n\nNo migration is required.\n\n- Runs that don't pass\n`graph_store=`\n\nbehave byte-for-byte as before.`InMemoryGraphStore`\n\nremains the default. - The FalkorDB backend is opt-in via the\n`[falkordb]`\n\nor`[falkordb-embedded]`\n\nextras. - If you tried the pre-release relations-as-nodes layout: no tooling needed. The projection is disposable — reload the run with\n`graph_store=`\n\nand it rematerializes as native edges. - v1.2.0 adds no new event types, reason codes, or error classes.\n\n## Why This Release Matters\n\nTwo reasons, one technical and one social.\n\nTechnical: the current-state view of a long-running agent system is now a real graph you can point real tools at. Cypher over live state, dashboards and sidecar inspectors sharing one projection, structural queries that cost what the answer costs — while the event log keeps being the boring, durable, replayable source of truth underneath.\n\nSocial: this is the first Active Graph release whose core capability was designed, argued, and built by someone outside the project, through the issues-first process the project asks contributors to follow. Four issues, each stating a problem, a workaround, and a proposal; then the PRs that resolved them. The process held up under its first real test, and the contract, conformance suite, and CI gate that shipped alongside it are what make the next outside contribution easier than this one.\n\nPyPI: [https://pypi.org/project/activegraph/1.2.0/](https://pypi.org/project/activegraph/1.2.0/)\n\nGitHub release: [https://github.com/yoheinakajima/activegraph/releases/tag/v1.2.0](https://github.com/yoheinakajima/activegraph/releases/tag/v1.2.0)\n\nFalkorDB guide: [https://docs.activegraph.ai/guides/using-falkordb/](https://docs.activegraph.ai/guides/using-falkordb/)\n\n[← back to blog](/blog)", "url": "https://wpnews.pro/news/activegraph-v1-2-0-is-live-x30-speedup", "canonical_source": "https://activegraph.ai/blog/activegraph-v1-2-0", "published_at": "2026-07-04 16:09:34+00:00", "updated_at": "2026-07-04 16:20:30.325200+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools"], "entities": ["ActiveGraph", "FalkorDB", "PyPI", "@dudizimber", "Apache 2.0"], "alternates": {"html": "https://wpnews.pro/news/activegraph-v1-2-0-is-live-x30-speedup", "markdown": "https://wpnews.pro/news/activegraph-v1-2-0-is-live-x30-speedup.md", "text": "https://wpnews.pro/news/activegraph-v1-2-0-is-live-x30-speedup.txt", "jsonld": "https://wpnews.pro/news/activegraph-v1-2-0-is-live-x30-speedup.jsonld"}}