⏳ This skill is pending AI review.

Scores will appear once the review pipeline completes.

version unknown

cpersona-memory

@cloto-dev⭐ 9 stars

>-

Choose how to use this skill

You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.

1. Native installer

This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.

Do not guess an installer command or replace an existing version without reviewing the diff.

2. Complete package recommended

Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.

No complete ProSkills package is published for this listing yet.

3. Prompt-only

Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.

Need only the instruction file?

Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.

No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.

—/10

// RATINGS

⭐GitHub Stars
⭐ 9 on GitHubGitHub ↗

New / niche

🟢ProSkills Score
—
📍

Not yet listed on ClawHub or SkillsMP

// README

CPersona

Long-term memory for AI agents, in one SQLite file you own.

CPersona is an MCP server that lets Claude Code, Codex, Claude Desktop, Cursor, VS Code or any other MCP client remember what you decided, why, and what happened last time — across sessions.

PyPI CI Python License: MIT

Documentation · Getting Started · Tools · Discussions

The built-in dashboard, showing a made-up store of 72 memories.

Why CPersona

Every new session with a coding agent starts from zero. CPersona gives the agent a memory it can write to as it works and read from before it acts.

  • Yours, on your machine. Everything lives in a single SQLite file. No account, no cloud, no external database; sqlite3 .backup copies it.
  • No language model inside. CPersona never calls a generative model to store or recall. Your agent writes the summary; CPersona keeps it and finds it again.
  • Answers you can trace. reconstruct, the recommended way to answer from memory, quotes the stored records behind each item, so you can see where an answer came from.
  • Search that catches what vectors miss. Vector search runs beside full-text and keyword search, so exact names, identifiers and error strings are found too, in Japanese and other scripts without spaces as well.
  • See what it remembers. cpersona dashboard opens a read-only page of the store: what was stored last, what is recalled most, every memory in full, and the network above.
  • Honest when it degrades. Without an embedding server it still runs on keyword search, and says so on every recall instead of quietly returning less.

Quick start

With Claude Code or Codex, install the agent plugin and let the agent do the rest:

/plugin install cpersona --marketplace Cloto-dev/cpersona

Then say "Set up CPersona." The plugin carries the setup skill and the hooks that remind the agent to recall before it acts and to store as it goes. (Claude Code 2.1.275 or later. In Codex: codex plugin marketplace add Cloto-dev/cpersona, then codex plugin add cpersona@cpersona.)

By hand, in three steps:

# 1. Run an embedding server (recommended; it powers vector search)
uvx --from "cembedding[onnx]" cembedding-download-model --model bge-m3
EMBEDDING_PROVIDER=onnx_bge_m3 uvx --from "cembedding[onnx]" cembedding

# 2. Register CPersona with your client (Claude Code shown)
claude mcp add-json cpersona '{"type":"stdio","command":"uvx","args":["cpersona"],"env":{"CPERSONA_DB_PATH":"/home/you/.claude/cpersona.db","EMBEDDING_MODE":"http","EMBEDDING_HTTP_URL":"http://127.0.0.1:8401/embed"}}' -s user

# 3. In a new session, ask the agent to store something, then recall it in another new session

# 4. See what it remembers, in the browser
cpersona dashboard

Getting Started covers the other clients, Windows, containers, and the short policy block that makes every future session use the memory.

Upgrading an existing install? Read the When you upgrade section of the release notes and SUPPORT.md first.

A look inside

OverviewA memory, opened
The dashboard overview: the memories stored last and recalled mostA memory opened in the dashboard, its text first

Memories are kept per agent, and project_id and channel let several agents and projects share one database without mixing.

Benchmarks

On OmniMemEval's LongMemEval-S pipeline (500 questions, answered by gpt-4.1-mini, judged by gpt-4o-mini), in this project's own run. Overall is the share of questions judged correct; Context Tokens is the average sent to the answer model per question:

