agent-memory
Portable, signed agent memory with a code-enforced fact lifecycle.
Overview
agent-memory is the memory standard in the Fareground agent-standards family: one agent's persistent experience across sessions, as a file the agent owns. Typed records (fact / episode / procedure / rule) carry provenance, confidence, and an explicit lifecycle state, are content-addressed and individually signable with fg-agent-id identities, and travel in a signed, canonical memory file that any runtime can verify. Engines compete on pipelines; the record format is the interop contract.
The differentiator is consolidation as code, not vibes. Most memory systems implement contradiction resolution, promotion, and decay as an LLM freely rewriting a store. Here the fact lifecycle is a deterministic state machine: superseding must name its successor and reason, contradiction produces a transition pair instead of a silent overwrite, rules keep machine-readable evidence links and are flagged the moment their evidence is invalidated, and archival is a terminal state — records are never deleted. The LLM is an operator inside the pipeline whose typed proposals are validated against the machine before anything is written; it is never a free rewriter.
The standard is storage-agnostic by construction: RecordStore, SearchIndex, Embedder, and Operator are adapter ports, every invariant is stateable over the record format alone, and the reference ships in-memory implementations plus a deterministic hash embedder and model-free operators so the whole framework runs and tests with no model and no backend.
Status
Alpha. The library is functional end to end, and the byte-level constructions are pinned by golden wire vectors. The wire format version is pinned at 0.1 and is expected to move before a 1.0 freeze — treat on-disk records and signatures as not yet stable across versions, and expect APIs to change. See CHANGELOG.md for the current state and recent changes.
Install
The package is distributed as fg-agent-memory (import path fg_agent_memory); its only dependency, the sibling fg-agent-id identity library, resolves automatically.
pip install fg-agent-memory
# with the optional MCP stdio server
pip install "fg-agent-memory[mcp]"
Until the first PyPI release lands, install straight from GitHub instead:
pip install "fg-agent-id @ git+https://github.com/Fareground/agent-id.git" \ "fg-agent-memory @ git+https://github.com/Fareground/agent-memory.git"
For development from checkouts of this repo and the agent-id sibling:
python -m venv .venv
.venv/bin/pip install -e ../agent-id -e ".[dev]"
Usage
Two calls. No lifecycle vocabulary required.
from fg_agent_memory import Memory
memory = Memory("./memory") # writes a readable directory you can commit to git
memory.remember("Sandro's favorite editor is Zed.")
print(memory.recall("what editor does Sandro use?").as_prompt_block())
Under the hood that was: a canonical-JSON record directory (FileRecordStore), a SQLite FTS index sidecar, content-address dedup, and auto-consolidation every few remembers. All of it is swappable — Memory(store=..., indexes=..., extractor=..., operators=..., identity=...) — none of it is required.
Want every record and export signed by a persistent fg-agent-id identity? Pass a keyfile path — it is created on first run and reloaded ever after:
memory = Memory("./memory", identity="agent.key")
(An existing KeyPair works too; the string form is load_or_create_keys under the hood.)
The ghost-memory demo
The failure mode this standard exists to kill: you learn X, later learn not-X, and the stale X silently haunts retrieval forever. Here a contradiction is a first-class state — both sides stay visible until you decide, and the loser is retired addressably, never deleted.
from fg_agent_memory import Memory
memory = Memory("./memory")
# Two assertions that cannot both be true.
a = memory.remember("The staging database is Postgres.")
b = memory.remember("The staging database is not Postgres.")
# Consolidation detects the contradiction. Neither side is dropped.
memory.consolidate()
print(memory.recall("staging database").as_prompt_block())
# - The staging database is Postgres. [disputed: one side negates the other]
# - The staging database is not Postgres. [disputed: one side negates the other]
# You name the winner, with a reason that goes on the record.
memory.resolve(a.record_id, b.record_id, "checked infra: staging moved off Postgres in March")
print(memory.recall("staging database").as_prompt_block())
# - The staging database is not Postgres.
# The loser is superseded, not gone — history is one flag away.
print(memory.recall("staging database", include_history=True).as_prompt_block())
# - The staging database is not Postgres.
# - The staging database is Postgres. [superseded — kept for history]
This exact snippet is executable as written. The default detector is deterministic negation-polarity matching over shared content words (it catches "X" vs "not X" and "no X needed" phrasings, morphology included); contradictions with no negation marker need an LLM operator plugged into the contradiction port.
MCP server
Any MCP client gets remember / recall / consolidate / status tools over one memory directory (requires the [mcp] extra):
fg-agent-memory-mcp --path ~/agent-memory
{ "mcpServers": { "memory": { "command": "fg-agent-memory-mcp", "args": ["--path", "/home/me/agent-memory"] } } }
Concepts
porcelain: Memory — remember / recall / consolidate / decay / resolve / export
───────────────────────────────────────────────────────────────────────────────
raw text ──► write stage ────► RecordStore ◄──── consolidation ◄──── decay
(extractor (append-only, dedup → contradiction (mechanical
Operator, versioned → resolution → salience;
create-only) history) promotion → flags) protections
│ reported)
▼
SearchIndex ───► retrieval (state-aware, budgeted) ───► prompt block
│
▼
MemoryFile (signed, portable — the file the agent owns)
Every arrow into the store passes through the lifecycle state machine (active | transitional | superseded | archived); operators — LLM or heuristic — only ever emit typed proposals that are validated first and rejected, never repaired.
The reference ships implementations for every port, so the whole framework runs with no model and no backend:
| Port | Shipped implementations | Bring your own |
|---|---|---|
RecordStore |
FileRecordStore (git-friendly canonical-JSON directory), SQLiteRecordStore (WAL, queryable), InMemoryRecordStore |
any append-only versioned backend |
SearchIndex |
SQLiteSearchIndex (FTS5 keyword), InMemorySearchIndex (cosine over an Embedder) |
vector DBs, hybrid search |
Embedder |
HashEmbedder (deterministic, model-free) |
any embedding model |
Operator (write) |
VerbatimExtractor (porcelain default), HeuristicExtractor (regex) |
LLM extractors |
Operator (consolidation) |
TrigramNearDupOperator, HeuristicContradictionOperator, HeuristicResolutionOperator |
LLM detectors / resolvers — see examples/llm_operator.py |
Every store implementation satisfies one shared port contract; conformance is the contract, not the backend.
The wire format, lifecycle legality table, adapter contracts, retrieval scoring, and pipeline authority rules are normatively specified in spec/SPEC.md (RFC 2119); byte-level constructions are pinned by the golden vectors in spec/vectors.json. Where prose and code disagree, the vectors win.
Project structure
src/fg_agent_memory/memory.py— the porcelainMemoryAPIsrc/fg_agent_memory/records.py—MemoryRecord+MemoryFile, the portable formatsrc/fg_agent_memory/lifecycle.py— the state machine (pure functions)src/fg_agent_memory/ports.py— storage/search/operator ports + reference implssrc/fg_agent_memory/stores/— file + SQLite adapters, FTS keyword indexsrc/fg_agent_memory/retrieval.py— state-aware, budgeted retrievalsrc/fg_agent_memory/pipeline/— write stage, consolidation, decaysrc/fg_agent_memory/mcp_server.py— the MCP stdio server ([mcp]extra)spec/SPEC.md+spec/vectors.json— the wire spec and golden vectorsexamples/— the quickstart and an LLM consolidation operator skeleton
Contributing
Development setup, test commands, and style conventions are in CONTRIBUTING.md.
Built by Fareground · Licensed under Apache-2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fg_agent_memory-0.2.0.tar.gz.
File metadata
- Download URL: fg_agent_memory-0.2.0.tar.gz
- Upload date:
- Size: 106.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1e25b6b94f120d4d0f47a469d094d35ab401daff38816e47cbc247969f27e10
|
|
| MD5 |
7a34dcbf9ce8c2cc6fab2bf6851e5b78
|
|
| BLAKE2b-256 |
0bb94a0f0ec0a121893ac24e36a933213b47e7da8c5115b5cb9f6045e01ae0c4
|
Provenance
The following attestation bundles were made for fg_agent_memory-0.2.0.tar.gz:
Publisher:
release.yml on Fareground/agent-memory
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fg_agent_memory-0.2.0.tar.gz -
Subject digest:
d1e25b6b94f120d4d0f47a469d094d35ab401daff38816e47cbc247969f27e10 - Sigstore transparency entry: 2415046317
- Sigstore integration time:
-
Permalink:
Fareground/agent-memory@f52040e6714112669e921b839ab75a0a149cd4da -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Fareground
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f52040e6714112669e921b839ab75a0a149cd4da -
Trigger Event:
push
-
Statement type:
File details
Details for the file fg_agent_memory-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fg_agent_memory-0.2.0-py3-none-any.whl
- Upload date:
- Size: 66.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8913c793e0ac8f8632a601ca0b7ecdfa9dd6d7d21e7ad8d2c170b1182c27d0a7
|
|
| MD5 |
393542bb2f48069e25ff3b3827dac1b9
|
|
| BLAKE2b-256 |
3d700b7936ca0113fce0504c2e3a76ea4b0d2ebfb767ce5fb7a74e60e21a7247
|
Provenance
The following attestation bundles were made for fg_agent_memory-0.2.0-py3-none-any.whl:
Publisher:
release.yml on Fareground/agent-memory
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fg_agent_memory-0.2.0-py3-none-any.whl -
Subject digest:
8913c793e0ac8f8632a601ca0b7ecdfa9dd6d7d21e7ad8d2c170b1182c27d0a7 - Sigstore transparency entry: 2415046321
- Sigstore integration time:
-
Permalink:
Fareground/agent-memory@f52040e6714112669e921b839ab75a0a149cd4da -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Fareground
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f52040e6714112669e921b839ab75a0a149cd4da -
Trigger Event:
push
-
Statement type: