Skip to main content

Fareground

agent-memory

Portable, signed agent memory with a code-enforced fact lifecycle.

CI Python Status


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 porcelain Memory API
  • src/fg_agent_memory/records.pyMemoryRecord + MemoryFile, the portable format
  • src/fg_agent_memory/lifecycle.py — the state machine (pure functions)
  • src/fg_agent_memory/ports.py — storage/search/operator ports + reference impls
  • src/fg_agent_memory/stores/ — file + SQLite adapters, FTS keyword index
  • src/fg_agent_memory/retrieval.py — state-aware, budgeted retrieval
  • src/fg_agent_memory/pipeline/ — write stage, consolidation, decay
  • src/fg_agent_memory/mcp_server.py — the MCP stdio server ([mcp] extra)
  • spec/SPEC.md + spec/vectors.json — the wire spec and golden vectors
  • examples/ — 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

fg_agent_memory-0.2.0.tar.gz (106.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fg_agent_memory-0.2.0-py3-none-any.whl (66.7 kB view details)

Uploaded Python 3

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

Hashes for fg_agent_memory-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d1e25b6b94f120d4d0f47a469d094d35ab401daff38816e47cbc247969f27e10
MD5 7a34dcbf9ce8c2cc6fab2bf6851e5b78
BLAKE2b-256 0bb94a0f0ec0a121893ac24e36a933213b47e7da8c5115b5cb9f6045e01ae0c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for fg_agent_memory-0.2.0.tar.gz:

Publisher: release.yml on Fareground/agent-memory

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for fg_agent_memory-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8913c793e0ac8f8632a601ca0b7ecdfa9dd6d7d21e7ad8d2c170b1182c27d0a7
MD5 393542bb2f48069e25ff3b3827dac1b9
BLAKE2b-256 3d700b7936ca0113fce0504c2e3a76ea4b0d2ebfb767ce5fb7a74e60e21a7247

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page