> ## Documentation Index
> Fetch the complete documentation index at: https://comis-fix-skill-import-vetting-gate.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Memory configuration

> Every Comis memory capability and the exact config option that enables it: recall, outcome signals, governed learning, and maintenance

**What this page is.** The complete reference for Comis's agent-memory capabilities and the
exact config option for each. **The memory features are ON by default (opt-out)**; a fresh
install runs them and you edit config to turn them off. The trust boundary
(`rag.scoring.trustAlpha`, `rag.includeTrustLevels`) is **frozen**, not a tunable capability.

<Warning>
  The LLM **build/ask** features (the session review job, the one learning-reflection cron,
  and the `memory_ask` grounded-Q\&A tool) spend **your own** LLM/API budget. They are on by
  default, and the daemon prints a first-run notice listing what's active.
  **One line turns all of them off:** `memory.enabled: false`.
</Warning>

<Note>
  The master kill-switch is `memory.enabled`, and the three recall model knobs nest under
  `memory.recall.*`. The whole per-agent learning layer is **one** `agents.<id>.learning`
  block (one `learning.enabled` flag + `learning.reflect.*` + `learning.forget.*`).
</Note>

**Where the config lives.** Capabilities are configured **per agent** under
`agents.<agentId>.` in `~/.comis/config.yaml`. The shared **memory engine** (store +
embeddings + reranker + the cost kill switch) is the top-level `memory:` block. The config
below is the **effective default** — set any `enabled: false` to opt a feature out.

