Tools¶
Applies to: CPersona 2.6.x. The authoritative description of every argument is the tool's own MCP description: your client reads it, and it ships with the version you are running. This page groups every tool by what you use it for, and links to the contract whenever a tool behaves in a way its name does not suggest.
Everyday memory¶
| Tool | What it does |
|---|---|
store |
Write one memory. Since 2.6.6 the text goes in content; on a connection whose ACL grants write access to exactly one agent, agent_id may be omitted (the agent used comes back as resolved_agent_id); source defaults to the writing agent, and lock: true locks the memory in the same call. The message={content, id, source, timestamp, metadata} form of earlier versions is still accepted, with its own defaults. A [Memory from …] annotation, the stamp early versions put on recalled text, is removed wherever it appears. Branch on result — stored / skipped / rejected — not on ok (dedup contract) |
recall |
Retrieve memories through the three-layer hybrid search. The last element is the best match (ordering contract). With trace: true it also returns a record of what each stage kept, dropped and reordered, with references and scores but no stored text (recall trace). With time_cue the caller says when the answer was stored, with a confidence; rows found in that period move up by a bounded number of places and up to three seats (3 / 2 / 1 by confidence) hold records that search found which the answer does not hold, without changing which rows pass the quality gate (time cue) |
recall_with_context |
Recall and merge with conversation history you pass in, deduplicated. Returns a chronological merge, not a score ordering |
get_contents |
Expand preview refs (mem:<id> / ep:<id>) returned by recall into full text (preview tier design). A ref can also name part of its record — overflow-tree nodes or a character span — so a reconstruct quote expands to its neighbours rather than the whole record |
reconstruct |
Assemble recall items from the candidate rows a recall produces: select, order and assign roles, never compose. count is a ceiling, not a fill target and not a search depth; breadth (top_k, max_hops, max_evidence) is a separate set of bounds (the exit). Declared associations add alias cues to the keyword search, bundle related records and add walked evidence inside items (contract) |
archive_episode |
Store a session summary. Also moves the episode boundary, which down-weights earlier records only when CPERSONA_EPISODE_PENALTY_ENABLED is on (it is off by default) |
update_memory |
Correct the content of an existing memory. Use this, not a re-store with the same msg_id |
declare_associations |
Declare associative memory after the fact — entities with aliases, and subject–predicate–object relations — anchored to a record you name; retract removes declarations. The same object rides on store as associations. Stored verbatim and read by reconstruct (associative memory design) |
traverse |
The neighbourhood of a declared entity, as a graph: its aliases, the relations declared on it and on what they reach up to max_hops, and the refs of the records that mention each entity. No record text; limit bounds entities and refs per entity (associative memory design) |
Profile and operator context¶
| Tool | What it does |
|---|---|
get_profile |
Read the accumulated user/project profile for an agent |
update_profile |
Replace the profile with a summary you computed. CPersona never writes it for you — see zero LLM dependency |
get_operating_context |
Read the operator-owned instructions served to every connected client. Read-only over MCP; edited on the filesystem (design) |
Profile rows are injected into recall responses but
carry no score. That
matters when you tighten limit.
Browsing¶
| Tool | What it does |
|---|---|
list_memories |
Recent memories, newest first — no search, no scoring |
list_episodes |
Archived episodes, newest first |
get_queue_status |
Depth and retry state of the background task queue |
Protection and deletion¶
| Tool | What it does |
|---|---|
lock_memory |
Refuse edits and deletes on a memory. It is protection, not a ranking boost (contract) |
unlock_memory |
Lift that protection |
delete_memory |
Delete one memory. Ownership is enforced only when agent_id is passed — omit it and the delete is unscoped and can remove another agent's row (rejected while locked either way) |
delete_episode |
Delete one episode. Same conditional ownership as delete_memory above |
delete_agent_data |
Delete everything belonging to one agent. It is exposed over the network like any other tool, which is reason enough to set CPERSONA_AUTH_TOKEN on the HTTP transport |
Retrieval quality¶
| Tool | What it does |
|---|---|
set_recall_precision |
The main gate knob. Sets an agent's precision preference and recalibrates its post-fusion quality gate — reach for this before touching raw thresholds (tuning order) |
get_recall_precision |
Read the effective precision for an agent |
calibrate_threshold |
Re-derive the vector threshold from the corpus itself. The default method (separation) finds where a null distribution of random pairs separates from same-session positives; percentile and zscore are the alternatives. No labels needed. Run it after a re-embed or a large import |
Portability and migration¶
| Tool | What it does |
|---|---|
export_memories |
Write memories, episodes, profiles and the declared associations (entities, aliases, mentions, relations) to JSONL. It is schema-version independent, so it doubles as a logical backup (backup runbook). A source or metadata value that is not JSON is carried as its own text and restored as it was |
import_memories |
Read that JSONL back, with the declared associations pointed at the restored records. Idempotent, though not by one key: memories dedup on msg_id and on identical content within the project/channel scope, while episodes dedup on an identical summary (they carry no msg_id). A line with a value it cannot store is refused and reported in errors; the rest of the file is restored. An export written by 2.4.37 or earlier carries no project or channel axis, so its rows are restored into the global pool, and errors says how many |
merge_memories |
Move or copy one agent's data into another, declared associations included, atomically and with deduplication |
migrate_channel_axis |
Re-channel bridge-type memories onto their concrete channel, together with the associations declared about them. A one-time repair, not a routine operation |
Health and maintenance¶
| Tool | What it does |
|---|---|
check_health |
Registry-driven check with severity-tagged issues and, with fix=true, auto-repair: contamination, duplicates, FTS integrity, embedding-dimension drift, schema objects, stale tasks, invalid data. Some checks are report-only by design, isolation-axis hygiene among them: which spelling of an axis is canonical is an operator's call, not a repair |
deep_check |
Semantic data-quality pass: anonymous sources, too-short content, stale profiles, orphaned episodes |
get_session_findings |
The same findings, pulled on demand. This is the SuperAuditor pull contract (standard). Whole-database by design (no agent or project filter), read-only, with capped_kinds naming every kind that had more than per_kind_limit rows. A probe that raised shows up as a finding of kind check_crashed rather than failing the call |
check_health and deep_check are also reachable outside MCP, as
python -m cpersona.checkup. That is the form to use in CI. Cadence guidance
is in the operations runbook.
Server version¶
| Tool | What it does |
|---|---|
check_update |
Whether a newer release of the server itself exists, or whether the release you are running has been withdrawn (PyPI yank) — something an installed server can otherwise never learn. The check runs once per process start and is cached for 24h; this tool reads that verdict, refresh=true re-fetches, and apply=true runs the update (pip and source-checkout installs only) |
The same verdict rides on recall as an update key, once per session and
absent when there is nothing to say. It also appears in check_health as an
update_available (info) or version_yanked (warn) issue.
recall carries one more notice of the same kind: suggestion, once per
session, when a recall that searches vectors locally has a scope (source filter
included) holding 1,000 or more records with a stored vector past the scan
window, and no coarse index exists for a time cue to search the rest of its
period (binary coarse search). It
holds a message to relay and the fix call that builds the index. Building it
needs write access to every agent, so it is the user's decision.
Nothing is ever installed as a side effect. apply=true is the only thing
that installs anything, and a restart is always required afterwards,
because the process that ran the install is still running the old code.
Two setups are declined, each with a reason. Under uvx, the environment is a
cache entry keyed by the launch arguments, so the change belongs in your MCP
client's config (uvx cpersona@latest). A source checkout that is not on a
branch — a clone parked at a release tag, which is a normal way to deploy one
— is declined too: git pull has nothing to fast-forward from a detached
HEAD. The tool refuses before running anything and answers with the
git fetch --tags && git checkout <tag> form to use instead. The command shown
on recall, in check_health and by check_update is already that form for
such a checkout.
One apply runs at a time. A second is refused while the first is still
installing, including one whose call was cancelled: a cancelled call stops
waiting, but the installer step it started runs to the end.
A refresh=true whose fetch fails keeps the verdict already known (its
checked_at does not move). Being offline does not make a withdrawn release
any less withdrawn.
CPERSONA_UPDATE_CHECK=false disables the feature entirely, including the one
outbound request (what it sends).
Session controls¶
| Tool | What it does |
|---|---|
pause_persistence |
Turn writes into no-ops for a TTL window. Responses carry persisted: false; branch on that, not on an id |
resume_persistence |
Re-enable writes immediately |
persistence_status |
Whether writes are paused, and how much TTL remains |
Use these for benchmarking, or for throwaway exploration you do not want in the corpus.
The blast radius follows session_key, which each of the three tools
reports back as scope. Declare a key on the pause and on the write calls it
should cover, and the pause covers that key alone (scope: "session"). A
session sending a different key is neither silenced by it nor able to clear it.
The key is compared, never verified, so it partitions keys rather than callers:
anyone sending the same string shares the pause.
Omit the key and you arm the bucket that every keyless caller shares
(scope: "process"). Under stdio, where the client owns its own process, that
bucket is the session. On a streamable-HTTP deployment one process serves every
client, so a keyless pause silences writes for every other keyless session —
and those sessions are not told.
Two paths do not fit the persisted: false shape. check_health and
deep_check are not blocked, but downgrade to fix=false.
migrate_channel_axis is forced into dry-run and reports repairs_skipped,
with no persisted key at all.
Isolation arguments¶
The three isolation axes are not offered uniformly. agent_id is accepted by
most tools (25), project_id by nine, and channel by exactly seven: store,
declare_associations, recall, recall_with_context, reconstruct,
traverse and archive_episode.
They are independent axes rather than one nested hierarchy, and reads treat an empty value differently from an omitted one. See isolation axes.