memos/apps/memos-local-plugin/docs/CONFIG-ADVANCED.md

14 KiB
Raw Permalink Blame History

Advanced configuration

The default config.yaml shipped by install.sh only exposes the handful of fields a user is likely to care about (viewer port, embedding/LLM provider, hub, telemetry, log level). Everything else is controlled by baked-in defaults that match the V7 algorithm spec.

If you need to override any of these, just add the corresponding block to config.yaml. The writer preserves comments and field order, so partial overrides are safe.

What's hidden from the default template (but still honored if you add it)

viewer

viewer:
  port: 18910
  bindHost: 127.0.0.1       # do NOT change unless you know why
  openOnFirstTurn: false

bridge

bridge:
  port: 18911
  mode: stdio               # stdio | tcp

embedding

embedding:
  endpoint: ""              # override cloud provider base URL
  model: "Xenova/all-MiniLM-L6-v2"
  dimensions: 384
  cache:
    enabled: true
    maxItems: 20000

llm

llm:
  endpoint: ""              # override provider base URL
  temperature: 0
  fallbackToHost: true      # retry through the OpenClaw host LLM on failure
  timeoutMs: 45000
  maxRetries: 3

algorithm

Direct mapping to the V7 spec (γ, support, gain, top-K, etc.). Change only if you know what you're doing — defaults are calibrated for the paper.

2026-04 default-tuning note — the L2/L3/Skill thresholds shipped in the V7 paper (minGain=0.1, minPolicies=3, candidateTrials=5) turned out to be too strict for normal interactive usage: real users almost never produce explicit failure cohorts, so the V7 contrast-only gain formula G = mean(V_with) mean(V_without) collapses to ≈ 0 and nothing ever crystallises. Two coordinated changes ship together:

  1. core/memory/l2/gain.ts now anchors the without-set against a neutral 0.5 prior (Beta-binomial shrinkage, pseudocount 5). Useful policies on a single-success path now score G ≈ 0.050.20 instead of ≈ 0; net-neutral / harmful policies stay at ≤ 0 and are archived as before.
  2. The L3 / Skill floors below were lowered to match the new gain distribution: minGain 0.1 → 0.02, minPolicies 3 → 2, candidateTrials 5 → 3, minTraceValue 0.05 → 0.01.

Together these let a focused user reach an L3 world model + first graduated Skill within ~1 week of normal usage instead of essentially never.

