See the README for a project overview and installation. This reference covers detailed behavior and optional controls; normal use is automatic.
- Installation and updates
- Automatic learning and recall
- Evidence, decay and ranking
- Storage and privacy
- Commands
- Migration
- Recovery and troubleshooting
- Provider fallback, error policies and budgets
Use Pi 0.85+ with a configured model. The runtime can be standalone Pi/Bun or npm Pi on Node 22.19+. Git installation also requires Git and npm on PATH. Pi supplies its own APIs and TypeBox; the extension uses built-in SQLite.
Choose one source:
# npm package
pi install npm:pi-memory-evolution
# Git default branch (main), without a historical tag pin
pi install https://github.com/btnalit/pi-memory-evolution
# Local checkout: direct reference, no copy
pi install /absolute/path/to/pi-memory-evolutionRun /reload and /memory status inside Pi. There is no separate installer,
post-install script, owner approval, or additional API key to configure. For local
development, install dev dependencies with npm ci --ignore-scripts in the checkout.
Before upgrading, read migration and backups. Update the same source you installed:
pi update npm:pi-memory-evolution
# Or, for a Git install:
pi update https://github.com/btnalit/pi-memory-evolution
# For a local checkout, update it yourself:
cd /absolute/path/to/pi-memory-evolution
git switch main
git pull --ff-only origin mainPlain pi update updates Pi itself, not this package. PI_OFFLINE=1 also suppresses
explicit package updates; unset it or use PI_OFFLINE=0 when updating. Package
subcommands do not accept the general --offline flag.
Pinned npm versions stay pinned. The old v0.1.0 Git tag is historical; install the
unpinned Git source to follow the default branch instead. Use pi list and remove
the old source before switching between npm/Git/local forms, which Pi treats as
different package identities. pi remove <source> does not erase memory state.
Restart or /reload all sessions using the extension after changing versions.
Pi treats npm, Git and local paths as different package identities. Installing the
same source twice is idempotent, but keeping both a dev checkout and an npm copy can
register memory_recall twice and prevent Pi from starting. Updating either copy
does not remove the other. This is not a failure of a single-source upgrade.
Use terminal commands, not commands inside the broken Pi session:
pi list
# Keep npm; remove the local source shown by pi list:
pi remove /absolute/path/to/pi-memory-evolution
# Or keep the checkout; remove npm instead:
# pi remove npm:pi-memory-evolutionChoose only the removal matching your intended source. If installed project-locally,
run pi list --approve and pi remove <source> -l --approve from that trusted project.
A manually configured extensions entry is not a package entry: remove that explicit
entry from the appropriate settings file as well. Then restart Pi and run
/memory status. Package CLI operations work without loading the conflicting
extensions, and removal leaves memory data intact. Do not delete the database or
rename the tool to hide the conflict; an old installation would still run its hooks.
- A successful
session_compactsaves a sanitized source and extracts up to 16 facts, preferences, decisions or project-state claims using recognizable headings. - Explicit user statements containing cues such as
remember,prefer,记住,偏好,纠正,不对,以后, or不要also trigger learning, without waiting for another compaction. The English counterparts of以后/不要count the same way, and all of them only at the start of a sentence:from now on,going forward,in the future(orin future),always,never,don'tordo not. Position is what separates a standing rule from a question about one —Always run the tests.andIn the future, always run the tests.state a rule, whileDo you always run the tests?,Don't you think we should refactor?andWill this work in the future?stay questions and are not learned. Both'and’are accepted. Two further narrowings keep ordinary sentences out: a text ending in?or?is a question whatever word it opened with (Never seen this error before, what is it?), and a bare imperative that limits itself to the step at hand —for now,for this,this time,justoryetafter the cue, as inDon't worry about the tests for now, just make it compile.— is an instruction, not a rule. The explicit openers are durable by their own words, soFrom now on, just run the unit tests.is still learned. A directive quoted from a pasted log or document is indistinguishable from your own by position alone, so it is learned; this matches the existing以后/不要behavior. Natural declarations such as我比较在意的三大功能…,我们的核心需求是…orOur priorities are…also trigger learning, even if followed by a question asking for feedback. This is bounded intent recognition, not universal understanding. Quotes, ordinary recall questions and one-off commands are not requirements. Assistant/tool text never becomes a user memory instruction. - Work requests (commit/push/fix/test/review, etc.) can update existing project states
from linked tool results. Important commit/push/test results are retained ahead of
late routine inspection, not simply the last 8 tools. Normal completion and interrupted
assistant responses are distinguished: a completed tool operation is usable evidence
even if the final reply failed, but it does not prove the entire task completed.
Internal
memory_recallresults and observations referencing this extension's own state directory are excluded from this evidence path. - Update nomination is separate from answering a query: explicit operation resources and project names nominate up to 8 active, unpinned states in the same capture origin, prioritizing pending states without a per-path top-2 or answer-deduplication gate. Expired states can receive new evidence; forgotten/conflicted states cannot. The model can only replace nominated project states, never create preferences from tool results. A mixed requirement/work turn can create two separate serialized sources/calls, preserving statement versus tool authority instead of silently discarding the work.
- Each processing attempt makes at most one background model call, using up to 32 recently updated active memories from that source's capture origin that the source actually mentions — the host filters the rest out, so a source cannot replace a record it never talks about. The filter runs before the cap, so an older record the source is squarely about is no longer hidden behind newer unrelated ones; reach is still bounded by the 32 most recent records that qualify. This is a conservative automatic-replacement safeguard, not a recall restriction. It defaults to the current Pi session model and Pi's own provider/auth resolution. With no session override, this is Pi's configured default. Quota/rate limits or repeated failures may switch to an available model from another configured provider, not a sibling sharing the default provider's quota. The foreground model is never changed. See fallback privacy, error handling and budgets; no extra credentials are stored.
- Valid additions/replacements commit immediately, with provenance and before/after
history. Inferred memories remain labeled
provisional, but are recallable without approval. Pinned memories cannot be automatically replaced. - Replayed source events are idempotent. Calls have a 120-second deadline and send the active model's own output limit as the cap, never a smaller one: a ceiling is consumed by the model's reasoning before it writes an answer, so an invented one can leave a thinking model with nothing to say. Cost is governed by the routing policy instead. They are cancelled on session shutdown/reload. Structured summary claims survive model failure. User-cue prose has no local-extraction fallback: its sanitized source is saved, but learning its claims requires a successful model attempt.
- Session start checks persisted work across all origins. While Pi remains running, a local recovery timer checks every 15 seconds (after the previous check/call ends), gradually draining eligible pending/failed work one source per check (at most one immediate backup per check). Selection favors least recently checked work, then retry time and oldest capture, so unavailable routes do not indefinitely block other sources.
- Recovery is error-specific, with persisted source backoff, separate provider/model
cooldowns, at most one output correction, and bounded cross-provider fallback. Generic
backoff is 1 minute, 5 minutes, 15 minutes, then 1 hour, plus up to 20% jitter. Defaults
cap each source at 4 reserved calls / 2 models / 300 seconds, and all models and
processes share 20 calls per rolling hour. Three output failures or five generic
failures also pause work; a write refused on the store's own authority (pinned, cross-origin,
or a record already newer than the source) pauses immediately, while a model that breaks the
output contract is corrected and retried like any other invalid output.
/memory statusexplains routes, budgets and actual outcomes./memory evolveoverrides source limits for one attempt, never shared ceilings or settled jobs. Full policy/configuration. - A job lease lasts 150 seconds (120-second deadline plus 30-second grace). The timer detects expired running jobs and schedules them with the same bounded backoff. Shutdown/ reload cancellation returns work to pending without consuming the failure budget. Timers stop at shutdown and do not keep a print-mode process alive. Recovery resumes next time Pi runs; this is not a standalone daemon.
- Recall searches the whole memory database, including previous sessions, other
directories and existing legacy claims. No project-directory startup or manual adoption
is needed. Matching uses exact literals, word segmentation and weighted topic coverage
locally, without a model call. Paths/filenames do not earn extra votes for their component
words; for example, a repository named
pi-memory-evolutionis not itself evidence about cross-session memory. - Natural questions such as
X相关记忆你还记得吗?orWhat do you remember about X?separate the recall request from its actual subject. This applies across topics, not through per-device exceptions. Technical questions about memory/recall remain topics. Asking what Pi remembers does not itself trigger a paid learning call. - Vague follow-ups use bounded recent user messages from the active branch, including
retained compaction tails. Multi-hop refinements such as
SQLite 数据库 → 端口呢? → 认证呢? → 继续retain the subject and require the current attribute; prior-topic-only matches cannot satisfy the new question. Explicit new, unknown and reset topics stop old-topic inheritance. Assistant/tool/injected text never supplies the topic. The active-context scan covers up to 4096 entries/messages, returning at most six user texts; repeated topic-less continuations share a slot so long tool-heavy work does not immediately lose its subject. Bounds and compaction still limit recall. A fresh session saying only继续injects nothing; naming a topic enables cross-session recall regardless of its original directory. - Recall works from an ordinary task prompt, not only from a question aimed at the memory:
a record qualifies either when it accounts for enough of what was asked or when the
prompt names that record's topic — an exact path/filename, or a known concept or one of the
record's own aliases that is rare in the store (an alias such as
serverthat many records share names nothing) — and engages it more than once. Neither measure shrinks as the request gets longer, nor as the stored claim gets longer or gains aliases, so describing a task in full no longer suppresses the background it is about, and a claim that explains itself is no harder to recall than a one-liner. A prompt that engages nothing stored still injects nothing. The live prompt itself may run up to 65,536 UTF-8 bytes before feature extraction — far past a single conversational turn — so a task naming a stored record after a long pasted log, diff or spec is still recalled, provided any paths in the paste sit on stack-frame, diff or fenced lines or carry a line reference (next point); a path on an ordinary line of an unfenced paste reads as typed and stays required. Only bounded replayed history from earlier turns keeps the smaller 2,048-byte-per-turn budget. - Query coverage, topic naming, evidence-based document frequency, field weights, mild length
normalization and a relative cutoff reject weak secondary matches. Unseen query words
no longer receive the highest rarity weight. An exact path or filename you type must match,
including case;
/srv/Atlasand/srv/atlasare distinct. A path that arrived inside pasted material — a stack-frame line (at …location:line:col; a line that merely opens with the wordatis the ask), a diff (a hunk ends where its@@header says), fenced code, or afile:line:colreference — still counts in favour of a record that names it but is not required of every record, so a trace pasted ahead of the ask does not block recall of the background the ask is about; a path that also appears in the ask itself is typed, and stays required. A quoted question in a replay/incident note is weaker than evidence answering it. Redundancy filtering cannot let a project-state note hide a preference of the same origin. Source IDs/cwd have no authority bonus. After relevance gates, host-assigned evidence, type-specific freshness and explicit feedback order eligible matches; pin/date break remaining ties. Common words such as没有or现在cannot trigger recall. At most three claims fit within 2048 UTF-8 bytes, with origin/source labels and non-truncatable trust guidance. Fewer matches means fewer claims, not padding with recent records. Identical content from different origins retains separate provenance. Unpinned project-state claims still age out after seven days; pinning exempts age, not truth checks. Short named-attribute queries require the subject and attribute, rather than substituting another subject/attribute when the correct memory is missing or suppressed. - Common Chinese/English concepts are normalized locally for existing records. Evolution
can add up to 8 validated bilingual
searchTermsper claim, extending matching without changing its factual text or adding a recall-time translation call. Aliases alone do not refresh evidence dates. This is bounded bilingual support, not universal translation.
A model call may incur the usual charges of your active provider. These background calls are not assistant turns and their usage is not added to Pi's session token totals. There is no additional call on ordinary recall. Eligible work turns may now incur one additional background call each; no related tracked state or no tool observation means no progress call. A mixed statement/work turn may additionally incur a separate learning call; interrupted turns with usable observations may also learn through automatic recovery. Automatic retries/fallback share a default total of four reserved calls per source; they do not get separate budgets per model. Each request uses Pi's authentication for the selected provider. Cross-provider data sharing and optional estimated-cost limits are explained in recovery configuration. Model mistakes remain possible; tool observations and model-generated aliases are not proof of truth. Use history, correction, pinning and undo rather than treating generated claims as verified facts.
- New claims carry host-assigned evidence:
summary,user_statement,tool_observationormanual_correction, plus extraction method, source ID and date. Model output cannot supply confidence/verification/feedback fields. Old records without this metadata remainunknown; migration does not guess their source or certify them. - Source appropriateness matters: a user's stated preference is stronger evidence of that preference than a summary; a linked tool observation supports a project state, not a user preference or independent proof of success. A weaker model-proposed replacement is withheld and its new variant quarantined, with history. Current user corrections and new tool-backed project progress can still update automatically; pins remain protected.
- Freshness decreases smoothly by type: project state fastest, then facts, decisions,
preferences. Every kind retains a nonzero floor, and past its own horizon becomes
dormant — no longer injected automatically, but still stored, still returned by the
memory_recalltool and by/memory search, and still offered to learning, so later evidence revives or retires it without you doing anything. Dormancy governs what is pushed into a session unprompted; it never makes a record unfindable for someone looking for it. Project states keep the seven-day cap; no upgrade revives old states. Read/search/injection, pinning, alias enrichment, feedback and conflict resolution never move the evidence date, and nothing does except a replacement. The separate decay clock is moved only by a later source that mentions a record and either leaves it standing or reaffirms it outright — never for project states, whose seven-day cap nothing resets. - Ranking keeps relevance, evidence, freshness and feedback separate. Quality cannot
rescue an unrelated/weak lexical match.
usefulis notaccurate; neither is independent verification. Repeated retrieval or repeated positive feedback earns no cumulative boost./memory showand/memory explainexpose the factors. Injected claims include evidence labels and an aging warning, not a fictitious probability of truth.
Optional /memory feedback <id> useful|unhelpful|accurate|incorrect records a precise user
verdict without a model call. unhelpful modestly lowers utility, not factual credibility.
incorrect quarantines the claim and same-origin exact duplicates, retires known pending
repeats, and is undoable. Use correct for new content or resolve to restore a disputed
claim; conflict/resolution does not rejuvenate old evidence. Feedback with a timestamp
older than the current content's evidence date is ignored. Receipts prevent replay after restart/undo; identical repeated verdicts do not
accumulate weight. Feedback receipts, like history, are not securely erased by forget.
Whole user messages 记忆 <24-hex-id> 有用。 / memory <24-hex-id> incorrect also work;
quotes, questions, assistant/tool text and vague “wrong” do not identify a feedback target.
Ordinary natural-language corrections continue through automatic model evolution.
The model also gets a read-only memory_recall tool for missing background discovered
mid-task. It takes an explicit topic and returns up to three relevant claims / 2048 UTF-8
bytes, using the same lifecycle and quality gates. It does not modify memory, persist a
query in the memory DB, or make an additional retrieval-model call (normal agent tool
turns still incur normal usage and appear in the Pi transcript). Automatic per-user-turn
injection remains the default; the model chooses whether a second lookup is needed.
Explicit tool allowlists must include memory_recall; the extension never overrides them.
These are bounded evidence policies, not learned semantic verification, independent-source corroboration, or a universally accurate self-evolving ranker. See core quality design and validation for formulas and remaining gaps.
State lives under Pi's public agent directory (getAgentDir()). By default:
~/.pi/agent/agent-suite/memory-evolution/
├── memory.sqlite # memories, sources, suppression hashes, jobs and history
├── memory.sqlite-wal # SQLite-managed when open
└── memory.sqlite-shm
If PI_CODING_AGENT_DIR is set, replace ~/.pi/agent with that directory. Using a
different agent directory means a different database. Changing cwd does not hide
memories in that database or create a recall boundary.
SQLite transactions/WAL protect concurrent processes and interrupted commits. Model calls run outside transactions; stale responses cannot overwrite intervening changes. Raw summaries are evidence only, never a separate recall fallback, so forgetting a derived claim cannot expose it again through its parent summary.
The stored scope field records capture origin (canonical cwd, not an inferred project
identity). It is retained for provenance and conservative write protection, not eligibility
for recall. An origin can cover multiple projects; facts must retain explicit subject names
where available. Explicit origin identifiers can help a named-context query at low weight;
current cwd, legacy labels and source IDs do not boost a claim's authority or relevance.
Global recall does not mean global rewriting: automatic replacement candidates remain within the source origin, and the model must identify the same subject/fact, not just a matching port or path. Cross-origin variants are not automatically merged or overwritten. Exact-ID manual corrections/forget work from any session and affect the selected record and exact duplicates within its origin, not identical text from unrelated origins. Suppression hashes likewise remain origin-qualified. Arbitrary paraphrases or semantic identity across origins cannot be resolved reliably by a local hash. These safeguards may leave ambiguous variants for inspection rather than guessing which one to retire. Forget is logical suppression, not secure erasure of history or the original Pi transcript.
Sensitive lines/blocks are suppressed before capture, edits, model submission and recall. This covers common token/password/JSON/Chinese/Bearer/private-key formats, including quoted multiline values, indented YAML blocks and control-character cleanup, but not every possible secret. Do not rely on a regex as a complete DLP system. Sanitized sources and selected existing memories go to the active Pi model provider or an allowed already-configured fallback provider. Fallback is enabled by default; restrict the model allowlist or disable it in recovery configuration to constrain data sharing.
These are optional direct controls, not approval gates:
/memory list [page] # all origins, 20 non-forgotten records per page
/memory list all [page] # alias for list
/memory list here [page] # optional current-origin view
/memory list legacy [page] # optional unknown-origin view
/memory show <id> # exact ID, any scope/status; includes provenance
/memory search <query> # up to 10 recallable matches across all origins
/memory explain # last automatic recall snapshot, including injection count
/memory explain <query> # preview retrieval reasons for an explicit query (3-claim cap)
/memory learning # last capture/nomination reasons + recent transaction outcomes
/memory status # integrity + retries + processed-versus-changed outcomes
/memory history # last 10 events across all origins
/memory evolve # optional one-off retry, overriding delay/failure limit
/memory evolve <source-id> # retry one named source without clearing other failure counts
/memory import [directory] # explicit, repeat-safe legacy JSONL import; never replays a completed one
/memory archive-legacy # copy inactive legacy plan files to a private unique archive; originals kept
/memory undo <event-id> # reverse actual changes, if not modified since
/memory feedback <id> <verdict> # useful | unhelpful | accurate | incorrect
/memory correct <id> <replacement> # literal replacement, 4–800 characters
/memory forget <id>
/memory pin <id>
/memory unpin <id>
/memory conflict <id> <other-id> # suppress both
/memory resolve <id> # restore this conflicted side; other stays suppressed
/memory adopt <id> # optionally label a legacy claim with this directory
Pages start at 1, sorted by update time descending, then ID. For example,
/memory list legacy 2 reaches the next 20 imports. all is retained as an alias;
here and legacy are optional inspection filters, never recall settings. There is no
full export command. Concurrent updates can move records between
pages. Lists can show conflicted or stale project-state records that search/recall
excludes. Status counts include all scopes and tombstones and validate source jobs and
history as well as memory records. Long content previews are capped at 1,440 bytes in
lists/search or 8,000 bytes in show, with an ellipsis when truncated.
Commands that take exact IDs can address records outside the current cwd. search and
explain <query> use only their explicit query, whereas automatic recall can resolve
follow-ups from recent user context. explain without arguments shows the last automatic
snapshot: normalized focus/context features, eligible/excluded counts, scores, query coverage,
up to 10 candidate IDs and rejection/selection reasons, plus actual injected count/bytes.
It retains at most 8,000 bytes (+ truncation marker) in memory, not a database/session log;
no memory bodies or provider errors are included. It resets on reload and is not proof
of what the model subsequently understood. Empty/no-match turns replace the old snapshot. Pin protects against automatic replacement/age expiry,
not manual edits, and does not force an unrelated record into every prompt. Pin/unpin
and adoption, feedback and conflict resolution preserve the stored evidence date; undo restores the prior date. These
bookkeeping actions do not restart the seven-day project-state recall window. Alias-only
model enrichment also preserves that date. A new, explicitly incorporated progress
observation can refresh it, even if the observed state is still unchanged/pending.
Manual correction clears old search aliases rather than attaching them to new content.
Undo reverses claim changes only when the affected records have not changed since;
it is not a database rollback. Suppression hashes remain, and jobs are not reopened.
Suppression retires pending sources known to repeat that fact, not just its first parent.
This skips the entire pending model pass for those sources; unrelated local claims remain,
but unlearned prose may need to be restated in a new source. Job state done also includes
these retired sources; history identifies actual model transactions.
There is no /memory confirm, /evolution approve, or owner-approval step in 0.2.
On first database use, valid memories.jsonl and memory-actions.jsonl are imported
once in a transaction. Original files are not modified or deleted. Corrupt or
unreadable ledgers stop migration rather than silently ignoring forget/correct actions.
Old records without origin metadata retain the label legacy. They participate in
relevance-based recall without adoption, with their unknown origin visible. Use
/memory list legacy [page] for inspection; /memory adopt <id> is an optional metadata
annotation, not a prerequisite for recall. Structured claims are extracted from eligible
legacy summaries, respecting existing lifecycle actions. Free-form raw summaries
remain available in the original JSONL but are not injected as claims. New imports
preserve unchanged children of corrected summaries and carry superseded-content hashes
when corrected legacy claims are adopted into a project.
Upgrading from earlier 0.2 development builds: stop Pi and back up the state directory first, then update/reload all Pi processes sharing it. Schema markers 2–6 upgrade transactionally to 7, adding missing recovery/feedback fields, source call/time/model budgets, provider cooldowns and usage receipts. Known v6 route waits are separated from source failure backoff; retained call history seeds counters without inventing missing calls. Existing records, IDs, histories and evidence dates remain unchanged. Missing evidence stays unknown, with no fabricated backfill. Existing failures below the limit become automatically eligible; their old error cause/time remain labeled unknown rather than invented. No copying, manual marker reset or JSONL re-import is needed. Older builds reject schema 7; rollback requires a matching backup, not editing the marker. Existing records are immediately eligible for global relevance-based recall. Legacy claims previously excluded by cwd filtering become eligible too. This shares relevant stored claims with the active Pi session/provider, not raw session archives.
Empty/missing ledgers do not mark an import completed. After supplying files, use
/memory import [directory]. Provably empty v6 snapshots can reopen safely; a zero claim
count alone never authorizes replay of a real consumed ledger. See migration details.
These migration fixes do not replay an already completed real import or retroactively erase previously stored sensitive data. If an older import already lost revision information, use the preserved ledgers/backup to review and correct affected records; do not reset the migration marker or replace a populated database blindly.
Old signals, agenda, thresholds, proposals, journals and execution plans are historical files only. This version neither processes nor deletes them. Back up the entire state directory with Pi stopped before changing versions. Returning to 0.1 reads the old JSONL, not changes made in the new database.
- No
/memorycommand: checkpi list, then/reload(or restart Pi). Only one source of this extension should be installed. Processes marked by a nonemptyPI_SUBAGENT_AGENT_IDdeliberately do not load it. - No recalled memories: check the active agent directory and
/memory search <topic>. Name the topic if the current session has no recent user context; cwd is not a recall gate./memory explainshows the last automatic decision;explain <query>previews an explicit query without invoking a model or updating claims. Forgotten/conflicted records and unpinned project state older than seven days are not recalled. Matching remains lexical, not a guarantee of semantic or cross-language equivalence; vague references and languages/terms outside the concept map or learned aliases can still be missed. - Old progress still shown:
/memory learningdistinguishes no work observation, no update targets, already captured and newly captured sources, with retained/omitted observation counts and nomination reasons./memory statusshows actual changed-record counts from recent model transactions:donemeans processed/retired, not learned. Age/weight does not prove a task finished. A new eligible work observation or compaction can update tracked progress; upgrading alone does not invent completion or replay old tool transcripts. Inspect/memory show <id>and history, or correct the record explicitly when you know the current state. - Pending/failed jobs: normally no command is needed: leave Pi running and recovery
automatically processes due work.
/memory statusdistinguishes scheduled retries from paused sources and shows the next eligible time (the next poll may be up to 15 seconds later when no local work is queued). After a crash, the 150-second lease must expire first. Inspect source call/time/output limits as well as failure count. Status distinguishesauth,quota,rate_limit,context_limit,request,safety, transport, output and stale-write failures. Provider cooldowns are separate from source retry times; switching providers cannot bypass the shared budget./memory evolvemakes one explicit source attempt without resetting counters or overriding shared ceilings. See error policy. A bad source remains saved/visible rather than being deleted or labeled successful. - Persistent storage/import errors: stop all Pi processes using that agent directory
and back up the entire state directory, including any SQLite sidecars and legacy
ledgers. Check file permissions and restore a known-good matching backup if needed.
Do not delete
memory-actions.jsonlto bypass an import failure: that can discard forget/correct history. Failed imports can retry after repairing the original ledgers; successful imports are never replayed merely because the old JSONL changes. - Disable the extension:
pi remove <installed-source>, then/reload. Its local database remains on disk. Restore/replace state only with all processes using it stopped; do not mix one backup's database with another's WAL/SHM files.
Diagnostics intentionally do not echo provider error bodies, which may contain secrets.
SQLite ok (schema 7) checks database structure/record validity, not the truth of model claims.