Memory
Every agent in Axocoatl has a four-tier memory system, modeled on the MemGPT/Letta split between a small curated context the agent edits itself and a larger lossless store it retrieves from. The tiers go from hot working state down to durable recall:
| Tier | Lives in | What it holds | |------|----------|---------------| | 1 — Session | In-process state | The live conversation, this turn | | 2 — Daily log | Append-only JSONL, one file per date | Everything that happened, by day | | 3 — Core memory | Named blocks, rendered into every prompt | Curated facts the agent keeps in context | | 4 — Semantic | On-device vector store | Lossless recall by meaning, not by key |
All four tiers are local-first. The semantic embedder runs on your own hardware (see below); nothing leaves the machine unless you point a provider at a remote LLM.
Tier 1: session
Section titled “Tier 1: session”The session is the live conversation — the ordered list of messages for the
current run, held in process. It’s the working set every LLM call sees.
Source: session.rs.
Tier 2: daily log
Section titled “Tier 2: daily log”The daily log is an append-only JSONL file per date
({base_dir}/{agent_id}/YYYY-MM-DD.jsonl). Every conversation turn, tool
call, decision, and note is appended as one line — nothing is ever
overwritten or evicted, so it’s the durable record of what the agent did.
The agent can read its own history back by date range with the
recall_timeframe tool — “what did I do on the 12th?” reads that day’s
log. Source: daily_log.rs.
Tier 3: core memory (agent-editable)
Section titled “Tier 3: core memory (agent-editable)”Core memory is the curated top of the hierarchy — a small set of named blocks that are rendered into the system prompt on every turn, so they’re always in context. By default an agent gets three blocks:
persona— who the agent is and how it behaves.human— what it knows about the person it’s working with.project— durable facts about the work at hand.
You can override the default set in YAML:
memory: core: blocks: - label: persona value: "A terse senior Rust engineer." limit: 2000 - label: project description: "Facts about the repo under work." shared: trueThe agent maintains these blocks itself, using three tools exposed in its tool loop:
core_memory_append— add a line to a block.core_memory_replace— find-and-replace within a block.core_memory_set— overwrite a block’s whole value.
Edits persist per-agent as atomic, owner-only (0600) JSON. Each block has a
character limit (default 2000; 0 means unlimited) the tools enforce, so
the curated context can’t grow without bound.
Shared blocks (team memory)
Section titled “Shared blocks (team memory)”A block marked shared: true is backed by a process-wide registry
instead of the per-agent store. Every agent that declares that label gets the
same block, so one agent’s edit is immediately visible to the others —
team memory across a lattice of agents. Source:
core_memory.rs.
Tier 4: semantic recall
Section titled “Tier 4: semantic recall”Tier 4 is a lossless on-device vector store. Every stored memory is embedded into a vector; recall finds the nearest vectors by cosine similarity. Real recall — semantically related text with no shared words still scores high.
There are two ways the agent reaches it:
- Passive injection. Each turn, the top-k most relevant memories above a score floor are injected into the prompt automatically — the agent doesn’t have to ask.
- The
recall_searchtool. The agent can also query the store directly when it needs a specific fact that isn’t in the passive set.
Both paths share one relevance bar, tunable under memory.recall:
memory: recall: passive_inject: true # inject top-k each turn (default true) top_k: 5 # how many hits (default 5) min_score: 0.15 # cosine floor a hit must clear (default 0.15)On-device embeddings
Section titled “On-device embeddings”Embeddings come from all-MiniLM-L6-v2 run with
Candle — pure-Rust, no ONNX, no C++
runtime, no external embedding API. The model weights are fetched once (~90 MB)
the first time an agent needs them, then cached. The active embedder’s id is
recorded in each store file; if it changes, every memory is automatically
re-embedded so all vectors share one space (the original text is always kept).
If you build with --no-default-features (dropping neural-embeddings),
Tier 4 falls back to a pure-Rust lexical embedder (signed feature hashing).
Recall is weaker — it reflects word overlap rather than meaning — but there’s
no model download and the binary stays small. Source:
semantic.rs.
Sleep-time consolidation
Section titled “Sleep-time consolidation”Tiers 3 and 4 are linked by a background “sleep-time” consolidation pass. A daemon loop periodically asks idle agents to run an LLM memory-manager turn that reads recent Tier-4 activity and promotes durable facts up into the core blocks — so the things that matter graduate into always-in-context memory on their own.
Two properties keep it safe:
- Promotion-only. It reads Tier 4 and writes Tier 3. It never evicts the semantic store — the lossless record stays intact.
- Idle-gated. Each agent decides whether it’s been idle long enough; the pass never fires mid-turn. A graceful stop runs one final pass.
Source: consolidation.rs
(the loop) and on_consolidate in the actor behavior (the per-agent pass).
Checkpointing
Section titled “Checkpointing”Checkpointing is separate from the memory tiers. It’s a crash-recovery
snapshot: the session transcript serialized to disk with bincode, written
atomically with owner-only (0600) permissions, keeping the last three
versions per agent.
On restart the supervisor restores the agent from its latest checkpoint —
the conversation transcript only. It does not restore token-usage
accounting or tool/plan state; the agent resumes its conversation and rebuilds
the rest. The checkpoint frequency follows the configured policy
(EveryLlmCall, EveryNMessages(n), Manual, or None). Source:
checkpoint.rs.
Where the data lives
Section titled “Where the data lives”By default, under ./data/:
data/ memory/ core/ agent_{id}.json # Tier 3 — per-agent core blocks shared/ # Tier 3 — shared (team) blocks {agent_id}/ YYYY-MM-DD.jsonl # Tier 2 — daily logs agent_{id}_semantic.json # Tier 4 — semantic store checkpoints/ # crash-recovery snapshots models/ all-MiniLM-L6-v2/ # cached embedder weightsThe data/ directory is gitignored by default. Move it to your home, back it
up, sync it — your call.