Memory System
Wayland Core can remember across sessions. When memory is on, the engine writes structured records during a run (event summaries, distilled facts, skill outcomes, user preferences) and reads them back the next time it boots in the same project. This stops a long-lived agent from re-asking the same questions and re-discovering the same project quirks.
Memory is on by default
Section titled “Memory is on by default”Memory is on by default, so a fresh install gets a working memory store with no setup. Tune it, or turn it off, per project in .wayland-core.toml or globally in the global config:
[memory]enabled = true # on by default; set false to disabledream_cycle_throttle_secs = 1800 # minimum gap between consolidation cyclesdecay_interval_secs = 3600 # how often the decay sweep runsThe --no-memory CLI flag is listed in the source but not yet wired. Use memory.enabled = false in wcore.toml to disable memory from the command line.
Five partitions, three tiers
Section titled “Five partitions, three tiers”The v2 memory model (wcore-memory/src/v2_types.rs) organizes every record by partition (what kind of thing it is) and tier (how long it persists). The two axes are independent: a partition’s default tier is a hint, not a lock. Valid combinations are enforced at write time.
Partitions
Section titled “Partitions”| Partition | Enum variant | Contents | Default tier |
|---|---|---|---|
| P1 Working | Partition::Working | Live conversation and tool context for the current session | Session |
| P2 Episodic | Partition::Episodic | Timestamped events with summaries and extracted atomic facts | Project |
| P3 Semantic | Partition::Semantic | Distilled facts as subject/predicate/object triples | Project |
| P4 Procedural | Partition::Procedural | Reusable skill artifacts with Thompson sampling stats | Project |
| P5 Core | Partition::Core | User model: preferences, style, persistent identity signals (system-only write) | Global |
| Tier | Store location | Lifetime |
|---|---|---|
| Session | <config_dir>/memory/sessions/<id>.db | One run. Each session gets its own file after rebind_session fires at init. |
| Project | .wayland-core/memory/memory.db | Lives in the repo. Shared across all sessions in that project. |
| Global | <config_dir>/memory/memory.db | Shared across all projects on the machine. |
To redirect all tiers, export WCORE_MEMORY_DIR before launch.
Valid partition/tier combinations
Section titled “Valid partition/tier combinations”Not every cell of the 5x3 matrix is open. The rules (v2_types.rs::valid_combinations):
- P1 Working: Session only.
- P2 Episodic: Session, Project, or Global.
- P3 Semantic: Project or Global (never Session).
- P4 Procedural: Project or Global (never Session).
- P5 Core: Global only (system-only write).
Writes to an invalid combination return MemoryError::AccessDenied through the gate check.
MemoryApi operations
Section titled “MemoryApi operations”The MemoryApi trait (wcore-memory/src/api.rs) is the only surface callers use directly. The production implementation is PartitionDispatcher.
| Method | What it does |
|---|---|
record_episode(ep, tok) | Write a P2 Episodic entry. Returns EpisodeId (UUIDv7). |
assert_fact(f, tok) | Write a P3 Semantic subject/predicate/object triple. Returns FactId. |
upsert_procedure(p, tok) | Insert or update a P4 Procedural skill artifact. Returns ProcedureId. |
list_procedures(tier, tok) | Return the full P4 set at the given tier (no pagination; P4 is small by design). |
update_user_model(key, val, tok) | Write a key/value pair to the P5 Core user model. Caller must hold AccessToken::System. |
search(q, tok) | Vector similarity search across partitions. Returns Vec<Hit> with partition, tier, score, and preview. |
get_episode(id, tok) | Fetch one P2 entry by EpisodeId. |
user_model(tok) | Read all P5 Core entries. |
dream_now() | Trigger consolidation immediately (normally runs on the throttle schedule). Returns DreamReport. |
compact(target_tokens) | Compact memory to a token budget. Returns CompactReport. |
record_skill_use(skill_name, succeeded, latency_ms) | Update Thompson sampling stats for a P4 procedure row. |
top_procedures(tier, k, min_uses, tok) | Top-K P4 skills by Beta-mean score, filtered to rows with at least min_uses invocations. |
kg_ingest_facts(transcript) | Extract facts from a transcript and write them to the knowledge graph. Returns fact count. |
clear_partition(partition, tier, tok) | Bulk-delete all rows in one partition at one tier. Returns the row count deleted. |
rebind_session(session_id) | Swap the Session-tier store from the bootstrap boot.db onto the real per-session file. |
Three of these are also available as LLM-invocable tools registered at bootstrap:
session_search(wcore-tools/src/session_search.rs): full-text search over past episodes.assert_fact(wcore-tools/src/assert_fact.rs): write a semantic S/P/O triple during a run.record_episode(wcore-tools/src/record_episode.rs): write an episodic entry during a run.
Auto-Memorize
Section titled “Auto-Memorize”At the end of each session the engine scores the fact candidates that surfaced during the run and persists those above a confidence threshold to long-term memory. This is on by default as of the 2026-06-04 smart-default decision (auto_memorize.rs:69).
How it works
Section titled “How it works”The AutoMemorize runner receives a SessionDigest (session id, turn count, and a list of FactCandidate triples each with a confidence in [0.0, 1.0]). It filters by min_confidence (default 0.5), requires at least min_facts_to_persist (default 1) to survive, then calls the persist closure with the filtered slice. If neither threshold is met, no facts leave the session.
Opting out
Section titled “Opting out”Auto-Memorize uses an opt-out model: absent any configuration, it is on. Two mechanisms disable it.
Environment kill switch (session-scoped):
WAYLAND_AUTO_MEMORIZE=off wayland-core "..."Persistent opt-out (write to the consent file):
echo "off" > "$WAYLAND_CONFIG_DIR/auto-memorize.consent"# or equivalently, using the default config dir:echo "off" > ~/.config/wayland-core/auto-memorize.consentThe consent file path resolves through wcore_config::config::wayland_config_dir(), so setting WAYLAND_HOME redirects it to $WAYLAND_HOME/auto-memorize.consent for hermetic sandboxing.
Decision order (auto_memorize.rs::consent_granted):
- If
WAYLAND_AUTO_MEMORIZE=off(case-insensitive), return false. This overrides the file. - If the consent file exists and its contents are one of
off,opt-out,optout,false,no, ordisable, return false. - Otherwise (absent file, unreadable file, any other content including a legacy
opt-infile), return true.
Decay scheduler
Section titled “Decay scheduler”A background tokio task ticks ConsolidationEngine::decay() on the interval set by decay_interval_secs (default 3600 seconds, i.e. one hour). The first tick is skipped at boot so freshly-opened memory has time to settle before the first sweep fires (memory.rs::spawn_decay_scheduler). Transient errors from individual decay ticks are logged as warnings; the scheduler keeps running.
Embedding backends
Section titled “Embedding backends”The Embedder trait (wcore-memory/src/embed/mod.rs) requires every backend to return an L2-normalized vector of constant length dim() for each input. The backend is selected per-project via memory.embedder.backend in wcore.toml.
| Backend | TOML value | Description |
|---|---|---|
| Hashed (default) | "hashed" | Deterministic 384-dim hashed-token bag. No API key, no model load. Good for offline development and CI. |
| OpenAI | "open_ai" | OpenAI embeddings API. Reads the API key from the env var named in api_key_env. |
| Voyage | "voyage" | Voyage AI embeddings API. Reads the API key from the env var named in api_key_env. |
| Local BGE | "local_bge" | Local bge-small-en-v1.5 model via candle/ggml. Requires the local-embedder Cargo feature. |
Configuration in wcore.toml:
[memory]enabled = truedecay_interval_secs = 3600dream_cycle_throttle_secs = 1800
[memory.embedder]backend = "open_ai" # hashed | open_ai | voyage | local_bgeapi_key_env = "OPENAI_API_KEY" # env var name; unused for hashed and local_bgemodel = "text-embedding-3-small" # optional; falls back to per-backend defaultThe api_key_env field takes the name of an environment variable, not the key itself. The engine reads the named variable at startup. For hashed and local_bge the field is ignored.
Inspect a session
Section titled “Inspect a session”The --memory-show flag prints the procedures and user model for a session in plain text. It works whether memory is currently enabled or not:
wayland-core --memory-show <SESSION_ID> --project-dir ~/projectWhen memory is off or the session has no data, all counts print as zero. Exits 0 in all cases so scripts can probe state safely.
Inside an active session the TUI /memory slash command opens the diagnostics surface (the same screen accessible via the /doctor//cost//memory triptych), which lists stored entries and offers a delete affordance.
You can also open any tier’s SQLite file directly with sqlite3 for ad-hoc queries:
sqlite3 .wayland-core/memory/memory.db ".tables"Wipe memory
Section titled “Wipe memory”rm .wayland-core/memory/memory.db # project tierrm -rf "$(dirname "$(wayland-core --config-path)")/memory" # global tier and user modelBoth are non-recoverable. To clear a single partition without deleting the file, use clear_partition via the API or the /memory TUI surface.
Relation to the desktop Memory and Wiki
Section titled “Relation to the desktop Memory and Wiki”This is the engine-level store the CLI reads and writes. The desktop app surfaces its own Memory and Wiki views on top of the same model, so what the CLI records in a project is the same memory the app can show.