Troubleshooting
Diagnosis-first guide for the five failures that look like “memory is broken” but are really routing failures. Every step uses tools that already ship with Pi Hindsight S1 Enhanced — no scratch commands and no hand-built HTTP calls.
Start with Triage, then jump to the symptom that matches. The full routing model is in Memory behavior → Decision-driven bank routing.
Triage order
Section titled “Triage order”Run these first, in this order. Together they answer most of the five symptoms.
hindsight_status— setup gate, project scope tags, queue depth, server reachability, andhostMemoryBackend.hindsight_bank_list— the routing table: which banks Pi is configured to use, each one’saccess(read / write / read-write) and retain mode (always/decision/explicit-only).hindsight_config_get— the effective allowlisted config:recall.mode,recall.bankMode,banks[].retain.mode,decision.*,banksFallback.hindsight_bank_getfor the suspect bank — whether that bank exists on the Hindsight side at all.
Then branch:
| Symptom | Root cause section |
|---|---|
| First recall injects nothing, no memory ever appears | Bank missing or not created |
| Banks exist, but every routing decision falls back to the same bank | Decision model cannot answer |
| A bank you configured is never written | Misspelled or missing bankId |
| Decisions route as if no work were in progress | Todo state unreadable |
| Nothing is ever written or read, in any mode | Setup gate closed |
1. Bank missing or not created
Section titled “1. Bank missing or not created”Symptom. The first automatic recall injects nothing. No error, no bank appears afterwards, and explicit retains that target the bank by id fail or create nothing reusable.
Root cause. The bank was never created, or was created under a different id. Automatic recall reads whatever exists; if the configured bank id does not resolve, there is nothing to read. The extension ensures the project bank only after the setup gate passes, so on a new install without a bank id there is no bank to ensure.
Verify.
hindsight_bank_list— check every entry you expect has a resolvablebankIdandenabled: true.hindsight_bank_getwith thatbankId— confirm the bank exists on the Hindsight side (existence, not just Pi-local config).hindsight_status— readsetupComplete.falsemeans the setup gate blocked automatic bank creation; the status also carriessetupHintnaming the next action.
Fix.
- If
setupCompleteis false, complete setup first: run/hindsightand follow guided setup, or set the bank id explicitly (banks[].bankId, orPI_HINDSIGHT_PROJECT_BANK_ID). See symptom 5 — an unconfigured install gets no automatic bank, and therefore no automatic memory. - If the id is missing, set it in config (
hindsight_config_set) or create the bank with the id you meant. - Re-run recall in a new turn; the decision cache (
decision.cacheTtlMs, 60s by default) and the recall block cache can otherwise replay the empty result.
2. Decision model cannot answer
Section titled “2. Decision model cannot answer”Symptom. Nothing is obviously broken — recall keeps working and no error surfaces — but every turn routes to the same bank (usually the coding bank), whatever the question was.
Root cause. Every backend rung failed or was unusable, so every decision fell through to decision.fallback and then to banksFallback. The layer is designed to do exactly this: a failing decision model costs routing quality, never memory. The common causes are a disabled layer, a model spec that does not resolve on this host, a timeout, or a backend that answered an incomplete question table.
Verify.
hindsight_config_get— confirmdecision.enabledis true anddecision.modelresolves to something this host has. Arole:<name>spec is a skipped level on pi, not an error: it degrades to the session model.<provider>/<modelId>works on both hosts.- Check that routing is actually being asked for:
recall.mode: "decision"and/orrecall.bankMode: "decision", and/or an entry inbanks[].retain.mode: "decision". With none of those, no decision call is made and fixed routing is correct behavior, not a fault. hindsight_config_get— confirmdecision.fallback.recallBanks/retainBanks(or top-levelbanksFallback) names a real entry id. An empty or stale fallback list is why a failed decision lands on the same bank every time.- Watch the
hindsight:retrievalevent bus forphase: "decision"spans and readreason:no-model,backends-failed,disabled, andno-candidateseach point at a different cause.
Fix.
- Set
decision.modelto a spec the host can resolve —<provider>/<modelId>for a portable setup,role:<name>on a host that has that role. - Set an explicit fallback so a failed decision still routes somewhere sensible:
decision.fallback.recallBanks/retainBanks, orbanksFallback. - Raise
decision.timeoutMsif slow backends are timing out; lower it if an unreachable backend is stalling each turn.
Do not treat this as data loss. Nothing went missing — the round was routed, just not well.
3. Misspelled or missing bankId
Section titled “3. Misspelled or missing bankId”Symptom. One configured bank never receives writes. Every other bank behaves. Nothing about it changes when you edit modes.
Root cause. Write routing needs a concrete bank id. The coding-role entry resolves to the derived project bank; every other entry needs its own bankId, and an entry without one is skipped as unresolved. A typo has the same effect: the configured id does not match any candidate, so the id is refused and reported rather than written. This is silent from the transcript’s point of view — the turn looks normal.
Verify.
hindsight_bank_list— readbankIdper entry character by character. Confirm each non-coding entry has one, and compare it againsthindsight_bank_get, which asks Hindsight itself whether that bank resolves.hindsight_bank_getwith the suspectbankId— a missing bank distinguishes a typo from a bank that was simply never created.- Watch
hindsight:retrievalphase: "retain"spans fordroppedBanks. Refused ids — not offered, or no longer eligible — are listed there instead of being written quietly.
Fix.
- Correct the id in config with
hindsight_config_set, or create the intended bank so the id resolves. - Confirm the entry is also enabled and write-capable (
accessiswriteorread-write,retain.enablednot false); access-incompatible entries are skipped as well.
4. Todo state unreadable
Section titled “4. Todo state unreadable”Symptom. Routing decisions look right for small talk but wrong for real work — a turn mid-task gets no project recall, or the decision quotes no open work.
Root cause. The decision prompt carries the host task state, and the two hosts read it differently. If no reader can read it, the state is unknown.
- omp — read through the
omp-todo-moreread event; projects to{kind:"ok", goal, openItems:[{phase,title,explanation}]}or{kind:"unavailable"}. - pi — read from the
rpiv-todo-statesession entry on the branch (TaskDetails{tasks: Task[], nextId}).
{kind: "unavailable"} and unknown are not “no tasks”. An unreadable task list is not an empty one: the layer treats it as task state unknown and decides accordingly, rather than concluding nothing is in flight. So a missing todo plugin changes decision quality, never the presence of memory.
Verify.
- Confirm the host’s todo surface exists at all: on omp, that the todo plugin is loaded and answering; on pi, that a
rpiv-todo-stateentry exists on the branch. - Compare what the host shows against what the decision saw. Since the last user message and the task state are never truncated by
decision.maxContextChars, a missing task state is a read failure, not a budget cut. - If routing quality matters here, sanity-check the layer is being consulted at all with
hindsight_config_get(recall.mode/recall.bankMode/ retain modes).
Fix.
- Enable or repair the host’s todo surface. This is the only real fix — the extension reads the host’s own state and does not keep a private copy.
- If the surface cannot be available, simplify the routing question: prefer
recall.bankMode: "all"orretain.mode: "always"overdecision, so routing no longer depends on task state you cannot read.
5. Setup gate closed or automatic memory off
Section titled “5. Setup gate closed or automatic memory off”Symptom. Nothing is remembered in any mode. Recall injects nothing, retain writes nothing, no queue grows, and there is no error in the transcript — possibly accompanied by a startup notice telling you automatic memory is off.
Root cause. Automatic memory never started, so none of the above could run. Two gates must pass:
- A setup signal must exist. Any one of:
setupComplete: true, a coding or user entry carrying abankId, a project config file (.pi/hindsight.json/.pi/hindsight.jsonc), or local runtime state under.pi/hindsight/(queue file,retain-cursors.json, import manifest, or last-recall snapshot). - Domain-tagged mode needs an explicit coding bank id.
requiresExplicitCodingBankId=scope.mode === "domain-tagged"and a coding entry that is enabled. In that mode a path-derived bank id is not enough — the extension will not silently auto-operate on a path-derived bank as if it were a shared coding domain.isolated-bankmode may still path-derive.
When the gate fails, /hindsight and the status surface show the hint: run /hindsight, or set banks.project.bankId (or PI_HINDSIGHT_PROJECT_BANK_ID). Until then automatic memory is off, which is why nothing else in this page can bite.
Verify.
hindsight_status— readsetupComplete.falsemeans the gate is closed; the response carriessetupHintwith the concrete next action.hindsight_config_get— readscope.mode.domain-taggedis the mode that additionally demands an explicit coding bank id.hindsight_bank_list— confirm the coding entry is enabled and has a non-emptybankId.omp config get memory.backend— omp only. When it is notoff, omp’s built-in memory backend is running alongside this extension and you have two entry points writing two different banks.hindsight_statusreports this as itshostMemoryBackendfact;redundant: trueis the signal. Symmetric fixes:omp config reset memory.backend(oromp config set memory.backend off), or/hindsight:omp-backendand pickoff.available: falsemeans the CLI could not answer — run it manually rather than guessing.
Fix.
- Run
/hindsightand complete guided setup (pick a profile, set bank ids). This satisfies both gates in one pass. - Or set the id directly:
banks.project.bankIdviahindsight_config_set, orPI_HINDSIGHT_PROJECT_BANK_ID, or the top-levelbanks[]entry. - In domain-tagged mode, an explicit coding
bankIdis mandatory;isolated-bankmode may keep deriving from the path. - On omp, make sure only one memory entry point is active (step 4 above).
Related
Section titled “Related”- Memory behavior → Decision-driven bank routing — the full model: gates, fallback chain, cache, and degradation philosophy.
- Configuration → Decision layer — field-by-field meaning of
decision.*. - Tools and commands — what every tool above reads and writes.
- The
hindsight-memory-doctorskill — the same checks run as a guided diagnosis when memory itself is in question.