Observed since 20 Oct, 21:44 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Semantic-causal CRDT for agent-mutable world state
Semantic-causal CRDT for agent-mutable world state.

Quick Start · How It Works · CLI Reference · MCP / Claude · OpenAI · vs. Alternatives · Contributing
Multi-agent systems share a mutable view of the world. When two agents update the same fact simultaneously — or when one agent asserts a fact that logically contradicts another — the shared state becomes inconsistent.
Traditional approaches either:
agentcrdt solves this with a semantic-causal CRDT:
(domain, entity, attribute) — same key always resolves to the same slotagentcrdt set life king alive False --agent-id agent-A
agentcrdt merge agent-B.db
agentcrdt events # shows ContradictionEvents if rules are violated
flowchart LR
A[Agent A\nWorldFact version=2] --> M[WorldMerger\nLWW merge]
B[Agent B\nWorldFact version=1] --> M
M --> S[WorldStore\nSQLite]
S --> R[RuleEngine\nsemantic check]
R --> C[ContradictionEvent\nsaved to store]
R --> OK[No event\nconsistent state]
Core primitives:
SHA-256[:16]("domain|entity|attribute"). Same key across agents = same slot. Value and version are mutable metadata.domain.entity.attr=X then other_domain.entity.other_attr must be Y".ContradictionEvent objects for violations.| Feature | Details |
|---|---|
| Content-addressed facts | Same (domain, entity, attribute) always produces the same ID |
| LWW CRDT merge | Higher version wins; on tie, higher timestamp wins |
| Semantic rules | SemanticRule + RuleEngine detect cross-domain contradictions |
| Contradiction events | Persisted as ContradictionEvent objects in the store |
| Offline / local-first | Single SQLite file, no server required |
| JSON output | Machine-readable output for downstream automation |
| Markdown output | Ready-to-paste GitHub PR comment |
| FastAPI REST server | /fact, /facts, /merge, /events, /health endpoints |
| MCP server | Model Context Protocol integration for Claude and other agents |
| 52 tests | Comprehensive test suite covering all layers |
pip install agentcrdt
from agentcrdt import WorldFact, WorldStore, WorldMerger, SemanticRule, RuleEngine
# Agent A: king is dead
fact_a = WorldFact(domain="life", entity="king", attribute="alive",
value=False, version=1, agent_id="agent-A")
# Agent B: treaty is still valid (inconsistent!)
fact_b = WorldFact(domain="alliance", entity="king", attribute="valid",
value=True, version=1, agent_id="agent-B")
rule = SemanticRule(
name="dead-king-voids-treaty",
trigger_domain="life", trigger_attribute="alive", trigger_value=False,
implies_domain="alliance", implies_entity_same=True,
implies_attribute="valid", implies_value=False,
)
with WorldStore("local.db") as local, WorldStore("remote.db") as remote:
local.set_fact(fact_a)
remote.set_fact(fact_b)
result = WorldMerger(rule_engine=RuleEngine([rule])).merge(local, remote)
print(result.conflicts) # [ContradictionEvent(rule='dead-king-voids-treaty', ...)]
# Note: the snippet above creates local.db and remote.db in the cwd; delete them when done.
# For automatic cleanup wrap with tempfile.TemporaryDirectory() (see docs/quickstart.md).
agentcrdt [--db PATH] COMMAND [ARGS]
| Command | Description |
|---|---|
set DOMAIN ENTITY ATTR VALUE | Store or update a world fact |
get DOMAIN ENTITY ATTR | Retrieve a world fact by key |
merge OTHER_DB | Merge another store into this one (LWW CRDT) |
events | List all contradiction events |
status | Show fact count and event count |
--version | Show installed version |
Examples:
agentcrdt --db world.db set life king alive False --version 2 --agent-id agent-A
agentcrdt --db world.db get life king alive
agentcrdt --db world.db merge /tmp/agent-b.db
agentcrdt --db world.db events
agentcrdt --db world.db status
pip install 'agentcrdt[api]'
uvicorn agentcrdt.api:app --reload
Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /fact | Create or update a world fact |
GET | /facts | List facts (optional ?domain= filter) |
POST | /merge | Merge a remote store into the local one |
GET | /events | List contradiction events |
GET | /health | Health check |
pip install 'agentcrdt[mcp]'
Add to ~/.config/claude/claude_desktop_config.json:
{
"mcpServers": {
"agentcrdt": {
"command": "agentcrdt-mcp"
}
}
}
Available MCP tools: set_world_fact, get_world_facts, merge_world_state.
agentcrdt exposes OpenAI-compatible tool definitions in tools/openai-tools.json:
import json
tools = json.loads(open("tools/openai-tools.json").read())
# Pass `tools` to openai.chat.completions.create(tools=tools, ...)
Topics: #crdt #agents #multi-agent #world-state #llmops #mcp
src/agentcrdt/
├── fact.py # WorldFact, ContradictionEvent
├── rules.py # SemanticRule, RuleEngine
├── store.py # WorldStore (SQLite)
├── merger.py # WorldMerger, MergeResult
├── report.py # print_state, print_events, to_json, to_markdown
├── cli.py # Click CLI entry point
├── api.py # FastAPI REST server
└── mcp_server.py # MCP server
E-Commerce: Preventing Multi-Agent Inventory Oversell on Black Friday
Three purchasing agents — East Coast, West Coast, and EU — each read inventory=50 and begin processing orders simultaneously. Without coordination, they'd oversell by 25 units ($380K in chargebacks). With agentcrdt, the merge surfaces the contradiction immediately:
import tempfile
import os
from agentcrdt import WorldFact, WorldStore, WorldMerger, SemanticRule, RuleEngine
# SemanticRule: if inventory count goes negative (EU sold past zero),
# the oversell_guard must flip to True — but the system seeded it False.
# The mismatch fires a ContradictionEvent at merge time.
oversell_rule = SemanticRule(
name="inventory-oversell-detected",
trigger_domain="inventory",
trigger_attribute="count",
trigger_value=-25, # EU's final count after selling 45 of 50
implies_domain="inventory",
implies_entity_same=True,
implies_attribute="oversell_guard",
implies_value=True, # rule expects guard=True when count<0
)
with tempfile.TemporaryDirectory() as tmp:
east_db = os.path.join(tmp, "east.db")
west_db = os.path.join(tmp, "west.db")
eu_db = os.path.join(tmp, "eu.db")
local_db = os.path.join(tmp, "local.db")
# System seeds a guard fact: "no oversell in progress" (version=0)
with WorldStore(local_db) as local:
local.set_fact(WorldFact(
domain="inventory", entity="airpods_pro",
attribute="oversell_guard", value=False,
version=0, agent_id="system",
))
# All three agents read inventory=50 simultaneously and start selling.
# East sells 30 → remaining count = 20
with WorldStore(east_db) as east:
east.set_fact(WorldFact(
domain="inventory", entity="airpods_pro",
attribute="count", value=20,
version=1, agent_id="east",
))
# West sells 25 → remaining count = 5 (already below East's view)
with WorldStore(west_db) as west:
west.set_fact(WorldFact(
domain="inventory", entity="airpods_pro",
attribute="count", value=5,
version=1, agent_id="west",
))
# EU sells 45 → count = -25 (went deeply negative)
with WorldStore(eu_db) as eu:
eu.set_fact(WorldFact(
domain="inventory", entity="airpods_pro",
attribute="count", value=-25,
version=2, agent_id="eu",
))
# Merge all three into local — LWW picks EU's version=2 count=-25.
# The rule engine then sees count=-25 alongside oversell_guard=False
# and fires a ContradictionEvent.
merger = WorldMerger(rule_engine=RuleEngine([oversell_rule]))
with WorldStore(local_db) as local, \
WorldStore(east_db) as east, \
WorldStore(west_db) as west, \
WorldStore(eu_db) as eu:
merger.merge(local, east)
merger.merge(local, west)
result = merger.merge(local, eu)
print("Conflicts detected:", len(result.conflicts))
for evt in result.conflicts:
print(f" rule={evt.rule!r} agents={evt.agent_a!r} vs {evt.agent_b!r}")
# Conflicts detected: 1
# rule='inventory-oversell-detected' agents='eu' vs 'system'
What this prevents: Last-write-wins databases silently allow the oversell — the last agent to write wins and the inventory appears valid until chargebacks arrive. agentcrdt surfaces the semantic contradiction at merge time so a reconciliation agent can intervene before fulfillment.
| Tool | Approach | Semantic Rules | MCP |
|---|---|---|---|
| agentcrdt | Content-addressed LWW CRDT | Yes | Yes |
| Automerge | JSON CRDT | No | No |
| Yjs | CRDT text/map | No | No |
| Redis | Key-value store | No | No |
| custom DB | Ad-hoc | Manual | No |
agentcrdt is available on Smithery — search for agentcrdt.
See how teams are using agentcrdt in production:
Subscribe to The Silence Layer — weekly dispatches on production AI infrastructure, new releases, and the failure modes that production AI systems don't surface until it's too late.
See CONTRIBUTING.md. PRs reviewed within 5 business days.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.1 | 24 Jun 2026 | 11 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:44 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:ce1ed28d878925e27cea932d3cc566c6c4f1e44d5cf7a0017a20d0f2586fcdb3