Skip to content
CompozyOS RuntimeMemory

Memory System

How Compozy stores curated Markdown memory, captures a frozen snapshot at session start, and routes every write through the controller WAL.

Audience
Operators running durable agent work
Focus
Memory guidance shaped for scanability, day-two clarity, and operator context.

Compozy memory is curated Markdown that survives across sessions. It is designed for durable facts that future agents should be able to discover without replaying every old transcript.

The current implementation is intentionally hybrid:

  • curated semantic memory (user, feedback, project, reference) is Markdown-authoritative on disk
  • memory_decisions is a per-database write-ahead log: every controller decision lands there before any file mutation
  • memory_events is the canonical observability log for memory operations
  • memory_catalog_entries, memory_chunks, and FTS5 indexes are derived projections
  • memory_recall_signals and memory_consolidations carry live runtime state for dreaming
  • there are three scopes: global, workspace, and agent — agent has two tiers
  • normal session prompts receive a frozen startup snapshot plus the workspace checkpoint; degraded resume replay receives the same checkpoint before persisted transcript context

Runtime Flow

Rendering diagram…

Every write — operator, agent, extractor, dreaming — goes through the controller. The WAL is durable before the file lands; the catalog is rebuilt from the file.

Memory is not streamed into an already-running process. When a session starts, Compozy captures a frozen snapshot of the resolved scopes, packages a recall block, appends the current workspace checkpoint, prepends the assembled memory section to the agent prompt, and hands that prompt to the ACP subprocess. Writes during the session are durable immediately but only become visible to the next session via a fresh snapshot.

Scopes And Authorities

ScopeStorage rootAuthority
global$COMPOZY_HOME/memory/Cross-workspace user-wide facts.
workspace<workspace>/.compozy/memory/Workspace-private project facts.
agent (workspace)<workspace>/.compozy/agents/<agent>/memory/Default agent tier. Workspace-private agent state.
agent (global)$COMPOZY_HOME/agents/<agent>/memory/Cross-workspace agent state. Explicit --agent-tier global.

Read precedence is agent-workspace ▸ agent-global ▸ workspace ▸ global. Identity is keyed by (type, slug) per scope, and a deeper scope shadows a shallower scope with the same identity. The runtime never silently merges shadowed entries — see Scopes.

Scope is selected explicitly. --scope agent requires --agent <name> and a validated --agent-tier {workspace, global}; the agent tier defaults to workspace when omitted. CLI/HTTP/UDS operator writes that omit --scope fall back to a conservative type-driven default for the non-agent scopes only: user and feedbackglobal, project and referenceworkspace. Agent scope must be explicit.

Workspace Identity

Workspace memory is keyed by a stable ULID stored in <workspace>/.compozy/workspace.toml:

workspace_id = "01HXJ9YR4Q..."
created_at   = "2026-05-04T14:30:00Z"
realpath_at_creation = "/Users/you/dev/checkout-api"

The runtime resolves the workspace by walking ancestors for .compozy/workspace.toml, reads the ULID, and uses that as the durable identity for catalog rows, events, decisions, dreaming runs, and session ledgers. Path-keyed memory is gone — moving the workspace directory does not orphan its memory because the ULID travels with the directory. See Workspace Resolver for the lookup cascade.

Four Memory Types

Every curated memory file declares one of four types:

TypeUse it forExample
userStable user preferences, working style, or recurring personal context."Prefer concise PR summaries with risk and test notes."
feedbackRepeated corrections, review guidance, and quality signals that apply across work."Do not weaken tests to match broken behavior."
projectDecisions, constraints, active architecture, and local project facts."This repo keeps docs site pages under packages/site/content/runtime/."
referenceExternal references, runbooks, links, or system facts worth re-reading on demand."Production logs live in the hosted provider console, not local files."

The taxonomy is closed. Unsupported types are rejected at the controller boundary.

Memory File Format

Memory files are Markdown with strict YAML frontmatter. The canonical YAML key for the agent name is agent; JSON and HTTP payloads use agent_name.

FieldRequired whenMeaning
nameyesHuman-readable title shown in list output and useful in index entries.
descriptionyesOne concise discovery sentence used by recall and indexing.
typeyesOne of user, feedback, project, or reference.
scopeyesOne of global, workspace, agent.
agentwhen scope = agentProducer agent name.
agent_tierwhen scope = agentOne of workspace, global.
provenanceoptionalSource actor, source sessions, confidence, supersession, timestamps.