algorithm:
  capture:
    maxTextChars: 4000        # per-turn text cap before truncation
    maxToolOutputChars: 2000  # per-tool-call output cap
    embedTraces: true         # vectorize state+action with the embedder
    alphaScoring: true        # ask the LLM to grade each reflection (α ∈ [0,1])
    synthReflections: false   # ask the LLM to WRITE a reflection when missing
    llmConcurrency: 4         # parallel LLM calls per episode
  reward:
    gamma: 0.9                # γ discount factor (V7 §0.6 eq. 4/5)
    tauSoftmax: 0.5           # τ for softmax reweighting in Phase 9 L2 induction
    decayHalfLifeDays: 30     # priority decay half-life (V7 §3.3)
    llmScoring: true          # use rubric LLM for R_human; off = heuristic only
    implicitThreshold: 0.2    # |R_human| threshold for implicit-feedback runs
    feedbackWindowSec: 600    # wait this long after capture.done for explicit feedback (0 disables)
    summaryMaxChars: 2000     # cap on the task summary handed to the scorer LLM
    llmConcurrency: 2         # parallel R_human LLM calls
  l2Induction:
    minSimilarity: 0.65            # cosine floor for trace→policy association
    candidateTtlDays: 30           # TTL for unpromoted rows in l2_candidate_pool
    minEpisodesForInduction: 2     # min distinct episodes to mint a new policy
    minTraceValue: 0.01            # ignore traces whose V < this after backprop
    useLlm: true                   # false = collect candidates but never call l2.induction
    traceCharCap: 3000             # chars per trace handed to the induction prompt
    archiveGain: -0.05             # active policies dipping below this → archived
  l3Abstraction:
    minPolicies: 2                 # min compatible L2s to trigger abstraction
    minPolicyGain: 0.02            # eligible L2 gain floor (paired with shrinkage-anchored gain)
    minPolicySupport: 1            # eligible L2 support floor
    clusterMinSimilarity: 0.6      # cosine cutoff for cluster-and-merge decisions
    policyCharCap: 800             # chars per policy in the prompt
    traceCharCap: 500              # chars per evidence trace in the prompt
    traceEvidencePerPolicy: 1      # evidence traces per policy in the prompt
    useLlm: true                   # false = collect clusters but never call l3.abstraction
    cooldownDays: 1                # debounce per primary domain tag (0 = disable)
    confidenceDelta: 0.05          # confidence step per merge / human thumb
    minConfidenceForRetrieval: 0.2 # Tier-3 hides WMs below this
  skill:
    minSupport: 2                  # min distinct-episode support to crystallize
    minGain: 0.02                  # min policy gain to crystallize (with the new shrinkage-anchored formula)
    candidateTrials: 3             # trials to transition out of `candidate` (legacy docs called this `probationaryTrials`)
    cooldownMs: 60000              # debounce between crystallize runs for a policy
    traceCharCap: 600              # chars per evidence trace in the crystallize prompt
    evidenceLimit: 4               # max evidence traces per crystallize call
    useLlm: true                   # false = schedule runs but skip LLM crystallization
    etaDelta: 0.1                  # η step per user.positive/user.negative thumbs
    archiveEta: 0.25               # η floor; crossing archives
    minEtaForRetrieval: 0.5        # η gate for Tier-1 retrieval + auto-promotion
  feedback:
    failureThreshold: 3            # failures in `failureWindow` that trigger a burst (V7 §6.3)
    failureWindow: 5               # rolling tool-call window per (toolId, context)
    valueDelta: 0.5                # |mean(high) - mean(low)| floor before repair fires (V7 §2.4.6 δ)
    useLlm: true                   # false = skip the decision.repair LLM call; template-only
    attachToPolicy: true           # merge the draft into `policy.boundary` @repair block
    cooldownMs: 60000              # debounce between repeat repairs for the same contextHash
    traceCharCap: 500              # chars per evidence trace in the decision-repair prompt
    evidenceLimit: 4               # max high-value / low-value traces per synthesis call
  retrieval:
    tier1TopK: 3            # skills injected at turn start
    tier2TopK: 5            # trace/episode snippets
    tier3TopK: 2            # world-model snippets
    candidatePoolFactor: 4  # poolSize = tierTopK × this, before ranking
    weightCosine: 0.6       # Tier-2 relevance = w_cos·cos + w_pri·priority
    weightPriority: 0.4
    mmrLambda: 0.7          # MMR: λ·rel  (1-λ)·redundancy; 1.0 = pure rel, 0 = pure diversity
    rrfConstant: 60         # k in RRF: score = Σ 1/(k+rank_i)
    minSkillEta: 0.5        # hide Tier-1 skills with η below this
    minTraceSim: 0.35       # hide Tier-2 traces below cosine threshold
    includeLowValue: false  # include priority=0 traces (overridden to true by repair entry)
    tagFilter: auto         # auto | strict | off — pre-filter traces by domain tag
    keywordTopK: 20         # per-tier FTS + pattern channel size (vector channel still uses tier{1,2,3}TopK · candidatePoolFactor)
    relativeThresholdFloor: 0.4
    # Drop ranked candidates whose blended `relevance < topRelevance · this`.
    # Adaptive cousin of `minTraceSim`: a strong query (top relevance 0.9)
    # trims to ≥ 0.36; a weak query (top 0.4) keeps items down to ≥ 0.16.
    # Set to 0 to disable the relative cutoff entirely.
    skillEtaBlend: 0.15     # blend weight for Tier-1 skill `η` (reliability).
    # Default 0.15 — cosine dominates, η is a small nudge so stale-but-
    # well-trodden skills no longer outrank fresh, query-aligned ones.
    smartSeed: true         # MMR seed-by-tier only when tier's best clears the relative floor
    skillInjectionMode: summary  # summary (default) | full
    # summary  → Tier-1 skills land in the prompt as `name + η + 1-line
    #            description + a `memos_skill_get(id="…")` invocation hint`. The
    #            host model loads the full procedure on demand by calling
    #            the `memos_skill_get` tool. Keeps prompts small.
    # full     → Inline the entire `invocationGuide` body (legacy). Use
    #            this if your host doesn't support tool / function calls.
    skillSummaryChars: 200  # char cap for the per-skill summary line
    # (The retrieval-trigger policy — turn-start / tool-driven / repair —
    # is not user-tunable; it's documented in ARCHITECTURE.md §4 and
    # core/retrieval/README.md.)