<Note>
  On by default is necessary but not always sufficient; several capabilities also need
  *built derived state* (a populated graph, scored usefulness) before they change recall. See
  [Dependencies & gotchas](#dependencies--gotchas) below.
</Note>

## Default config (opt-out)

This is the **effective default** a fresh install runs. To opt out, set the relevant
`enabled: false` (or flip the master `memory.enabled: false` to silence all LLM-cost features
at once).

```yaml theme={}
# ─────────────────────────────────────────────────────────────────────────
# 1. MEMORY ENGINE (top-level) — the substrate every capability runs on
# ─────────────────────────────────────────────────────────────────────────
memory:
  enabled: true                     # MASTER KILL SWITCH — set false to disable ALL LLM cost features at once
  dbPath: memory.db
  walMode: true
  recall:                           # the $0 on-device recall substrate — NOT gated by `memory.enabled`
    embeddingModel: text-embedding-3-small   # hosted (1536d). Point at a local GGUF for on-device.
    embeddingDimensions: 1536
    rerankerModel: "hf:gpustack/bge-reranker-v2-m3-GGUF:bge-reranker-v2-m3-Q8_0.gguf"  # local by default
  rerankerModelsDir: models
  rerankerGpu: auto                 # auto | metal | cuda | vulkan | false
  rerankerThreads: 4
  compaction: { enabled: true, threshold: 1000, targetSize: 500 }
  retention: { maxAgeDays: 0 }      # 0 = keep forever

agents:
  my-agent:
    # ───────────────────────────────────────────────────────────────────
    # 2. RECALL + RECALL-TIME CAPABILITIES  (agents.<id>.rag)
    # ───────────────────────────────────────────────────────────────────
    rag:
      enabled: true                 # recall is ON by default
      maxResults: 5
      minScore: 0.1
      includeTrustLevels: [system, learned]   # trust filter — FROZEN (see Trust note)
      rerank:
        enabled: true               # default false; cross-encoder rerank (local bge)
        maxCandidates: 40
        minResults: 1
        timeoutMs: 800
      scoring:                      # ranking weights, each 0..1
        recencyAlpha: 0.2
        temporalAlpha: 0.2
        proofAlpha: 0.1
        trustAlpha: 0.1             # FROZEN — leave at the shipped value
        usefulnessAlpha: 0.1        # magnitude of the recall-utility (FEED) loop
        forgetAlpha: 0.1            # magnitude of the recall-score decay (FORGET)
      lanes:
        fts: { weight: 1.0 }
        vector: { weight: 1.5 }
        temporal: { enabled: true, weight: 1.0, windowDays: 7 }            # default off
        causal:   { enabled: true, weight: 1.0 }                           # default off
        graphSpread: { enabled: true, weight: 1.0, maxDepth: 2, fanOut: 8 } # KG lane — default off
      entityLane: { enabled: true, seedCount: 5, perEntityCap: 200, weight: 1.0 }  # default off
      mmr: { enabled: true, lambda: 0.7 }       # MMR diversity re-rank — default off
      feedback: { enabled: true }               # FEED recall-utility loop (uses scoring.usefulnessAlpha)
      forget: { enabled: true }                 # recall-score decay gate (uses scoring.forgetAlpha)
      queryUnderstanding:                       # LEARN-IQ (LLM-free)
        intentReweight: true
        synonyms: true
        temporalParse: true

    # ───────────────────────────────────────────────────────────────────
    # 3. OUTCOME SIGNAL + the ask tool
    # ───────────────────────────────────────────────────────────────────
    learningOutcome:                 # fused outcome signal used by reflection + forgetting
      enabled: true                  # default ON (opt-out)
      judge: { enabled: true }       # cost-gated LLM fallback for a conversational turn
      correction: { enabled: true }  # cost-gated correction detector; a signal is not an automatic demotion

    dialectic:                       # memory_ask grounded-Q&A tool (the one query-time LLM surface)
      enabled: true
      maxOutputTokens: 1024
      maxRecall: 10

    # ───────────────────────────────────────────────────────────────────
    # 4. MAINTENANCE / LIFECYCLE JOBS (cron-driven)
    # ───────────────────────────────────────────────────────────────────
    memoryReview:                    # session → memory review + dedup (accumulate tier)
      enabled: true
      schedule: "0 2 * * *"
      minMessages: 5
      maxSessionsPerRun: 50            # best-out-of-box: broader consolidation coverage per run
      maxReviewTokens: 16384           # best-out-of-box: richer consolidation per session

    memoryLifecycle:                 # the FORGET sweep cron — TRIMMED to enable + schedule
      enabled: true
      schedule: "0 9 * * *"          # the __LIFECYCLE__ sweep slot (keyless; thresholds live in learning.forget)

    # ───────────────────────────────────────────────────────────────────
    # 5. LEARNING — the one outcome-gated reflection engine (~10 keys)
    # ───────────────────────────────────────────────────────────────────
    learning:
      enabled: true                  # ONE master gate for the WHOLE learning layer (opt-out; force-disabled by memory.enabled: false)
      reflect:                       # the one __REFLECT__ cron (skill + profile + topic in one pass)
        schedule: "0 */3 * * *"      # best-out-of-box: every 3 hours (near-real-time learning)
        minConfidence: 0.6           # reflection-side confidence floor [0..1]
        promoteAtProofCount: 3       # attributed reuse-success count for candidate-to-active promotion
        maxDocsPerRun: 100           # finite DoS bound, set high so it does not throttle learning
        maxProcedureDocsSurfaced: 10 # per-agent cap on orchestrate-derived procedure docs in <available_skills> (the scaling guard)
        corroboration:               # HOW a topic must corroborate before it can seed a learned doc
          mode: single_owner         # default: repetition by one explicitly named owner; not independent corroboration
          minObservations: 2         # single_owner only: minimum repeated success-labeled observations
      forget:                        # the wrongness-based soft-eviction policy (the __LIFECYCLE__ sweep reads these)
        maxDormantDays: 365          # best-out-of-box: remember ~a year (forget pure-disuse less)
        failureEvictionFloor: 3      # corroborated failure_count at/above which a non-exempt memory is soft-evicted
        highProofFloor: 5            # high-proof exemption — a memory at/above this proof count is never failure-evicted
```

## Capability → config map

| Capability                | Enable knob (`agents.<id>.`)                                            | What it does                                                                                                    |
| ------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Recall (base)             | `rag.enabled` *(default true)*                                          | Hybrid FTS + vector recall, fused + scored                                                                      |
| Rerank                    | `rag.rerank.enabled`                                                    | Local cross-encoder rerank of the top candidates                                                                |
| Temporal lane             | `rag.lanes.temporal.enabled`                                            | Recency-window recall lane                                                                                      |
| Causal lane               | `rag.lanes.causal.enabled`                                              | Cause/effect-linked recall lane                                                                                 |
| **KG** graph-spread       | `rag.lanes.graphSpread.enabled`                                         | Walks the knowledge graph from top hits (LLM-free)                                                              |
| Entity lane               | `rag.entityLane.enabled`                                                | Entity-seeded recall expansion                                                                                  |
| MMR diversity             | `rag.mmr.enabled`                                                       | Maximal-marginal-relevance diversification                                                                      |
| **FEED** loop             | `rag.feedback.enabled`                                                  | Boosts memories that proved useful (`scoring.usefulnessAlpha`)                                                  |
| **LEARN-IQ**              | `rag.queryUnderstanding.intentReweight` (+ `synonyms`, `temporalParse`) | LLM-free query understanding / lane reweighting                                                                 |
| **FORGET** (recall decay) | `rag.forget.enabled`                                                    | Per-type score decay demotes stale memories at recall (`scoring.forgetAlpha`)                                   |
| Outcome signal            | `learningOutcome.enabled`                                               | Records and fuses configured outcome observations used by reflection and forgetting                             |
| **DIALECTIC**             | `dialectic.enabled`                                                     | The `memory_ask` grounded-Q\&A tool (query-time LLM)                                                            |
| Review                    | `memoryReview.enabled`                                                  | Turns sessions into reviewed memories (accumulate tier)                                                         |
| Lifecycle sweep           | `memoryLifecycle.enabled`                                               | The keyless `__LIFECYCLE__` soft-eviction sweep (thresholds in `learning.forget.*`)                             |
| **LEARN** (reflection)    | `learning.enabled`                                                      | Maintains learned **skill**, per-user **profile**, and **topic** docs, plus soft eviction (`learning.forget.*`) |

## The one learning-reflection engine

Comis's learning layer is **one governed reflection engine**. A single `__REFLECT__`
cron maintains named **Mental Model** docs (`kind: skill | profile | topic`) via
byte-stable delta operations. Skill reflection uses the fused `learningOutcome`
signal instead of text overlap alone. That signal is evidence, not a guarantee
that the task actually succeeded. The whole layer is governed by **one flag**,
`agents.<id>.learning.enabled`, under the master `memory.enabled` switch.

```yaml theme={}
agents:
  my-agent:
    learning:
      enabled: true            # the SINGLE gate for the whole learning layer
      reflect:
        schedule: "0 3 * * *"  # the one reflection cron
        minConfidence: 0.6     # the reflection-side confidence floor
        promoteAtProofCount: 3 # candidate to active after this many attributed success labels
        maxDocsPerRun: 100     # per-run cost bound
        maxProcedureDocsSurfaced: 10 # per-agent surface cap on procedure docs (default 10)
        corroboration:
          mode: distinct_sessions # stricter than the single_owner default
          minObservations: 2   # single_owner only: repeated observations required
      forget:
        maxDormantDays: 365
        failureEvictionFloor: 3
        highProofFloor: 5
```

* **Reflection (`learning.reflect.*`)** -- for skill docs, the `__REFLECT__`
  cron clusters trusted-origin trajectories whose configured outcome resolver
  reports `success`. A fused success label is not independent verification. Mixed
  tool, pipeline, judge, reaction, or correction signals can classify a session
  that failed overall as successful. Profile and topic docs are built from the
  eligible `system` and `learned` memory corpus instead of the skill outcome path.
  Every admitted doc is stored at `trust=learned`; this is a policy label and
  trust ceiling, not a claim that the content is reliable.
* **Admission and surfacing** -- a topic must pass the selected corroboration
  mode and the static learned-document validator before admission. Critical
  secret and poison patterns are rejected. Warning-level patterns, including
  some jailbreak-like language, are recorded but can pass. A read-only,
  non-evicted `candidate` can surface in `<available_skills>` before promotion so
  it can receive reuse feedback. `active` remains the higher proof tier. Mutating,
  stale, archived, and evicted docs do not surface.
* **Promotion, correction, and demotion** -- attributed reuse labeled `success`
  increments proof and can promote `candidate` to `active` at
  `promoteAtProofCount`. A recorded correction does not by itself guarantee
  demotion or a durable behavior change. The correction detector must be enabled,
  the prior turn must attribute a surfaced skill, confidence and failure
  corroboration must pass, and the trend must become weakening before a skill
  moves to `stale`. When an accepted profile or topic update supersedes an
  existing doc, the prior body is appended to `history` rather than hard-deleted.
* **Authority and scope** -- learned docs contain advisory Markdown and no
  executable column. The model re-authors any action through its existing tools,
  capability gates, approvals, credentials, and sandbox posture. The learned doc
  adds no execution authority. Reads and writes are scoped to `(tenant, agent)`;
  this is not a per-chat or per-sender recall boundary.
* **Procedure-doc surface budget (`learning.reflect.maxProcedureDocsSurfaced`, default `10`)** --
  a per-agent cap on how many procedure docs surface into one prompt's `<available_skills>`. With
  no ranked top-K at surface time, a burst of procedure docs would otherwise bloat every prompt;
  the budget caps that subset only. When it is exceeded the highest-proof procedure docs
  (highest proof count) keep their slot, surfaced in a stable listing order. User-intent **skill**
  docs and **topic** docs are **unaffected**; they keep a separate, uncapped path.
* **Forgetting (`learning.forget.*`)** -- couples a memory's decay to its outcome-attributed
  `failure_count` and **soft-evicts** a sufficiently
  weak or stale memory: it is marked `evicted_at` (excluded from recall, still resolvable via
  `asOf`/inspect, **reversible**, never hard-deleted). A memory implicated in
  `failureEvictionFloor` (default 3) or more **corroborated** failures is soft-evicted regardless
  of its decayed strength, while a memory at/above `highProofFloor` (default 5) is **exempt**.
  A **corroboration gate** (two distinct-session observations, or one deterministic source, on every
  `failure_count` increment) plus exemptions for pinned / `system` / high-`proof_count` memories
  reduce induced eviction risk. The sweep runs on the keyless
  `memoryLifecycle` cron (`__LIFECYCLE__`).

Recall **ranking** itself is the **fixed `rag.scoring`** fusion (deterministic RRF + the
cross-encoder reranker); there is no learned recall weight.

### Corroboration: single-owner (default) vs distinct-sessions (`learning.reflect.corroboration`)

Before a topic can seed a learned doc it must satisfy the configured admission
gate. The configuration calls both modes corroboration, but they provide
different evidence strength:

* **`mode: single_owner`** (**default**) -- repetition by exactly one sender
  explicitly named in `elevatedReply.senderTrustMap`. The topic can seed after
  `minObservations` success-labeled repetitions (default `2`). These observations
  can come from the same owner and session, so this is **not independent
  corroboration** and does not prove the guidance is correct. It exists so a
  single-owner deployment can learn without requiring another sender.
* **`mode: distinct_sessions`** -- requires at least two distinct
  `(session, sender)` observations. Repeats from one sender in one session count
  once. This is the stricter anti-domination posture, although distinct keys are
  still evidence signals rather than proof of correctness.

<Note>
  The `single_owner` gate excludes unknown senders and senders trusted only by
  `defaultTrustLevel`; repetition counts only for an operator-named sender. If
  two or more explicitly named senders are present, Comis falls back to the
  distinct-sessions gate. These controls reduce who can seed a doc, but they do
  not establish truth. Choose `distinct_sessions` when same-owner repetition is
  not enough for your risk model.
</Note>

The `reflect:funnel` telemetry carries a `singleOwnerCorroborated` count (how many topics
corroborated via repetition this run), so [`comis explain`](/reference/cli#comis-explain) and
[`comis system-health`](/reference/cli#comis-system-health) show the mode is active. An `admitted > 0` run with
`maxClusterCardinality: 1` reads as single-owner learning, not a contradiction.

See [`learning` in config-yaml](/reference/config-yaml#learning-agents-learning) for every key
and default, the [`mental_models`](/operations/data-directory#learned-skills-verified-learning)
and [`memory_usefulness` / `evicted_at`](/operations/data-directory#ranking--forgetting-verified-learning)
storage, and the **counts-only** trajectory telemetry (`reflect:admitted` / `reflect:funnel`
for the reflection funnel; `learning:memory_demoted` / `learning:memory_evicted` for the
forget sweep) surfaced through [`comis explain`](/reference/cli#comis-explain) and
[`comis system-health`](/reference/cli#comis-system-health).

## Strict config schema

The config schema is **strict** (`z.strictObject`): a `config.yaml` that carries an
unrecognized key is **rejected at boot** with a parse error naming the exact key, so a typo
or an unsupported block is pointed straight at the line to fix. A **bare config**
(`memory:`/`agents:` with no learning keys) loads fully-defaulted.

## Dependencies & gotchas

1. **Some capabilities need built derived state, not just the flag:**
   * **KG** (`rag.lanes.graphSpread`) is a no-op until the knowledge graph is populated with
     entities/edges.
   * **FORGET** decay (`rag.forget`) shows up at recall; **eviction** is the `memoryLifecycle`
     sweep — live as **soft, reversible** eviction (`evicted_at`) when `learning.enabled` is on
     (it reads `learning.forget.*`), exempting pinned/system/high-proof memories. See
     [the one learning-reflection engine](#the-one-learning-reflection-engine).
   * **Reflection** needs eligible sources and, for skill docs, enough
     trusted-origin trajectories resolved as `success`. A resolved success is a
     fused signal, not proof that the overall task succeeded. The cron abstains
     when no topic passes its selected admission gate.
2. **`dialectic` (`memory_ask`) spends tokens per ask**; it is the only query-time LLM
   surface in the memory stack. Everything else in recall is LLM-free.
3. **Trust is frozen, not a tunable capability.** `rag.scoring.trustAlpha` and
   `rag.includeTrustLevels` are the trust hard-boundary; leave them at the shipped values.
4. **On by default; watch your spend.** The LLM build/ask features are opt-out so operators
   get the full memory stack from day one; they spend your own budget. Your controls are the
   first-run notice and the master switch `memory.enabled: false` (or per-feature
   `enabled: false`). Measure the effect in your own domain. Comis's reproducible
   methodology and the latest costed results are on the
   [Memory benchmarks](/agents/memory-benchmarks) page.

See also: [Memory](/agents/memory), [Search](/agents/search),
[Embeddings](/agents/embeddings), and [RAG](/agents/rag).
