CONCEPTS
The Event-Sourcing Model
ChainMemory follows an event-sourcing architecture. Understanding this pattern is key to understanding the entire system.
In traditional systems, you store the current state and overwrite it on each change. In event-sourcing, you store every change as an immutable event, and the current state is derived by replaying those events.
In ChainMemory:
- Memories are events — Each memory is an immutable record of something that happened: a decision was made, a risk was identified, a technology was chosen, a milestone was reached.
- Project State is a view built from those events — A client reads the memories and proposes operations that cite them; the server validates and applies them, and stores each resulting version. The state is not recomputed automatically from the log: it changes only when a client consolidates.
- The anchor is the proof of existence — When a Project State is anchored on-chain, the blockchain certifies that this specific materialized view existed at that exact block height.
Pattern
Memory #1 (event) ─┐
Memory #2 (event) ─┤
Memory #3 (event) ─┼──→ ops from a client ──→ Project State v1 ──→ Anchor (block 120000)
Memory #4 (event) ─┤
Memory #5 (event) ─┘
Memory #6 (event) ─┐
Memory #7 (event) ─┼──→ ops from a client ──→ Project State v2 ──→ Anchor (block 123539)
Memory #8 (event) ─┘
The memories are the source of truth and never change. Each state version records which memories it relied on, so any item can be traced back to its evidence. The anchor proves which state existed at which block.
What is a Memory
A memory is the fundamental unit of ChainMemory. It is a fragment of information extracted from an AI conversation that is considered valuable for the project's future.
Each memory contains:
- Content — The text of the conversation or note
- Hash — SHA-256 of the content, immutable
- Project — Which project it belongs to
- Tags — Free-form labels for organization (decision, bug, architecture, idea, etc.). Tags are for your use — the Project State has its own fixed fields (see Project State)
- Number — Sequential within your account (#1, #2...)
- Source — Where it was saved from (extension, MCP, API)
- Timestamp — Exact moment of creation
Projects
A project groups related memories. Each project has its own timeline, consolidated state, and independent on-chain anchor.
Example projects: my-saas, ml-thesis, chainmemory, mobile-app.
Project State
The Project State (also called the Project Brain) is the consolidated, versioned view of a project. It is not generated by a server-side engine: a client — an AI model working through update_project_state (MCP) or POST /v1/project/:name/state/ops (API) — proposes operations, the server validates them against a closed grammar, applies them with a deterministic builder and computes the new state_hash. Each item records the memories that justify it.
What the state contains (schema version 2)
| Field | What it holds | Closed values |
|---|---|---|
| vision, phase, current_focus | Where the project is going, the stage it is in, and what matters right now | — |
| decisions | Choices with a title, a statement and their status | status: proposed, confirmed, rejected, superseded |
| milestones | Deliverables | status: planned, in_progress, done |
| risks | Identified threats | severity: low, med, high — not medium or critical; status: open, mitigated, closed |
| priorities | Ranked work with a priority_score, linked to the risks it mitigates (mitigates) | status: active, done, dropped |
| open_questions | Questions and, once resolved, their answer | — |
| assumptions, constraints | What the project takes for granted and the rules it must respect | — |
| vocabulary, metrics | Shared terms and named values | — |
| environment | Hosts, services, repositories and operating rules | — |
| state_meta | Version, consolidated_until_event watermark and previous_state_hash | — |
"severity": "medium": the engine only accepts low, med or high.
get_project_state (MCP) or GET /v1/project/:name/state, and it is what a client reads before proposing operations. The brief is the same state written as text by relevance and within a character budget, to get oriented or to work on one priority: get_project_brief (MCP), GET /v1/project/:name/inject (API) and the extension's Project Brain button. The brief is public by default: addresses, ports, server paths and security rules are withheld.
State lifecycle
The state is incremental and append-only: each consolidation starts from the previous version and applies only the new operations. Every version carries its state_hash (SHA3-256 of the canonical state, domain-separated with CM_PROJECT_STATE_V<schema_version>) and, in state_meta, the hash of the version before it. After it is written, the version's hash is anchored on-chain in the ProjectStateAnchor contract, normally within ten minutes.
Version chain
v85 ──previous_state_hash──▶ v86 ──previous_state_hash──▶ v87
│ │ │
└─ anchorId 89 └─ anchorId 90 └─ anchorId 94
Example: what GET /v1/project/:name/state returns (trimmed)
JSON
{
"project": "payment-system",
"schema_version": 2,
"version": 4,
"state_hash": "0x3f8c2a…e91d",
"generated_at": "2026-09-13T22:02:35.000Z",
"anchor": { "status": "anchored", "onchain_anchor_id": 12, "tx_hash": "0x…", "block_number": 681919 },
"state": {
"phase": "beta",
"current_focus": "PCI review before opening to the first tenants",
"decisions": [
{ "id": "dec_0002", "title": "PostgreSQL with RLS for multi-tenancy",
"statement": "Row-level security removes tenant filtering from the application layer",
"status": "confirmed", "superseded_by": null,
"evidence_root": "0x9a41…c07e", "created_version": 2, "updated_version": 3 }
],
"milestones": [
{ "id": "mil_0001", "title": "Database schema", "status": "done",
"evidence_root": "0x5b2d…81fa", "created_version": 1, "updated_version": 2 }
],
"risks": [
{ "id": "risk_0001", "title": "RLS performance at 100K tenants", "severity": "med", "status": "open",
"evidence_root": "0xd7e0…2a19", "created_version": 3, "updated_version": 3 }
],
"state_meta": { "version": 4, "consolidated_until_event": 150, "previous_state_hash": "0x7b2e…f4c0" }
}
}
GET /v1/project/:name/state requires the owner's API key and always returns the latest version. Past versions are verifiable by hash (see Hash & Verification), not re-readable in full through this endpoint.
Best practices
- Save the memory first, consolidate after — the state cites memories; a decision that only exists in the operation has no support
- Wait for anchoring before citing — a plaintext memory gets its
event_hashwhen it syncs to the chain, about 30 seconds after being written - Advance the watermark — send
consolidated_until_eventwith the highest memory number you actually reviewed - Supersede, don't rewrite — a replaced decision stays in the state with its status changed, so the history of how the project evolved is kept
Evidence Chain
When a client proposes an operation it cites the memories that support it in evidence_memory_ids — an array of memory numbers. The server resolves each one to its event_hash and stores, on the resulting item, the Merkle root of those hashes as evidence_root.
Operation sent by the client
{
"op": "add_decision",
"title": "Use Clique PoA consensus",
"statement": "Proof of Authority gives fast, low-cost anchoring for a sovereign chain",
"evidence_memory_ids": [12, 45, 67]
}
Item stored in the state
{
"id": "dec_0001",
"title": "Use Clique PoA consensus",
"statement": "Proof of Authority gives fast, low-cost anchoring for a sovereign chain",
"status": "proposed",
"evidence_root": "0x028218d0…f082"
}
This creates a provenance chain:
- Decision
dec_0001exists because memories 12, 45 and 67 support it; the consolidation response lists their event hashes - Each memory's
event_hashis written on-chain when the memory syncs - The
evidence_rootcommits to exactly that set of hashes - The state that contains the item has a
state_hashanchored inProjectStateAnchor
422 evidence_unresolved, and nothing is written or charged. An operation that cites nothing is accepted but stored with evidence_root 0x000…0: state with no provenance. The chain seals it just the same, because it verifies hashes, not correctness.
Conflict Resolution
Nothing resolves contradictions automatically. There is no engine reading memories and deciding which one wins: the client that consolidates decides, and the grammar makes that decision explicit and auditable.
Replacing a decision
If a newer memory changes direction, the client adds the new decision and marks the old one with supersede_decision (id of the old one, by_id of the new one). Both remain in the state.
Decision status
A decision is created as proposed. The client moves it to confirmed or rejected with set_decision_status, and to superseded with supersede_decision.
Several agents on the same project
Operations are applied on top of whatever version is current when the call arrives; /state/ops does not check an expected version. Nothing is lost — every call creates a new version — but an agent working from a stale read can re-add or contradict what another agent just wrote. Read the state immediately before consolidating. Each call accepts up to 100 operations.
State Governance
The Project State lifecycle is governed by clear rules:
Who can consolidate?
Only the project owner (the account that created the project) can trigger a consolidation. This ensures that the structured knowledge extraction is always controlled by the data owner.
When does consolidation happen?
Consolidation can be triggered in two ways:
- Client-driven — an AI model proposes operations through
update_project_state(MCP) orPOST /v1/project/:name/state/ops(API). The server validates them and only then do they become state - No automatic trigger — consolidation never happens on its own. Nothing is ever written to your state unless a client proposes it
Can it be reverted?
Each consolidation creates a new version (v1, v2, v3...). Previous versions remain accessible. You cannot delete a version, but you can always consolidate again to produce a corrected state. The version chain is append-only.
Snapshots
Every Project State version is a snapshot. The combination of version number + state_hash + on-chain anchor creates a verifiable checkpoint. The owner reads the latest version with GET /v1/project/:name/state; the hash and on-chain anchor of any past version are public at GET /v1/project/:name/state/anchor?version=2 and GET /v1/verify/:name.
| Action | Who | When | Reversible |
|---|---|---|---|
| Consolidate | Project owner | Only when a client proposes operations | New version created (append-only) |
| Anchor on-chain | Automatic (operator wallet) | Within ~10 minutes of each consolidation | Immutable once anchored |
| Archive memory | Project owner | Anytime | Can unarchive |
| Read the latest state | Project owner (API key) | Anytime | N/A (read-only) |
| Verify any version's hash | Anyone (public endpoint) | Anytime | N/A (read-only) |
Hash & Verification
Each memory generates a SHA-256 hash of its content. This hash is the unique, immutable fingerprint of that memory. Content cannot be modified without changing the hash.
The state hash is a hash of the complete consolidated state (all decisions, milestones, risks, etc.). This state hash is anchored on the blockchain via a transaction on the ProjectStateAnchor contract.
Public verification
Verification in ChainMemory is public and permissionless. Anyone can:
- Call
GET /v1/project/:name/state/anchor(no API key required) - Get the
state_hashand thetx_hashof the transaction - Verify on the explorer that the transaction exists
- Read the contract directly on the blockchain to confirm the hash matches
This proves the project state existed exactly as described at the time of anchoring. It cannot be falsified retroactively.
Privacy Model
A common concern with blockchain-based systems is data exposure. ChainMemory addresses this with a strict separation:
What is stored where
| Data | Location | Access |
|---|---|---|
| Memory content | Encrypted database (off-chain) and AES-256-GCM ciphertext on-chain | Plaintext: owner only. Ciphertext: public but unreadable without the key |
| Memory hash (SHA-256) | Database + on-chain once the memory syncs (~30 s) | Hash is public but reveals nothing about content |
| Project State (structured) | Database (off-chain) | Owner only |
| State hash | Blockchain (on-chain) | Public — this is the verifiable proof |
| Anchor metadata (tx, block) | Blockchain (on-chain) | Public |
A state anchor contains only the hashed project identifier, the version number, the state hash and a timestamp. A memory transaction additionally carries the encrypted content plus its category, importance and plaintext length. From either one it is impossible to reconstruct the content without the owner key.
This design means ChainMemory can provide cryptographic verification without compromising privacy. The blockchain proves that a state existed, not what it contained.