BackendDeploymentSS-UserSS-AsstSS-PrefTemp. ReasMulti-SKnow. UpdOverallContext Tokens
CPersona 2.6.11 (pro mode)local97.1494.6496.6786.4785.7188.4689.604,262.5
CPersona 2.6.11 (lite mode)local95.7183.9390.0080.4574.4482.0582.20993.3
MemOScloud100.00100.00100.0089.4778.9584.6289.204,151

Pro mode is level with MemOS within sampling error, and on LoCoMo it answers 84.03%. Setups, the registered rules and every departure from a clean run are in the results.

Documentation

cloto-dev.github.io/CPersona is the full reference, also in Japanese:

GuideWhat it covers
Getting StartedInstall, embedding server, client registration, verification
Behavior ContractsWhat you may rely on: recall ordering, dedup, scan window, response shapes
ToolsEvery tool, grouped by what you reach for it for
ArchitectureStorage, the retrieval pipeline, isolation axes
RoadmapWhat each release line is for and may break; planned retrieval features and the scale ladder
Operations RunbookBackup, degradation detection, tuning, CJK guidance, corpus sync
ConfigurationEvery environment variable and its default
Quality AssuranceHow a release is gated: audits, the bug ledger, structural and mutation gates
FAQShort answers to the questions operators actually ask

Contributing

Bug fixes, tests and documentation can be sent as a pull request straight away. For changes to the database schema, the tool contracts or the tool list, open an issue first. CONTRIBUTING.md has the setup — no embedding server is needed to run the ~4,150 test functions — and the three checks CI runs.

Questions and ideas are welcome in Discussions. A sentence in the docs that confused you is worth reporting too: it is a defect of its own.

Support

// HOW IT'S BUILT

// FILES

