FAQ¶
Applies to: CPersona 2.5.x. Seeded from real questions asked by production operators (anonymized). Short answers here; the canonical detail lives in Behavior Contracts and the Operations Runbook.
Why does recall return the best match last?¶
Deliberate contract: results are ordered by ascending score so the strongest
memory sits at the end of the injected context, where LLMs attend most
strongly ("lost in the middle"). If you evaluate hit@k, index from the tail —
measuring from the head inverts your numbers. recall_with_context is
different: it returns a chronological merge.
→ Contract §1
My newest decisions keep losing to older ones. How do I make recency win?¶
In priority order:
- Don't bet must-win facts on recall at all — put the current decision in
a deterministically injected surface (
CLAUDE.md/ system prompt) and use memory for what is asked for, not what must always fire. - Overwrite, don't append:
update_memorythe superseded decision. A stale decision that no longer exists cannot win. - Then, optionally, enable
CPERSONA_CONFIDENCE_ENABLED=true— it blends time decay into the ranking. Be aware it takes over ordering and the quality gate from the fusion mode, and runcalibrate_thresholdonce after switching. Fine-grained recency ranking (recency-weighted search) is planned for the 2.6 line.
Is CPERSONA_CONFIDENCE_ENABLED=false a "temporarily disabled" feature?¶
No — it is a conservative shipping default, not a disabled-because-broken
flag. Confidence changes ranking semantics, so it ships opt-in. It is used in
production (the maintainer's own instance runs rsf + confidence on). If you
enable it, know that it re-sorts results and re-keys the quality gate —
→ Contract §2.
How do I keep an index of Markdown files in sync with CPersona?¶
There is no built-in file watcher or upsert — CPersona is a passive server
and ingestion is caller-driven. Two supported patterns: (A) a dedicated
agent_id for the index, rebuilt wholesale on change (recommended first —
provably in sync, no diff logic), or (B) caller-side content-hash ledger with
update_memory for changed chunks. The one trap: re-storing changed
content under the same msg_id is silently skipped, not updated.
→ Corpus indexing patterns
What should I tune for a Japanese (or other CJK) corpus?¶
CPERSONA_RECALL_MODE=rsf, and that's it — the rsf mode exists largely to
compensate for FTS5's weak CJK tokenization. Expect the default embedding
model to be strong when query and memory share a proper-noun/identifier
anchor and weaker on pure concept matches; phrasing queries with a concrete
anchor term is the right adaptation.
→ Japanese / CJK corpora
Recall returns too few results. Which knob actually widens the gate?¶
set_recall_precision(agent_id, "lenient") — under the default fusion modes
it is effectively the only policy knob. CPERSONA_AUTOCUT_MIN_RESULTS does
nothing under rsf/rrf (autocut is deliberately inert on rank-fusion
scores), and disabling the fused gate entirely is a last resort.
→ Tuning recall
What happens when the corpus grows past CPERSONA_MAX_MEMORIES?¶
Nothing is deleted and nothing breaks: the constant is the vector scan window, not a storage cap. Rows older than the window stay reachable via the FTS and keyword channels. For a large corpus, raise the env var — that is the supported knob; no archival routine is needed. → Contract §4
How often should archive_episode run, and does bulk backfill hurt?¶
Intended cadence: one episode per session, at session end. The episode
boundary penalty softly prefers current-session memories (halving older ones
at the floor) — and its boundary is simply the newest episode's timestamp, so
bulk-importing historical conversations moves the boundary to import time
and penalizes everything older. Don't backfill episodes, or disable the
penalty (CPERSONA_EPISODE_PENALTY_ENABLED=false) while you do.
→ Contract §3
Does lock_memory make a memory rank higher?¶
No. Lock protects against deletion and editing; ranking is unaffected, and a
locked memory can still lose a recall. "Must never be lost" → lock. "Must
always be in context" → deterministic injection. The profile
(update_profile) is only a reliable always-surfaces channel when confidence
scoring is on — with it off, profile rows carry no score and are cut by
limit on a full corpus.
→ Contract §7 /
§9
Do I need to configure the operating context?¶
Not for single-client, single-agent setups — leaving it unconfigured is the
correct state, not a gap. operating-context.toml exists for operators who
run several MCP clients against one server and want to distribute shared
operating instructions and a project-id registry to all of them.
→ OPERATING_CONTEXT_DESIGN
How do I back up the database safely?¶
Not with a plain cp while the server runs (WAL). Use
sqlite3 ... ".backup ..." or VACUUM INTO, or stop the server and copy the
.db with its -wal/-shm siblings; complement with a monthly
export_memories JSONL. Keep the live DB out of cloud-sync folders.
→ Backup & restore
How do I notice the embedding server died?¶
You don't have to catch it yourself: degraded recalls carry an advisory
field (instruct your agent to surface it), a store that writes a row reports
embedded: true|false, and check_health(fix=true) repairs rows written during
the outage. Do not poll embedded alone: a skipped or rejected store omits
the key, so re-storing content the corpus already has tells you nothing about
the encoder. Note that a green check_health alone does not prove the endpoint is
up.
→ Detecting a dead embedding server
Will CPersona ever merge or summarize memories with an LLM?¶
No. The server never calls a generative model is a core, unchanging
invariant — embedding calls are the only model traffic, so memory itself adds
no API cost and stays deterministic. Retrieval-side features planned for
future lines stay within deterministic SQL + pure-function processing, return
reference-traceable results rather than generated text, and never modify or
replace the underlying memories. Semantic summarization remains the calling
agent's job (archive_episode is where its results land).