Example feedback memory written through the controller:

---
name: Test Integrity
description: Production bugs must be fixed instead of weakening tests
type: feedback
scope: global
provenance:
  source_actor: extractor
  source_sessions:
    - 01J7VR2Q8MZ4FXWZ8WB7M2A4S0
  confidence: high
  created_at: 2026-04-12T14:32:11Z
  updated_at: 2026-04-12T14:32:11Z
---

If a test reveals incorrect behavior, fix the production code. Do not relax assertions just to make
the suite green.

Storage Layout

Each scope has a MEMORY.md index next to its memory documents and a structurally-excluded _system/ namespace for machine-managed artifacts:

$COMPOZY_HOME/memory/
  MEMORY.md
  user_review-style.md
  feedback_test-integrity.md
  _inbox/                        # extractor staging (operator-quiet)
  _system/
    dreaming/
    extractor/
    extractor/failures/
    ad_hoc/

<workspace>/.compozy/memory/
  MEMORY.md
  project_checkpoint_summary.md # machine-maintained continuity context
  project_runtime-docs.md
  reference_session-events.md
  _system/
    dreaming/
    ...

<workspace>/.compozy/agents/<agent>/memory/
  MEMORY.md
  user_pedro-style.md
  _system/
    ...

_system/ is reserved. Curated indexing skips it, recall filters it out by default, and the controller rejects any write that would land directly in a top-level _system_*.md file. Operators can browse _system/ artifacts explicitly with --include-system on list/show/search/etc.

The Write Controller

Every write — CLI, HTTP, UDS, native tool, extractor, dreaming, file-watcher, provider — passes through the controller:

  1. Caller submits a Candidate { workspace_id, scope, agent, agent_tier, origin, frontmatter, content, ... }.
  2. The controller computes a deterministic decision with rule-first lexical+entity-slot logic; an LLM tiebreaker runs only when the rule trace falls in the configured ambiguity band.
  3. The decision is persisted to memory_decisions (per-database WAL) before any file mutation, carrying full replay material: target_filename, frontmatter, post_content, post_content_hash, prior_content (for update/delete), idempotency_key, and the rule/LLM trace.
  4. The file mutation lands atomically; the catalog reindexes the affected file; a canonical memory_events row is appended.
  5. On crash, daemon boot replays unapplied decisions in decided_at order. Replay is idempotent by idempotency_key and post_content_hash.

There is exactly one write path. Controller-bypassing tools are forbidden; provider-supplied tools that collide with reserved names are rejected at registration with a memory.provider.collision event.

Atomic native-tool batches

compozy__memory_propose accepts operations when an agent needs to change several parts of one Memory v2 document as a unit. The batch is closed to three body operations:

ActionRequired fieldsEffect
addcontentAppends one Markdown block unless that exact block already exists.
replaceold_text, contentReplaces old_text when it occurs exactly once in the staged body.
removeold_textRemoves old_text when it occurs exactly once in the staged body.

Operations run in array order against an in-memory body. A missing or ambiguous old_text, an invalid operation shape, unsafe content, or an oversized final body rejects the whole batch before a decision is written. Compozy checks [memory.file] max_lines and max_bytes only against the final body, so one call can remove stale content and add a replacement even when the current file is at capacity.

{
  "scope": "workspace",
  "workspace": "01HXJ9YR4Q...",
  "filename": "project_release.md",
  "operations": [
    {
      "action": "remove",
      "old_text": "The release still uses the retired deploy path."
    },
    {
      "action": "add",
      "content": "The release uses the signed artifact deploy path."
    }
  ]
}

The result becomes one controller decision and one Markdown mutation; no earlier operation can land by itself. Retrying the same payload returns the existing decision and marks each operation already_applied. operations cannot be mixed with the single-write operation or top-level content fields. Batch support is currently agent-manageable through compozy__memory_propose; the CLI and HTTP/UDS entry-write shapes remain single-document replacements.

Frozen Snapshot And Recall