Tuning cheat-sheet

Symptom Try
Packet dominated by old, off-topic traces Lower weightPriority, raise minTraceSim.
Similar traces keep repeating in packet Lower mmrLambda (0.50.6) for more diversity.
Tag filter suppresses legitimate results Keep tagFilter: auto (fallback kicks in) or set "off".
Too few skills surface after restart / fresh install Lower minSkillEta (0.3); skills start at η=0.5 by default.
Ranker too slow in perf logs Lower candidatePoolFactor (e.g. 3).
L2 induction fires on single-episode loops (noisy) Raise l2Induction.minEpisodesForInduction (e.g. 3).
Useful L2 policies never get promoted to active Lower algorithm.skill.minGain or minSupport.
LLM costs too high during heavy on-ramp Set l2Induction.useLlm: false — candidates still collect.
Active policies churn between activearchived Lower l2Induction.archiveGain (-0.10 for a wider dead-zone).
L3 world models never get created Confirm at least 2 policies are active and share a domain key; lower l3Abstraction.clusterMinSimilarity (0.50.55) if the domain is heterogeneous.
Too many near-duplicate world models Raise l3Abstraction.clusterMinSimilarity (0.650.7).
Low-confidence world models leak into retrieval Raise l3Abstraction.minConfidenceForRetrieval.
Skills never graduate from candidate Lower skill.candidateTrials (e.g. 2) or minEtaForRetrieval (e.g. 0.4).
Skills churn between activearchived Lower skill.archiveEta (0.15) or raise etaDelta damping.
Verifier rejects most drafts with "coverage-low" Raise skill.traceCharCap/evidenceLimit so more evidence reaches the verifier.
Verifier rejects drafts with "resonance-low" Confirm CJK tokenization is enabled (verifier supports CJK bigrams since 2026-04); otherwise lower the implicit minResonance.
Too few skills surface — retrieval empty Lower skill.minSupport (1) or minGain (0.0).
Agent ignores obvious failure loops (≥3 tries) Lower feedback.failureThreshold (2) or failureWindow (3).
"value-delta-low" keeps skipping valid repairs Lower feedback.valueDelta (0.3) — it's the §2.4.6 δ floor.
Decision-repair table fills with near-duplicates Raise feedback.cooldownMs (e.g. 300000 = 5 min).
Repair guidance never reaches skills Check feedback.attachToPolicy: true and that the source
policies are active; only active policies get tagged.
Template-only repairs feel generic Set feedback.useLlm: true and confirm the LLM provider works.

hub

hub:
  role: client              # hub | client
  port: 18912
  teamName: ""
  nickname: ""

logging

logging:
  console:
    enabled: true
    pretty: true
    channels: ["*"]
  file:
    enabled: true
    format: json             # json | compact
    rotate:
      maxSizeMb: 50
      maxFiles: 14
      gzip: true
    retentionDays: 30        # app/error files
  audit:
    enabled: true
    rotate:
      monthly: true
      gzip: true
    # Note: audit/llm/perf/events are kept FOREVER by design. If you really
    # need to prune them, gzip them out of logs/ by hand.
  llmLog:
    enabled: true
    redactPrompts: false
    redactCompletions: false
  perfLog:
    enabled: true
    sampleRate: 1.0
  eventsLog:
    enabled: true
  redact:
    extraKeys: ["api_key", "secret", "token", "password", "authorization"]
    extraPatterns: []
  channels: {}               # per-channel level overrides, e.g. "core.l2.cross-task": debug

Resetting to defaults

Delete the block in config.yaml. On next load the schema's default value kicks in.

Environment-variable overrides (dev/test only)

Env var Effect
MEMOS_HOME Overrides the whole runtime home. All paths recomputed from it.
MEMOS_CONFIG_FILE Overrides only the config file path.

These are intentionally undocumented in user-facing docs — they're meant for tests and CI, not day-to-day configuration.