4 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.

  • plugin/skills/cpersona-memory/SKILL.md33 KB77fed364b809truncatedupstream ↗

    Showing the inlined prefix. The rest is in the upstream file.

    ---
    name: cpersona-memory
    description: >-
      Give Claude persistent, searchable memory across sessions using the CPersona
      MCP server. Use this skill whenever the user wants Claude to remember things
      between conversations, asks to install or set up CPersona / a memory server,
      or when CPersona tools are available and the conversation contains decisions,
      rules, preferences, or a session boundary worth recording, or when a recall
      comes back degraded or the user says memory search stopped working. Covers
      install, MCP-client configuration, the embedding server, the day-to-day
      store / recall / archive workflow, diagnosing and repairing a degraded
      embedding backend, and persisting the memory policy into the user's
      always-loaded instructions file (CLAUDE.md, AGENTS.md, …) so the triggers
      survive without this skill loaded.
    ---
    
    # CPersona — persistent memory for Claude
    
    CPersona is an [MCP](https://modelcontextprotocol.io/) server that gives Claude
    persistent memory across sessions. It stores memories in a single local SQLite
    file and retrieves them with a 3-layer hybrid search (vector + FTS5 + keyword,
    merged by Reciprocal Rank Fusion). It has **zero LLM dependency** — the server
    never calls a model, so memory adds no generative API cost and stays out of
    your token budget; the calling agent (you) does all summarization. (Embedding
    is separate: `EMBEDDING_MODE=api` bills per store and per recall against
    `CPERSONA_EMBEDDING_API_URL`. The local `http` mode and `none` cost nothing.)
    
    - Single SQLite file, MIT licensed.
    - Works with Claude Code, Claude Desktop, Codex CLI, Cursor, VS Code, and any
      other MCP host.
    - Repo: <https://github.com/Cloto-dev/cpersona>
    
    This skill has two jobs: **(1) help the user install and configure CPersona**,
    and **(2) use it correctly** once it is connected.
    
    ---
    
    ## When to use this skill
    
    Activate this skill when any of the following is true:
    
    - The user asks Claude to **remember** something across sessions, or complains
      that Claude forgets context between conversations.
    - The user asks to **install / set up / configure** CPersona or "a memory
      server".
    - CPersona MCP tools (`store`, `recall`, `archive_episode`, …) are connected
      **and** the current turn contains a decision, a standing rule/preference, a
      bug finding, or a session boundary (start/end).
    - A `recall` response carries an `advisory` field, a `store` response comes back
      `embedded: false`, or the user reports that memory search has got worse.
    
    If CPersona tools are **not** connected and the user wants memory, go to
    **Setup**. If they are connected, go to **Usage** — or to **When recall is
    degraded** if a signal in the last bullet is what brought you here.
    
    ---
    
    ## Setup
    
    CPersona is a Python MCP server. Installing it has two parts: the **memory
    server** and a strongly recommended **embedding server** (it powers the
    vector-search layer). Running without an embedding backend is supported as a
    fallback — CPersona then serves FTS5 + keyword only — but it is not
    recommended for normal operation.
    
    **Prerequisites:** Python 3.11+ (Git only for from-source installs). No Python
    on the machine? Install [uv](https://docs.astral.sh/uv/) first — `uvx` and
    `uv tool install` fetch a suitable interpreter on their own, without touching
    the system.
    
    ### 1. Install CPersona
    
    The one-command path (needs [uv](https://docs.astral.sh/uv/)):
    
    ```bash
    uvx cpersona          # run directly
    # or: pip install cpersona  (then the `cpersona` command is on PATH)
    ```
    
    From source (development): `git clone https://github.com/Cloto-dev/cpersona.git`,
    `cd cpersona`, `python -m venv .venv && source .venv/bin/activate`,
    `pip install .`, run with `python -m cpersona`.
    
    ### 2. Install the embedding server (recommended)
    
    CPersona is embedding-server-agnostic — it talks to any HTTP endpoint that
    implements `POST /embed` → `{ "embeddings": [[float,…],…], "dimensions": int }`.
    The reference server is [CEmbedding](https://github.com/Cloto-dev/CEmbedding)
    (MIT), which runs `bge-m3` on-device (CPU), MIT-licensed and multilingual — the
    model CPersona recommends (the earlier recommendation, `jina-v5-nano`, is licensed
    for non-commercial use only):
    
    ```bash
    # one-time model fetch into ./data/models (run both commands from the same directory)
    uvx --from "cembedding[onnx]" cembedding-download-model --model bge-m3
    EMBEDDING_PROVIDER=onnx_bge_m3 uvx --from "cembedding[onnx]" cembedding   # serves http://127.0.0.1:8401/embed
    ```
    
    Or install it onto your PATH with `pip install "cembedding[onnx]"`, then run
    `cembedding-download-model --model bge-m3` and
    `EMBEDDING_PROVIDER=onnx_bge_m3 cembedding`. From source: `git clone
    https://github.com/Cloto-dev/CEmbedding.git`, `cd CEmbedding`,
    `pip install ".[onnx]"`, then `cembedding-download-model --model bge-m3`
    and `EMBEDDING_PROVIDER=onnx_bge_m3 python -m cembedding` — the download
    and the provider are not optional here any more than in the recipe above; a
    server started without them serves a different backend than the one just
    downloaded.
    
    **Keep its stdin open.** The reference server runs an MCP session on stdio and
    serves `/embed` from a background task, so its lifetime is bound to stdin.
    Started with stdin closed — `nohup … </dev/null`, a service manager, or your
    own background shell — it binds the port and exits within the same second with
    status 0, leaving CPersona pointed at a URL nothing answers. Hold the pipe:
    `sleep infinity | cembedding` (with the same `EMBEDDING_PROVIDER` as above).
    In an interactive terminal the terminal already does this. `uvx` runs the
    package out of uv's cache; for a server that has to come back after a reboot,
    `uv tool install "cembedding[onnx]"` gives a persistent install with
    `cembedding` on PATH.
    
    > CEmbedding is the reference and recommended backend; any other server
    > satisfying the contract above is equally supported and equally recommended.
    >
    > Without an embedding server, set `EMBEDDING_MODE=none`. That configuration is
    > supported as a fallback but is not recommended for normal operation: vector
    > search (the strongest retrieval layer) is disabled and recall falls back to
    > FTS5 + keyword. CPersona v2.4.33+ will *tell* you when it is running degraded
    > (see Troubleshooting) instead of silently serving reduced recall.
    
    ### 3. Register with the MCP client
    
    Pick an absolute `CPERSONA_DB_PATH` (e.g. `~/.claude/cpersona.db`).
    
    **Claude Code:**
    
    ```bash
    claude mcp add-json cpersona '{"type":"stdio","command":"uvx","args":["cpersona"],"env":{"CPERSONA_DB_PATH":"/absolute/path/cpersona.db","EMBEDDING_MODE":"http","EMBEDDING_HTTP_URL":"http://127.0.0.1:8401/embed"}}' -s user
    ```
    
    **Every other client** (Claude Desktop, Codex CLI, Cursor, VS Code, any MCP
    host) — the per-client entries live in one place,
    [Getting Started §3](https://cloto-dev.github.io/CPersona/getting-started/#3-register-cpersona-with-your-mcp-client),
    and this skill does not repeat them. The shape is always the same triple:
    command `uvx`, args `["cpersona"]`, and the `env` above; only the file and the
    key names differ.
    
    > **No embedding server yet?** Drop the `EMBEDDING_*` lines (or set
    > `EMBEDDING_MODE=none`) — recall runs on FTS5 + keyword and reports when degraded.
    > **From source:** use `"command": "python", "args": ["-m", "cpersona"]` with the
    > venv's python. **ClotoCore users:** install from the in-app marketplace
    > ([ClotoHub](https://hub.cloto.dev)) instead.
    
    **Choose the `agent_id` now** — one stable id for this user and client (e.g.
    `"claude-code"`, `"claude-desktop"`), reused on every call from here on. Recall
    is scoped to an exact `agent_id`: a later session that guesses a different one
    gets an empty result, not an error. With the cpersona plugin installed, its
    session-start note already names one: the plugin's `agent_id` option, else
    `CPERSONA_AGENT_ID`, else `default`. Keep that one, or, if the user wants
    another, set it there as well (`/config` in Claude Code, `CPERSONA_AGENT_ID`
    for Codex) so the notes and the policy block below name t
  • plugin/skills/cpersona-memory/references/always-loaded-index.md6.2 KB4ce942c3c023upstream ↗
    # Using an always-loaded index over this store
    
    Some MCP clients keep a small file that is injected into **every** session —
    Claude Code's `MEMORY.md` is the one this reference is written against. This
    page is about pairing such a file with CPersona. It is loaded on demand; the
    one-line rule that belongs in every session lives in the policy block in
    `SKILL.md`.
    
    Read this before moving any existing memory. **The migration is not a setup
    step and this skill will not perform it for you** — see "Moving existing
    memories" below for why.
    
    ## Why pair them at all
    
    The two channels fail in opposite directions, and that is the whole value:
    
    | | always-loaded index | CPersona |
    | --- | --- | --- |
    | arrives | **deterministically**, every session | when a `recall` happens to retrieve it |
    | holds | one line per memory | the full text, vector-searchable |
    | bounded by | a hard size cap | corpus size |
    | readable by | one client | every client sharing the `agent_id` |
    
    An index alone cannot hold bodies; it runs out of room. A store alone cannot
    guarantee that an agent ever learns a memory exists, because retrieval is
    ranked and a query that does not resemble the memory will not surface it. Put
    the pointers where arrival is certain and the bodies where search works, and
    each channel does the thing the other cannot.
    
    ## The shape
    
    One line per memory in the index:
    
    ```
    - <slug> — <one sentence that changes behaviour without opening anything>
    ```
    
    The line is not a title. It is the part that has to work when nothing else
    loads, so write the conclusion, not the topic: `never delete the -wal file` is
    a line, `about WAL files` is not. Keep it short enough that the index stays
    well under its cap — a line that costs 180 bytes buys nothing a 90-byte line
    does not.
    
    The body goes to CPersona with the slug as the join key, so that reading the
    line tells the agent exactly what to ask for:
    
    ```
    store(
      agent_id="<AGENT_ID>",
      message={
        "id": "memory-index:<slug>",          # dedup key: re-storing edits, never duplicates
        "content": "[<slug>] <the full memory>",
      },
    )
    ```
    
    Retrieve it with `recall(agent_id="<AGENT_ID>", query="<slug>")`. The prefix is
    what makes the join checkable in both directions (below); `message.id` is what
    makes a re-store idempotent, because CPersona deduplicates on it.
    
    ### Not everything should move
    
    Split by whether the memory is **fired** or **queried**:
    
    - **Fired** — behavioural rules that must act without anyone asking for them
      ("always do X", "never do Y"). The index line is the working copy; the body
      in CPersona is the evidence and the reasoning.
    - **Queried** — lookups you open on purpose (a runbook, a table of endpoints,
      a design decision you cite). These want a real file at a real path, because
      citing one means naming where it is. Keep the body wherever your client
      keeps files, and give it an index line too.
    
    Splitting this way also keeps the index honest about its own cost: the bodies
    that grow without bound are exactly the ones that left.
    
    ## Keeping the two in step
    
    The index and the store can disagree in two directions, and **both are silent**:
    
    - a line whose row was never written, or was deleted — it costs its bytes in
      every session and points at nothing;
    - a row with no line — it is in the store, and no session is told it exists.
    
    Nothing detects either one for you. `check_health` audits the store's internal
    consistency, not its agreement with a file it has never heard of. So check the
    join yourself, on the two sets of slugs:
    
    ```bash
    # every slug named by an index line
    grep -oE '^- [a-z0-9-]+' MEMORY.md | sed 's/^- //' | sort > /tmp/index-slugs
    
    # every slug stored under the prefix, via list_memories on the agent
    #   -> extract the text between "[" and "]" at the start of each content
    #   -> sort into /tmp/store-slugs
    
    comm -23 /tmp/index-slugs /tmp/store-slugs   # lines with nothing behind them
    comm -13 /tmp/index-slugs /tmp/store-slugs   # rows no session will hear about
    ```
    
    Both outputs empty is the invariant. Run it after any bulk change, and treat a
    non-empty result as a defect rather than as drift to be tidied later — a
    half-migrated corpus is worse than either whole one, because neither channel
    can be trusted on its own.
    
    ## The cap is the binding constraint
    
    The index has a hard limit (Claude Code's is 25,000 bytes / 200 lines), it is
    paid in every session, and **exceeding it does not raise an error** — the
    content is simply not injected, which from inside the session is
    indistinguishable from having no memories at all.
    
    So decide the rule before you need it:
    
    - Set a working threshold well below the cap (80% is a reasonable warning
      line) and act at the threshold, not at the limit.
    - At the threshold, **consolidate rather than compress**. Merging several
      related lines into one durable document — one you can cite, and reference by
      a single line — reduces the growth rate. Shortening existing lines is a
      one-off saving that buys a few sessions and changes nothing about the slope.
    - Never solve a full index by deleting entries you have not read. A line you
      cannot justify is a line whose body you should read first; the body is in
      the store, which is the point of putting it there.
    
    ## Moving existing memories
    
    **Ask before moving anything, and do the move yourself rather than having the
    agent do it unattended.** This skill deliberately does not automate it:
    
    - It is destructive in a way that is hard to see. If the bodies are deleted
      from their old location after being stored, the old location is the only
      copy that existed; if they are not deleted, you now have two copies that
      will drift.
    - It is not idempotent until the join key exists. Re-running a half-finished
      move without `message.id` set as above writes second copies of everything it
      already wrote.
    - It is unbounded. A corpus of any size is a long sequence of writes, and
      nothing reports that it stopped halfway.
    
    If you do move a corpus, the order that survives an interruption is: store the
    body (with `message.id`), verify the row, then rewrite the index line, then
    remove the old body — one memory at a time, so an interruption leaves a
    consistent prefix rather than a scattered mixture. Run the join check above
    afterwards, in both directions, and read the result rather than the exit code
    of the loop.
    
  • plugin/skills/cpersona-memory/references/embedding-backend-repair.md13 KBf67db63b5911upstream ↗
    # Repairing a degraded embedding backend
    
    CPersona answers `recall` from three retrieval layers. Two of them — FTS5 and
    keyword — live inside the SQLite file and cannot fail on their own. The third,
    vector search, reaches an embedding server over HTTP, and it is the one that
    degrades silently at the network boundary.
    
    This file is the walkthrough for that single failure: how to tell which
    condition you are in, what to say about it, what to propose, and how to prove
    the repair worked. It is a separate file because it is only needed when
    something is actually wrong — the day-to-day store / recall / archive workflow
    in `SKILL.md` never reaches it.
    
    ---
    
    ## 0. What this file authorizes
    
    Diagnosing and explaining: freely. Everything else: a proposal.
    
    Starting a process, editing an MCP client's configuration file, changing an
    environment variable, restarting a server — each is a change to the user's
    machine, and the approval rules you already operate under govern them here
    exactly as they do anywhere else. Show the exact command or the exact edit, say
    what it will do, ask, and wait for an answer.
    
    Nothing about a degraded backend makes that urgent. The memories are intact,
    writes keep succeeding, and one of three search layers is off. There is no
    state that decays while you wait for the user to reply.
    
    ---
    
    ## 1. Name the condition before you explain anything
    
    Two conditions degrade recall and they need different conversations. Telling
    them apart is the first step, not a detail.
    
    | | **HINT** | **FAULT** |
    |---|---|---|
    | Configuration | no embedding backend configured (`mode=none`) | a backend is configured (`mode=http` or `mode=api`) |
    | What it means | a standing, deliberate configuration | an outage: the configured endpoint did not answer |
    | `advisory.severity` | `hint` | `fault` |
    | `advisory.evidence` | `mode=none / no embedding backend configured` | names the mode, the endpoint, and the failure |
    | Raised after | the first `recall` | two consecutive failed embed calls (one blip is debounced) |
    | Right response | offer to connect a backend | find out why it stopped answering |
    | Wrong response | treating it as a fault the user must fix now | treating it as a configuration choice |
    
    A `hint` is not a smaller `fault`. The user chose a supported configuration and
    may keep it; your job is to make sure they chose it knowingly. A `fault` is
    something that used to work and stopped.
    
    ---
    
    ## 2. The signals, and what each one can and cannot tell you
    
    - **`advisory` on a `recall` response** — the primary surface, and the only one
      that fires on its own. Shape:
      `{degraded, severity, reason, evidence, runbook, advisory_scope}`. The first
      time in a degraded episode it carries the full runbook; afterwards a short
      reminder. `advisory_scope` says whose "already told" state you are seeing:
      `session` when the caller declared a session key, `process` when the state is
      the whole server's and the transport is shared.
    - **Running a `recall` is the liveness test — with two caveats.** It embeds the
      query through the real client, so a success clears the degraded state and
      re-arms the full runbook, and a failure feeds the fault counter. There is no
      separate probe to run. The first caveat is that it is not always read-only:
      with `CPERSONA_CONFIDENCE_ENABLED=true` a successful, non-deep recall that is
      not a gate fallback updates `recall_count` and `last_recalled_at` on the rows
      it returns. The flag ships off, so a default install is unaffected — but this
      page tells you to run the test repeatedly, and an install that turned
      confidence on is ranking on state those runs move. It writes nothing while the
      session is paused, which is what keeps the test safe during a no-persist
      window. The second caveat: a single-text embed is cached for five minutes, and a cache hit
      returns the stored vector without a request leaving the process. It no longer
      clears the degraded state — an advisory therefore survives a repeated query —
      but it cannot confirm a repair either. **Test with a query you have not just
      used**, or the answer describes the cache rather than the backend.
    - **`embedded` on a `store` response** — `false` means the write landed without
      a vector. The memory is saved and searchable by keyword; the vector is
      repairable later (§6).
    - **`check_health(agent_id, fix=true)`** — probes the backend and reports
      `embedding_backend_unreachable` (`warn`) with the failing call's own evidence
      when a configured backend does not answer. No finding means it answered; an
      answer to this run's own probe outranks a fault latched earlier.
    - **`check_health(agent_id, fix=false)`** — does not judge liveness. It may
      still contact the backend (the dimension check's probe embed, the backend's
      identity, token counts for the node scan) but reads none of those calls as
      liveness, and says so: `embedding_backend_not_probed` (`info`). A fault
      a recall already latched is still reported. Do not read a quiet `fix=false`
      run as evidence that the backend is up. A `fix=true` run reports the same
      finding when the probe hit the embed cache instead of the endpoint; its
      `reason` field distinguishes `served_from_cache` from `no_probe_on_this_run`.
    - **No backend configured is deliberately not a `check_health` finding.** It is
      permanent, it was never confusable with "the server is up", and a finding
      that can never be resolved teaches an operator to skim past the check. That
      state is raised on the recall advisory instead, which is the surface a user
      reads.
    - **`get_session_findings()`** — `_meta.server_version` is the version of the
      code answering the request, not of whatever distribution sits beside it. Quote
      that when a version matters.
    
    ---
    
    ## 3. HINT — no backend is configured
    
    ### Say this
    
    - CPersona is working. Memories are being stored and recalled right now.
    - No embedding backend is configured, so recall runs on FTS5 + keyword only.
    - That configuration is **supported** — it is not a broken install.
    - It is **not recommended for normal operation**: recall matches on shared
      words, so a memory phrased differently from the question can be missed, and
      so can older ones.
    - Connecting a compatible embedding server is strongly recommended, and it is a
      one-time setup.
    - CEmbedding is the reference implementation and the first recommendation; any
      server satisfying the embedding contract is equally supported.
    
    ### Then propose one of two paths
    
    **The reference backend.** Both commands run from the same directory; the first
    downloads the model once, into `./data/models`:
    
    ```bash
    uvx --from "cembedding[onnx]" cembedding-download-model --model bge-m3
    EMBEDDING_PROVIDER=onnx_bge_m3 uvx --from "cembedding[onnx]" cembedding
    ```
    
    That serves `http://127.0.0.1:8401/embed`. On a PATH install
    (`pip install "cembedding[onnx]"`) the same two steps are
    `cembedding-download-model --model bge-m3` and
    `EMBEDDING_PROVIDER=onnx_bge_m3 cembedding`; from a source checkout,
    `python -m cembedding.download_model --model bge-m3` and
    `EMBEDDING_PROVIDER=onnx_bge_m3 python -m cembedding`.
    
    **Any conforming backend.** CPersona is embedding-server-agnostic. The server
    must implement `POST /embed`, taking `{"texts": ["…"]}` and returning
    `{"embeddings": [[float, …], …]}`. Three requirements are easy to miss and each
    degrades ranking quietly: embeddings **must be L2-normalized** (similarity is a
    raw dot product, so unnormalized vectors bias ranking by magnitude); the
    contract is **role-less**, with queries and documents embedded through the same
    call and no instruction prefix, which is why prompt-prefix model families
    underperform behind it; and CPersona sends **at most 32 texts per request**.
    
    ### Point CPersona at it
    
    Both variables belong in the MCP client's `env` block for the `cpersona` server
    — the same block that carries the database path — and the client has to be
    restarted to pick them up:
    
    - `CPERSONA_EMBEDDING_MODE=http`
    - `CPERSONA_EMBEDDING_URL=http://127.0.0.1:8401/embed`
    
    `EMBEDDING_MODE` and `EMBEDDING_HTTP_URL` are accepted as aliases, and the
    `CPERSONA_`-prefixed names win when both are set. Check for an existing pair
    before editing: setting the alias while the prefixed one is already present
    changes nothing, and it looks exactly like a repair that did not take.
    
    ### If the user declines
    
    That is a legitimate answer, and `CPERSONA_DEGRADED_ADVISORY=false` records it —
    it stops the report, not the degradation. Offer it only after they have heard
    what the configuration costs, and say plainly that it does not make running
    without a backend the recommended setup.
    
    ---
    
    ## 4. FAULT — the configured backend is not answering
    
    ### Say this
    
    - A backend is configured and is currently unavailable.
    - Only the vector layer is affected. Storing and recalling both still work; the
      fallback in force is FTS5 + keyword.
    - Writes made while it is down come back `embedded: false`. They are saved, and
      their vectors are repairable once the backend returns (§6).
    - Quote `advisory.evidence` verbatim. It is built from the client's own
      configuration and the exception, never from request headers, and the endpoint
      is stripped of any userinfo and query string — so it names the mode, the
      endpoint and the failure without carrying a credential.
    
    ### Work through the causes in this order
    
    1. **Read the endpoint in the evidence.** If it is not the endpoint the user
       expects, the configuration is the fault and no amount of restarting the
       server will help.
    2. **Is the backend process alive?** It may have exited, or never been started
       in this session.
    3. **Is the port reachable from this host?** A backend on another machine, in a
       container, or behind a firewall answers locally and not here.
    4. **Did the model ever get downloaded on this machine?** A freshly provisioned
       host — or a database copied to a new one — has the configured URL and no
       model cache behind it.
    5. **Did the client's configuration change?** A port moved, or a second
       `CPERSONA_`-prefixed variable was introduced and now takes precedence.
    
    A direct probe separates "the backend is down" from "CPersona cannot reach it",
    and it is read-only:
    
    ```bash
    curl -s -X POST http://127.0.0.1:8401/embed \
      -H 'Content-Type: application/json' -d '{"texts":["ping"]}'
    ```
    
    An `embeddings` array back means the backend is healthy and the problem is
    between it and CPersona.
    
    ### Then propose the matching repair
    
    Restart the backend; or correct the URL and restart the MCP client; or download
    the model on this machine and start it. One cause, one proposal — and say which
    of the five checks led you there, so the user can disagree with the diagnosis
    rather than only with the command.
    
    ---
    
    ## 5. Verify the repair — do not stop at "it started"
    
    Run these in order. The first three prove liveness; only the fourth repairs
    what the outage left behind.
    
    1. **`curl` the endpoint** (command above) — the backend answers at all.
    2. **Run a `recall` with a query you have not just used** — no `advisory` on the
       response. An embed that reaches the backend clears the degraded state, so this
       is the check that says CPersona itself is satisfied. A repeated query can be
       answered from the five-minute embed cache; that hit clears nothing, so a
       still-present advisory after one would tell you about the cache, not the
       backend.
    3. **`store` a fact** — the response carries `embedded: true`.
    4. **`check_health(agent_id, fix=true)`** — no `embedding_backend` finding, and
       the rows written during the outage are re-embedded. A `not_probed` finding
       with `reason: served_from_cache` means step 4 asked the cache, not the
       backend; re-run it once the entry expires.
    
    A green step 2 with a skipped step 4 leaves the user with working recall over a
    corpus that still has holes in it.
    
    ---
    
    ## 6. Backfill what was written while it was down
    
    `check_health(agent_id, fix=true)` re-embeds rows whose embedding is NULL —
    exactly the rows that came back `embedded: false`. One run re-embeds up to 500
    of them, so on a long outage run it until the finding count reaches zero rather
    than assuming a single pass caught everything.
    
    ---
    
    ## 7. What repair cannot reach
    
    Swapping a **different model of the same dimension** behind the same URL is
    undetectable and unrepairable by these tools. CPersona fingerprints a backend by
    embedding dimension only, so nothing is flagged; the dimension check NULLs blobs
    of the wrong length, so nothing is NULLed; and `fix=true` re-embeds only NULL
    blobs, so nothing is re-embedded. The corpus is then scored against a model that
    did not produce it, and every layer above reports healthy. The remedy is to
    treat a model swap as a corpus rebuild, not as a configuration change — see the
    Getting Started guide at <https://cloto-dev.github.io/CPersona/getting-started/>.
    
  • README.mdupstream ↗

    Contents are not inlined in the catalog. Open the upstream file.

Plain-text copy, no login: /skill-bundles/cloto-dev-cpersona-plugin-skills-cpersona-memory.md

// REPO STATS

9 stars