At session start, Compozy captures a frozen snapshot of the resolved memory context (global, workspace, and the agent's two tiers when applicable). The snapshot includes:

  • the per-scope MEMORY.md index after staleness banners
  • a packaged recall block produced by the deterministic recall pipeline (FTS5 unicode + trigram, scope shadow, top-K) when a contextual query is available
  • a freshness banner for entries whose age exceeds memory.recall.freshness.banner_after_days

Snapshots are cached by session boot request and memory generation. Repeating the same assembly request without a memory mutation returns byte-identical prefix content. A committed write, delete, or reindex advances the shared generation; the next assembly captures the new index once and then remains byte-identical at that generation. Compozy does not rewrite a system prompt already delivered to an ACP subprocess, so a running session keeps that delivered prompt and the next session receives the new snapshot. Sub-agent sessions inherit the parent snapshot read-only.

_system/ artifacts are never injected into the prompt by default. Recall skips ledger files, extractor inbox/DLQ artifacts, and dreaming output unless the caller explicitly opts in.

Workspace Checkpoint Continuity

Compozy maintains one workspace-scoped project memory at <workspace>/.compozy/memory/project_checkpoint_summary.md. After an eligible user, coordinator, or dream session stops, the active workspace memory provider receives a bounded transcript projection. The bundled local provider updates the previous checkpoint instead of regenerating it from scratch. The file keeps the 32 most recent unique source-session IDs in provenance.

Checkpoint writes use the same controller and memory_decisions WAL as operator and agent writes. Ordinary memory proposals and generated checkpoint summaries reject raw compozy_claim_* tokens before persistence. Malformed, oversized, raw-token-bearing, or failed generations leave the previous checkpoint unchanged. Inspect or revert its decisions through the existing surfaces:

compozy memory show project_checkpoint_summary.md --scope workspace
compozy memory decisions list --filename project_checkpoint_summary.md -o json
compozy memory decisions revert <decision-id>

New sessions receive the complete checkpoint in a <compozy_checkpoint_summary> block after their frozen memory indexes. When ACP session loading is unavailable or its saved provider session is missing, degraded resume places that checkpoint before the pruned transcript replay. The block is reference-only historical context: it cannot replace the current user request. Workspace identity is resolved explicitly on both write and injection paths, so one workspace's checkpoint cannot enter another workspace's prompt.

Pressure compaction coverage

When an ACP usage update reaches [session.compaction].pressure_threshold, Compozy selects only the complete persisted turns before the triggering turn. The active memory provider summarizes that sequence span into the workspace checkpoint and records hidden (workspace, session, from, to) coverage before the session store marks the rows archived. Repeating the same span is idempotent: existing coverage prevents duplicate provider work while still allowing an interrupted archive to finish.

Archiving is non-destructive. compozy session events and compozy session history retain the rows for forensics, while degraded replay excludes archived rows so it does not re-inject context already covered by the checkpoint. A successful provider session/load keeps using provider-owned context. If a daemon stops after checkpoint coverage but before archive, the original events remain unarchived and readable; Compozy never archives first and hopes a later summary succeeds.

Operator And Agent Surfaces

Memory is reachable from CLI, HTTP, UDS, and native tools with parity. The Slice 1 verbs are:

CapabilityCLIHTTP / UDSNative tool
List entriescompozy memory list [--type/--sort/--cursor/--limit]GET /api/memory?type=&sort=&cursor=&limit=compozy__memory_list
Show one entrycompozy memory show <filename>GET /api/memory/{filename}compozy__memory_show
Search recallcompozy memory search <query>POST /api/memory/searchcompozy__memory_search
Operator writecompozy memory writePOST /api/memoryn/a
Editcompozy memory edit <filename>PATCH /api/memory/{filename}compozy__memory_propose
Deletecompozy memory delete <filename>DELETE /api/memory/{filename}compozy__memory_propose
Agent proposaln/acontroller-backed via POST /api/memory / PATCH /api/memory/{filename}compozy__memory_propose (single write or atomic body batch)
Ad-hoc noten/aPOST /api/memory/ad-hoccompozy__memory_note
Dream triggercompozy memory dream triggerPOST /api/memory/dreams/triggercompozy__memory_dream_trigger
Dream listingcompozy memory dream show <date-or-run-id>GET /api/memory/dreams, GET /api/memory/dreams/{dream_id}compozy__memory_dream_list, compozy__memory_dream_show
Dream retrycompozy memory dream retry <run_id>POST /api/memory/dreams/{dream_id}/retrycompozy__memory_dream_retry
Dream statuscompozy memory dream statusGET /api/memory/dreams/statuscompozy__memory_dream_status
Decisions listcompozy memory decisions list [--filename <file>]GET /api/memory/decisions[?filename=<file>]compozy__memory_decisions_list
Decision detailcompozy memory decisions show <id>GET /api/memory/decisions/{decision_id}compozy__memory_decisions_show
Decision revertcompozy memory decisions revert <id>POST /api/memory/decisions/{decision_id}/revertcompozy__memory_decisions_revert
Recall tracecompozy memory recall trace <session_id> <turn_seq>GET /api/memory/recall-traces/{session_id}/{turn_seq}compozy__memory_recall_trace
Historycompozy memory historyGET /api/memory/historycompozy__memory_admin_history
Healthcompozy memory healthGET /api/memory/healthcompozy__memory_health
Config metadatan/aGET /api/memory/confign/a
Reindexcompozy memory reindexPOST /api/memory/reindexcompozy__memory_reindex
Promotecompozy memory promote --from <scope[:tier]> --to <scope[:tier]>POST /api/memory/promotecompozy__memory_promote
Resetcompozy memory resetPOST /api/memory/resetcompozy__memory_reset
Reload snapshotcompozy memory reloadPOST /api/memory/reloadcompozy__memory_reload
Scope inspectorcompozy memory scope-showGET /api/memory/scope-showcompozy__memory_scope_show
Daily logscompozy memory daily lsGET /api/memory/dailycompozy__memory_daily_list
Extractor statuscompozy memory extractor statusGET /api/memory/extractor/statuscompozy__memory_extractor_status
Extractor failurescompozy memory extractor list-pendingGET /api/memory/extractor/failurescompozy__memory_extractor_failures
Extractor replaycompozy memory extractor replay --session <id>POST /api/memory/extractor/retrycompozy__memory_extractor_retry
Extractor draincompozy memory extractor drainPOST /api/memory/extractor/draincompozy__memory_extractor_drain
Provider listcompozy memory provider listGET /api/memory/providers, GET /api/memory/providers/{provider_name}compozy__memory_provider_list, compozy__memory_provider_get
Provider selectn/aPOST /api/memory/providers/selectcompozy__memory_provider_select
Provider enablecompozy memory provider enable <name>POST /api/memory/providers/{provider_name}/enablecompozy__memory_provider_enable
Provider disablecompozy memory provider disable <name>POST /api/memory/providers/{provider_name}/disablecompozy__memory_provider_disable
Session ledgern/aGET /api/workspaces/{workspace_id}/memory/sessions/{session_id}/ledgercompozy__memory_session_ledger
Session replayn/aPOST /api/workspaces/{workspace_id}/memory/sessions/{session_id}/replaycompozy__memory_session_replay
Session prunen/aPOST /api/memory/sessions/prunecompozy__memory_sessions_prune
Session repairn/aPOST /api/memory/sessions/repaircompozy__memory_sessions_repair

Entry writes from agents still route through compozy__memory_propose and compozy__memory_note; both go through the controller. The operational tools live in the separate compozy__memory_admin toolset and mirror the daemon CLI/API surfaces. There is no compozy__memory_read, no compozy__memory_history, no raw compozy__memory_write, no raw compozy__memory_edit, no raw compozy__memory_delete, no compozy memory read, and no compozy memory consolidate in this slice — the renamed verbs above own the same intent.

CLI verbs accept -o json and -o jsonl for structured output. Errors are deterministic {code, message, details} payloads with stable codes such as memory.scope.invalid, memory.controller.timeout, and memory.provider.collision.

MEMORY.md Indexes

The per-scope MEMORY.md is the prompt-safe table of contents. [memory.file] max_lines = 200 and max_bytes = 25600 cap both a controller-authored document body and the index content included in the snapshot. Useful index entries are short and point to one file:

- [Review Style](user_review-style.md) — User wants concise review findings with file references first.
- [Runtime Docs Location](project_runtime-docs.md) — Runtime docs live under `packages/site/content/runtime/`.
BehaviorCurrent implementation
Missing MEMORY.mdCompozy synthesizes an index from memory-file frontmatter for that scope and warns when an existing index is stale.
Prompt limitsIndex injection is capped by [memory.file] max_lines and max_bytes.
Write behaviorController writes the file, updates the WAL, reindexes the catalog, and re-renders the scope index so new entries are discoverable.
Delete behaviorDeleting a memory file also removes index lines that link to that filename and emits memory.write.committed with op delete.
Full entry contentNot injected. Agents fetch full entries on demand with compozy memory show <filename> or compozy__memory_show.

Observability

Every controller decision and recall outcome is observable.

SurfaceUse it for
compozy memory healthEnabled state, controller backlog, provider circuit state, dreaming gate status, and per-scope catalog/file counts.
compozy memory decisions list [--filename <file>]The Slice 1 truthful audit log. Filename filtering happens before --limit, so one file's recent decisions are not displaced by newer decisions for another file.
compozy memory recall trace <session_id> <turn_seq>The deterministic recall pipeline trace for a specific session turn: candidate set, scoring weights, freshness banners, and shadow-by-id outcomes.
compozy memory extractor statusQueue and useful-work diagnostics: queued/in-flight sessions, active provider sessions, backpressured sessions, coalesced/dropped turns, skipped empty turns, and failure count.
GET /api/memory/healthSame data as compozy memory health over HTTP/UDS.
GET /api/memory/decisions[?filename=<file>]Same data as compozy memory decisions list with redaction-safe payloads; filename is applied before limit (no post_content, prior_content, or raw LLM responses on the wire).
GET /api/memory/recall-traces/{session_id}/{turn_seq}Same data as compozy memory recall trace over HTTP/UDS.
GET /api/memory/extractor/statusSame extractor queue and useful-work diagnostics over HTTP/UDS.

memory_events rows have stable canonical op names (memory.write.committed, memory.write.rejected, memory.recall.executed, memory.dream.run.promoted, memory.extractor.completed, memory.provider.collision, etc.). They are queryable through the event store and feed compozy memory health and the web Memory inspector.

Skipped empty extractor turns are recorded as memory.extractor.dropped with metadata.reason = "empty_snapshot" and redaction-safe counters only. Extractor completion events carry candidate_count, and controller write decisions remain under memory.write.*.

compozy memory history returns the same audit material in the legacy summary shape as a thin compatibility view over memory_events. Use compozy memory decisions list when you need controller-level detail.

Basic Usage

Write a global preference (operator-only):

compozy memory write \
  --scope global \
  --type user \
  --name "Review Style" \
  --description "User wants concise review findings with file references first" \
  --content "Put blocking findings first. Cite file paths and symbols."

Write a workspace decision in the current workspace:

compozy memory write \
  --scope workspace \
  --type project \
  --name "Runtime Docs Location" \
  --description "Runtime docs live in the Fumadocs runtime collection" \
  --content 'Runtime docs are authored under `packages/site/content/runtime/` and build to `/runtime/*`.'

Write to a specific agent tier:

compozy memory write \
  --scope agent \
  --agent reviewer \
  --agent-tier global \
  --type feedback \
  --name "Reviewer Tone" \
  --description "Reviewer keeps findings short and actionable" \
  --content "Lead with the blocker. Cite file:line. Keep lists tight."

List and show:

compozy memory list
compozy memory list --scope workspace --type project --sort name --limit 50 -o json
compozy memory show project_runtime-docs.md --scope workspace

Memory lists are counted cursor pages. Filtering and sorting happen before the page cut; JSON and native-tool results expose page.total, the normalized page.limit, page.has_more, and an opaque page.next_cursor. Reuse that cursor only with the same selector, type, and sort. The default page size is 50 and the maximum is 200. _system/ entries remain excluded unless include_system is explicitly enabled.

Search recall:

compozy memory search "review tone" --scope agent --agent reviewer --agent-tier global

Trigger a gated dreaming pass:

compozy memory dream trigger
  • Scopes explains scope selection, agent-tier rules, and shadowing.
  • Dream explains gates, signals, and what dream trigger actually changes.
  • Memory Best Practices gives concrete writing and hygiene guidance.
  • Memory CLI Reference lists every generated memory command.

On this page