reflect-memory — recall reference (all 57 ports)
“Correct once, never again.” This is the reference half of reflect-memory: first one learning’s whole journey (the newcomer’s mental model), then every ported feature as a callout — flag, what it does, an example, and the counterfactual: what you’d get if it didn’t exist.
For the architecture see Construct; for the problem and the landscape comparison see Problem & fit and Why build, not adopt.
Examples are illustrative
The reflect search … examples and their results below are representative, hand-authored to show
the behaviour — not pasted from a specific live KB run. Every feature is backed by a behavioural
proof under tests/eval/behavioral/proofs/
that exercises it with the knob on and off.
Memory end to end — one learning’s journey
Follow one correction from the moment it happens to the moment it saves you weeks later.
1 · Capture. Mid-session you tell the agent: “no — don’t bump the shared payments.proto
without regenerating the clients, it broke staging last time.” A PostToolUse/Stop hook detects
the correction signal, slices just the relevant dialogue window (not the whole 100k-token transcript),
and the drain writes a structured learning:
---title: "Regenerate gRPC clients after editing payments.proto"category: reliabilitytags: [grpc, proto, payments, codegen]confidence: 0.8project_id: billing-svcproblem: "Bumped payments.proto without regenerating clients"fix: "Run `make proto-gen` after any .proto edit; CI now gates on it"rule: "Never ship a .proto change without regenerated clients"---Alongside it, an entity sidecar records payments.proto —[prevents]→ staging outage.
2 · Index. reflect reindex embeds the note (vector arm), adds its entities + edges to the
GraphRAG graph (graph arm), and registers it in the BM25 index (QMD arm). It’s now reachable three
different ways.
3 · Recall — three weeks later, a different session. A new teammate’s agent opens billing-svc
and is about to edit payments.proto. SessionStart fires, builds a query from project + branch
context, and runs hybrid recall: the vector arm matches on meaning, the BM25 arm matches the
literal payments.proto, the graph arm hops the prevents edge — RRF fuses the rankings,
the cross-encoder reranks, the OOD gate confirms relevance, the token budget packs it in.
Before the agent writes a line, it sees: “Regenerate gRPC clients after editing payments.proto —
broke staging last time; run make proto-gen.” The mistake never happens twice. That whole chain —
capture → index → fuse → rerank → gate → inject — is what the 57 ports tune.
The 57 ports at a glance
┌──────────────────────── recall time ───────────────────────┐
query ─▶ [arms] ─▶ RRF fuse ─▶ [rerank] ─▶ [gate] ─▶ [boosts] ─▶ budget ─▶ inject
R1·R5·R6 R2·R3 R7·R12 R8·R16
─────────────────── scope: R15·A6 · modes: M1·R10·R11 ────────────────
- Retrieval arms — R1 R5 R6 R2 R3 R4 → § below
- Relevance gates — R7 R12 → § below
- Ranking & affinity boosts — R8 R16 S3 S4 → § below
- Scope: sharding & isolation — R15 A6 → § below
- Recall modes & inject — M1 R10 R11 M7 M4 O3 A1 R20 → § below
- Caching, dedup & negative-recall — R9 S7 C1 A3 SG6 S1 → § below
- Capture · storage · consolidation · team (the other 29) → § below
All 57: R1–R16 + R20 (17 retrieval/recall), M1–M8 (8 modes), S1–S10 (10 capture/storage), A1–A6 (6 advanced), C1–C5 (5 consolidation), O1–O3 (3 observations), SG1–SG8 (8 signals). (No R17–R19 — the R-series jumps R16 → R20.) ★ = has a worked example below.
Retrieval arms
The parallel signals that find candidates, plus the post-fusion shapers that order them.
RECALL_GRAPH_ARM (on)Does A 3rd arm walks the entity graph and fuses notes you never matched lexically. e.g. “why does checkout call recalcTax twice?” → hops caused_by to the EU-VAT rounding note.
Without it Only the lexically-matching note; you “fix” the perf and re-introduce the rounding bug the double-call fixed.
RECALL_TEMPORAL_ARM (on)Does When a date phrase is found (R6), a 4th arm fuses notes whose timestamp falls in the window. e.g. “what did we decide last week about auth”.
Without it In-window notes get crowded out by topical arms; recent decisions don't surface.
RECALL_TEMPORAL (on)Does Regex-extracts “last week” / “in march” / “since 2026-01-01” into a real date range that feeds R5.
Without it “last week” is just two more keywords; temporal intent silently dropped.
RECALL_CROSS_ENCODER (on)Does Re-reads the top-20 jointly with the query (local MiniLM CE) and re-sorts by meaning. “flaky test in the auth suite” lifts the real answer over a keyword-similar “auth token format”.
Without it The keyword-similar-but-wrong note wins rank 1; right prior art misses a tight budget.
RECALL_MMR (on) / --no-mmrDoes Final top-k via Maximal Marginal Relevance — de-clusters near-duplicates. “nginx 502 under load” surfaces the lone “enable keepalive” note past 4 “raise worker_connections” twins.
Without it Top-k is 4 copies of one idea; the second, correct idea sits at rank 6, never injected.
--max-tokens NDoes Packs ranked notes by estimated tokens until the budget is hit, instead of a fixed top-k. reflect search "deploy steps" --max-tokens 1500.
Without it A fixed top-k blows the window on a verbose corpus; long notes evict the user's own files.
Relevance gates
--min-overlapDoes Measures query-term coverage of the top hit; below threshold it injects nothing (ood_gated). --min-overlap 0.3 in a fresh repo.
Without it Every session gets the least-bad junk; the agent learns to ignore the inject block.
RECALL_ARM_<NAME>_MIN_SCOREDoes A per-arm floor applied before RRF (arm scores aren't comparable). RECALL_ARM_BM25_MIN_SCORE=0.15 drops weak BM25 hits without nuking strong graph hits. Seed via reflect calibrate-thresholds.
Without it One global cutoff either lets BM25 noise through or starves the graph arm.
Ranking & affinity boosts
Secondary signals that break ties — each bounded so it can nudge, never hijack.
RECALL_*_ALPHADoes Each signal applied as 1+α·(norm−0.5), clamped to ±α/2 — recency / confidence / tags / proof break ties only (defaults 0.2/0.2/0.2/0.1).
Without it Unbounded boosts let “most recent” bury a 2-year-old note that perfectly answers the query.
RECALL_PROJECT_ALPHA (0.2)Does Under --global, current-project notes get a capped +10% lift over equally-relevant foreign ones.
Without it Cross-project recall treats every project equally; a foreign note outranks your own.
--field confidence_numDoes Stores continuous 0–1 confidence as the canonical ranking value; HIGH/MED/LOW are display buckets.
Without it Coarse tiers can't separate two “HIGH” notes; ranking loses a real signal.
RECALL_PROOF_ALPHA (0.1)Does First-class proof_count provenance nudges ranking ±5% and is projectable via --field proof_count.
Without it A note proven 12 times ranks identically to an unverified one.
Scope: sharding & isolation
--global / RECALL_GLOBALDoes Each project has its own nano-graphrag shard; recall defaults to the current project's. --global unions across all.
Without it Every project's recall is polluted by every other's; the relevant local note drowns.
RECALL_BRANCH / --all-branchesDoes Within a project, each git branch/worktree gets a sub-shard; recall pins to the current branch.
Without it A speculative note from an abandoned feat/y surfaces as fact while you work feat/x.
Recall modes & inject
reflect index → reflect hydrateDoes Index-then-hydrate: returns token-capped ID-only rows; the agent hydrates only the ids it wants.
Without it Every recall pays full-body cost for every candidate; deep digs become token-prohibitive.
REFLECT_TIERED_INJECTDoes SessionStart consults curated skills first; a strong skill hit is injected and raw recall skipped.
Without it Every session runs full raw recall even when a promoted skill already has the answer.
Does If the tier-1 skill hit is fresh and high-confidence, SessionStart emits just that and never spawns the recall subprocess.
Without it Warm-project boots needlessly spawn the full pipeline — slow and noisy.
reflect corpus buildDoes Snapshots a filtered KB subset into corpora/<name>.json for a primed, deterministic Q&A scope.
Without it No way to pin recall to a curated subset; every query hits the whole corpus.
REFLECT_MODEDoes Loads taxonomy + prompt templates from a mode JSON (deep-merge inheritance); drives learning types + economics glyphs.
Without it One hard-coded taxonomy; research/writing workflows can't retune what's captured/surfaced.
Does A high-confidence distilled field (e.g. testing_style='TDD') answers an open-domain query directly. “what testing style does this project use?”
Without it The question falls through to generic recall; a known team fact isn't answered crisply.
REFLECT_SLOTSDoes A pinned scratchpad slot per (project, name) injected at Tier-0, ahead of skills/recall, regardless of ranking.
Without it No way to force an always-present note; critical context depends on it ranking well.
Does A queryable sqlite index of installed skills (name/tags/summary) replaces per-query SKILL.md scanning; feeds R10/R11.
Without it Tiered inject rescans every SKILL.md per query; slower, and never matches an unindexed skill.
Caching, dedup & negative-recall
RECALL_FUZZY_CACHE (on)Does A reworded repeat within the Jaccard threshold (0.85) is served from cache — skips embed+graph+rerank.
Without it Every rephrasing pays the full retrieval cost; a debugging back-and-forth re-runs it dozens of times.
Does Slice-chunk hashing at drain so re-draining the same transcript doesn't duplicate the learning.
Without it Recall returns two copies of the same lesson; duplicates crowd the top-k.
REFLECT_DEDUP_THRESHOLD (0.97)Does Before a CREATE lands, an embedding-cosine twin ≥ threshold is held as a “merge?” adjudication.
Without it Near-identical phrasings accumulate; the KB bloats with restatements of one idea.
forget_after TTL prune · hourly sweepDoes Expired learnings are archived and moved to .forgotten/; permanent/future ones survive.
Without it Stale, time-boxed notes linger forever and keep surfacing past their relevance.
RECALL_GAP_LOG (on)Does A 0-result recall logs {query, normalized, session_id} to knowledge-gaps.jsonl as a curation backlog.
Without it Misses vanish silently; you never learn what the KB should have known.
--field NAMEDoes Projects a single typed field (rule/fix/problem/…) instead of the whole note.
Without it Every hit returns the full note body; context-expensive when you only need the rule.
Worked examples
Illustrative command → output for the marquee arms (representative, not a live run).
R1 · graph-expansion
$ reflect search "why does checkout call recalcTax twice"✓ recalcTax is idempotent but expensive (vector + bm25)✓ double-call fixes an EU-VAT rounding bug (a1b2c3) (graph: caused_by hop) ← never matched lexicallyR2 · cross-encoder rerank
$ reflect search "flaky test in the auth suite" RRF rank 1: auth token format … ← keyword-heavy, wrong→ CE rank 1: auth integration test flaky under parallel xdist ← answers the questionR5 · temporal arm
$ reflect search "what's our current API auth"✓ migrated to server-side sessions (Jun) ← temporal arm lifts recent we use JWT (Apr) ← older, more-cited, demotedR7 · OOD gate
$ reflect search "totally unrelated topic" --min-overlap 0.3∅ ood_gated — top hit overlap 0.08 < 0.3 → injected nothing (no least-bad junk)M1 · staged recall
$ reflect index "tokio panic on shutdown" # token-capped id+title rows [a17] Graceful tokio shutdown ordering score 0.82 [c44] Abort vs cancel on JoinHandle score 0.71$ reflect hydrate a17 c44 # full bodies only for what you pickedThe other 29 — capture, storage, consolidation, team
Not query-time features, but the plumbing that fills and maintains the KB the recall arms read. Listed for completeness so the full 57 are accounted for. (Scroll horizontally.)
| Feature | Category | Flag (default) | What it does |
|---|---|---|---|
| M2 Writer-output classifier + breaker | capture | REFLECT_DRAIN_INVALID_THRESHOLD (3) | Kills + archives a drifting/poisoned writer after N bad outputs. |
| M3 Quota-aware writer abort | capture | REFLECT_DRAIN_DAILY_MAX | Defers the whole drain queue when the daily LLM gate is closed, instead of burning the cap. |
| M5 Commit-reference verification | capture | always-on | Checks every cited commit hash against the repo; rejects all-fabricated notes, flags partials. |
| M6 Private-tag strip | capture | always-on | Strips <private> spans at the LLM-prompt boundary so they never reach the writer/index. |
| M8 Token-economics surfacing | dashboard | RECALL_ECONOMICS (on) | Annotates each result with discovery/read tokens + savings % and a mode glyph. |
| S2 Typed causal-link enum | capture | always-on | Closed enum for sidecar relations (caused_by / causes / enables / prevents / contradicts / supersedes / part_of / uses). |
| S5 Belief-revision on ingest | capture | always-on | Runs CREATE/UPDATE/DELETE against reflect.db so new learnings revise prior beliefs. |
| S6 History snapshot on update | capture | always-on | Snapshots the prior form into learning_history before mutating a live row. |
| S8 Doc→chunk→learning grouping | capture | always-on | Persists each learning's lineage back to its source transcript + chunk. |
| S9 Volatile-signals sidecar | capture | always-on | Moves churning signals (recall_count, helpful_count…) out of note markdown into a DB sidecar — clean git diffs. |
| S10 Write-validate-retry loop | capture | always-on (3 tries) | Validates structure + sidecar after write; re-prompts; flags unfixable notes validated: false. |
| R13 Auto skill-refresh trigger | capture | always-on | Flags an existing skill for refresh when a learning it covers lands. |
| R14 Per-skill staleness signal | signal | REFLECT_STALENESS_DAYS (30) | Marks a skill is_stale when an in-scope learning changed after its last refresh. |
| SG1 Cross-turn contradiction | capture | always-on | Detects + reconciles contradicting learnings at capture (sets is_latest). |
| SG2 Git-event capture | capture | always-on | Links commits↔sessions; demotes a reverted commit's learnings on git revert. |
| SG3 Idle-sweep trigger | signal | REFLECT_IDLE_THRESHOLD_SEC | Idle timer sweeps quiet transcripts into speculative learnings (down-ranked at recall). |
| SG4 Test-outcome parsing | signal | always-on | Parses pass/fail from Bash output in PostToolUse into a capture signal. |
| SG5 Tool-loop detection | signal | always-on | Detects repeated/oscillating tool-call loops as a signal. |
| SG7 TodoWrite completion signal | signal | always-on | Emits a “how I did X” candidate when a todo flips to completed. |
| SG8 Permission-reply capture | signal | always-on | Captures permission-prompt allow/deny replies as policy learnings. |
| A2 Bitemporal graph edges | infra | always-on | Edges carry tcommit / tvalid / tvalid_end — “what was true” vs “what we knew” stay separable. |
| A4 Followup-rate diagnostic | dashboard | RECALL_FOLLOWUP (on) | Logs a recall-quality verdict (did the user immediately re-query differently?) to metrics. |
| A5 Synthetic compression fallback | capture | drain --no-llm | Builds a structured learning from heuristics alone when the drain LLM is unavailable. |
| C2 Auto-consolidation threshold | consolidation | REFLECT_SYNTHESIS_AUTO_THRESHOLD (30) | Fires the synthesis pass early once learnings-since-last-consolidation cross the threshold. |
| C3 Graph maintenance sweep | consolidation | every N drains | Structural rewrite of the local graphml to repair orphan edges after deletes. |
| C4 Lifecycle events fan-out | infra | REFLECT_EVENTS_ON_<EVENT> | Appends lifecycle events to events.jsonl + runs per-event shell hooks (local webhooks). |
| C5 KB export/import round-trip | team | kb_export.py / kb_import.py | Snapshots documents/ + reflect.db into one git-friendly tarball; byte-identical restore elsewhere. |
| O1 Consolidated observations | consolidation | always-on | A 2nd drain stream of persona/convention statements that accumulate evidence over time. |
| O2 Auto-refreshing conventions doc | consolidation | always-on | Re-renders a conventions markdown doc from accumulated observations each consolidation. |
Every feature above is verified by a behavioural proof under
tests/eval/behavioral/proofs/
(57 proof_*.py, one per port). See the reflect CLI reference for how to
drive recall directly.