{"id":48388651,"url":"https://github.com/strvmarv/total-recall","last_synced_at":"2026-07-11T05:00:34.802Z","repository":{"id":349239901,"uuid":"1201576622","full_name":"strvmarv/total-recall","owner":"strvmarv","description":"Multi-tiered memory and knowledge base plugin for TUI coding assistants (Claude Code, Copilot CLI, OpenCode, Cline, Cursor)","archived":false,"fork":false,"pushed_at":"2026-06-23T00:50:01.000Z","size":4503,"stargazers_count":11,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-23T02:20:21.178Z","etag":null,"topics":["ai-coding","claude-code","copilot-cli","knowledge-base","mcp","memory","sqlite","tui","vector-search"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strvmarv.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-04T21:36:25.000Z","updated_at":"2026-06-23T00:47:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/strvmarv/total-recall","commit_stats":null,"previous_names":["strvmarv/total-recall"],"tags_count":119,"template":false,"template_full_name":null,"purl":"pkg:github/strvmarv/total-recall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvmarv%2Ftotal-recall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvmarv%2Ftotal-recall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvmarv%2Ftotal-recall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvmarv%2Ftotal-recall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strvmarv","download_url":"https://codeload.github.com/strvmarv/total-recall/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strvmarv%2Ftotal-recall/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35351426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-coding","claude-code","copilot-cli","knowledge-base","mcp","memory","sqlite","tui","vector-search"],"created_at":"2026-04-05T23:00:27.221Z","updated_at":"2026-07-11T05:00:34.795Z","avatar_url":"https://github.com/strvmarv.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"```\n╔══════════════════════════════════════════════╗\n║  REKALL INC. -- MEMORY IMPLANT SYSTEM v2.84  ║\n╠══════════════════════════════════════════════╣\n║                                              ║\n║  CLIENT: Quaid, Douglas                      ║\n║  STATUS: MEMORY EXTRACTION IN PROGRESS       ║\n║                                              ║\n║  \u003e Loading tier: STICKY ......... [OK]       ║\n║  \u003e Loading tier: HOT ............ [OK]       ║\n║  \u003e Loading tier: WARM ........... [OK]       ║\n║  \u003e Loading tier: COLD ........... [OK]       ║\n║  \u003e Semantic index: 384 dimensions  [OK]      ║\n║  \u003e Vector search: ONLINE                     ║\n║                                              ║\n║  ┌──────────────────────────────────┐        ║\n║  │ SELECT PACKAGE:                  │        ║\n║  │                                  │        ║\n║  │  [x] Total Recall -- $899        │        ║\n║  │  [ ] Blue Sky on Mars            │        ║\n║  │  [ ] Secret Agent                │        ║\n║  └──────────────────────────────────┘        ║\n║                                              ║\n║  \"For the Memory of a Lifetime\"              ║\n╚══════════════════════════════════════════════╝\n```\n\n[![CI](https://github.com/strvmarv/total-recall/actions/workflows/dotnet-ci.yml/badge.svg)](https://github.com/strvmarv/total-recall/actions/workflows/dotnet-ci.yml)\n[![npm](https://img.shields.io/npm/v/@strvmarv/total-recall)](https://www.npmjs.com/package/@strvmarv/total-recall)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n# total-recall\n\n**Persistent, cross-tool memory for AI coding assistants.**\n\nYour AI forgets everything when the session ends. Preferences, decisions, project context, corrections — gone. total-recall fixes that: a shared memory layer that persists across sessions, tools, and devices.\n\n---\n\n## The Problem\n\nEvery TUI coding assistant has the same gaps:\n\n- **No memory between sessions** — every new session starts from zero, repeating the same context\n- **Siloed by tool** — switching between Claude Code and Copilot CLI means starting from scratch\n- **Single-machine** — your context doesn't follow you across devices\n- **Context bloat** — stuffing everything into a `CLAUDE.md` wastes tokens every prompt\n- **No token visibility** — no way to know what your AI sessions actually cost\n\n---\n\n## The Solution\n\n- **Persistent memory** — corrections, preferences, decisions, and project context survive sessions automatically\n- **Cross-tool** — one memory store shared across Claude Code, Copilot CLI, Cursor, Cline, OpenCode, and Hermes; existing memories auto-import on first run\n- **Built-in web UI** — `total-recall ui` opens a local browser dashboard (Dashboard, Memory, Knowledge Base, Usage, Insights, Eval, Config) for visual memory management without touching the CLI or AI session. Dark/light themes, a keyboard-first ⌘K command palette, and a developer-native *Terminal / Archive* design\n- **Cross-device** — point `TOTAL_RECALL_DB_PATH` at a cloud-synced folder and your memory follows you everywhere\n- **Smarter context, lower token cost** — a three-tier model (Hot / Warm / Cold, with sticky pins) enforces a 4000-token budget per prompt; new memories land in warm and earn their way into hot, so you get relevant context without carrying everything\n- **Token expenditure tracking** — see exactly what each session costs, broken down by host, project, and time window\n- **Knowledge base** — ingest your docs, READMEs, API references, and architecture notes; retrieved semantically when relevant\n- **Observability** — measure retrieval quality, run benchmarks, and compare config changes with the built-in eval framework\n\nBy default, all state is local: SQLite + vector embeddings, no external services, no API keys. For teams, configure a shared Postgres/pgvector backend and remote embedder — same binary, just config.\n\n---\n\n## Quick Start\n\n### Self-Install (Paste Into Any AI Coding Assistant)\n\n\u003e Install the total-recall memory plugin: fetch and follow the instructions at https://raw.githubusercontent.com/strvmarv/total-recall/main/INSTALL.md\n\nThat's it. Your AI assistant will read the instructions and install total-recall for its platform.\n\n### Claude Code\n\n```\n/plugin install total-recall@strvmarv-total-recall-marketplace\n```\n\nOr if the marketplace isn't registered:\n\n```\n/plugin marketplace add strvmarv/total-recall-marketplace\n/plugin install total-recall@strvmarv-total-recall-marketplace\n```\n\n### npm (Any MCP-Compatible Tool)\n\n```bash\nnpm install -g @strvmarv/total-recall\n```\n\nThen add to your tool's MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"total-recall\": {\n      \"command\": \"total-recall\"\n    }\n  }\n}\n```\n\nThis works with **Copilot CLI**, **OpenCode**, **Cline**, **Cursor**, **Hermes**, and any other MCP-compatible tool. The `total-recall ui` command is available independently of MCP configuration — it is a local management surface, not a host tool.\n\n\u003e **Note:** `npx -y @strvmarv/total-recall` does not work due to an [npm bug](https://github.com/npm/cli/issues/3753) with scoped package binaries. Use the global install (`total-recall` command) instead.\n\n---\n\n## What Gets Remembered\n\nEvery memory has an entry type that tells total-recall what it is and how to treat it.\n\n| Entry Type | Stored When | Example |\n|---|---|---|\n| `Correction` | You fix a mistake the AI made | `\"Use Array.from() not spread for NodeList — spread fails in our build target\"` |\n| `Preference` | You state a style or workflow preference | `\"Always use const over let unless reassignment is needed\"` |\n| `Decision` | You make an architecture or design choice | `\"Using Zustand for state — Redux was overkill for this app size\"` |\n| `Surfaced` | The AI captures context automatically | Key facts, constraints, or project-specific patterns noticed during work |\n| `Imported` | First-run import from another tool | Your existing Claude Code memories, Copilot snippets, Cursor history |\n| `Compacted` | Tier compaction generates a summary | Multiple related memories merged into a higher-signal entry |\n| `Ingested` | You ingest a file or directory | Chunks from READMEs, API docs, architecture notes |\n\n**`Correction` and `Preference` entries get priority treatment.** They surface as actionable hints at every session start and carry higher decay scores — helping them earn promotion into the hot tier and resist eviction once there.\n\n---\n\n## How It Works\n\n### Tier Model\n\ntotal-recall uses a three-tier memory model — **Hot / Warm / Cold** — with a **sticky** flag that turns any hot entry into an always-injected pin. New memories land in **Warm** by default and *earn* their way into Hot by proving useful, so the auto-injected context stays high-signal without carrying everything:\n\n- **Warm** (default landing tier, up to 10K entries) — where new memories go unless you say otherwise. Retrieved semantically per query: when you ask about authentication, relevant auth memories surface automatically. An entry is **promoted to Hot** once it earns it — `access_count ≥ 5` **and** `decay_score ≥ 0.7` (both tunable). Unused entries decay and migrate to Cold.\n- **Hot** (up to 50 entries, 4000-token budget, 1200 chars/entry) — auto-injected into every prompt, no query needed. Populated by earned promotion from warm (and by explicit `tier: \"hot\"` writes, which are capped at 1200 characters — store a concise summary, not an essay). Sticky tokens come off the top of this budget.\n- **Sticky (pinned)** — a flag on a hot entry, set via `memory_pin` (or store-and-pin with `memory_store { pinned: true }`). Sticky entries are **unbounded**, injected verbatim and first at session start under a `## Pinned directives (always follow)` header, and are **never** truncated, decayed, demoted, evicted, or compacted. `memory_unpin` clears the flag, leaving the entry in hot as a normal earned resident. **Project-scoped injection** (default on): untagged pins are global and inject everywhere; a pin tagged with a `project` value (lowercase `owner/repo` slug or folder name) injects only when the detected cwd matches that repo. When no git repo is detected, only global pins inject (fail-closed).\n- **Cold** (unlimited, hierarchical) — your knowledge base. Ingest entire directories — source trees, documentation, design specs — and they're retrieved when relevant.\n\n\u003e **Upgrading from 3.x?** The old Pinned tier is merged into Hot as the sticky flag, and a one-time migration runs automatically on first `session_start`: existing pins become sticky-hot, previously auto-hot entries move to warm, and the legacy `pinned_*` tables are dropped. The migration is irreversible — back up `~/.total-recall/total-recall.db` first if you want a rollback path.\n\n### Hybrid Search\n\nRetrieval combines **BM25 full-text search** and **cosine vector similarity**, merged by a pure F# ranking function. You get keyword precision when you search by exact terms and semantic recall when you describe what you need in natural language. The BM25/vector weight is tunable via `[search] fts_weight`.\n\n### Embeddings\n\nAll memories are embedded with [bge-small-en-v1.5](https://huggingface.co/BAAI/bge-small-en-v1.5) (384 dimensions, CLS pooling, with an asymmetric query prefix for searches), running locally via ONNX — no API calls, no network dependency. The model (~133 MB) is fetched and sha256-verified at release build time and ships bundled inside the npm/release artifact; there is no runtime HuggingFace download. If the bundled model is absent, the binary fails fast with a clear error rather than fetching anything.\n\nIf you swap the local embedder, existing vectors are in the old model's space. By default (`embedding.on_model_change = \"auto\"`) the **sqlite** and **cortex** backends re-embed their local index automatically — a one-time re-embed that runs **in the background** after launch, not on the startup path. The server stays fully usable while it runs; local semantic retrieval is degraded until it finishes, and progress is reported through `session_start`/`status` (you'll see a \"re-index in progress (N/M)\" notice). It's batched and resumable, so restarting mid-re-index picks up where it left off rather than starting over. This also covers a pre-existing index that was never fingerprint-stamped (e.g. an older cortex database): if it holds vectors but carries no fingerprint, it is re-embedded too rather than silently left in a stale model space. Set `on_model_change = \"warn\"` to run with the stale vectors (degraded retrieval, recurring warning) or `\"block\"` to refuse to start. **Postgres** can't auto-migrate: under `auto` it stops with an actionable error — re-ingest into a fresh database or use `\"warn\"`. For **cortex**, only the local vector index is re-embedded (the remote re-embeds independently); `total-recall reindex-embeddings` runs the same re-embed offline for `warn`/`block` deferrals and manual re-embeds.\n\nFor enterprise deployments, swap in a remote embedder (OpenAI, Amazon Bedrock) for higher-dimensional vectors and finer-grained retrieval across shared team knowledge.\n\n### Session Start\n\nEvery `session_start` call runs the same sequence:\n\n1. **Import sync** — scans all installed host tools (Claude Code, Copilot CLI, Cursor, Cline, OpenCode, Hermes), deduplicates via content hash, and imports new entries.\n2. **Sticky + hot tier assembly** — sticky (pinned) entries are injected first, verbatim and untruncated, then current hot entries fill the remaining token budget. When `tiers.pinned.project_scoping` is on (default), only global pins and pins tagged to the detected repo are included; if no repo is detected, only global pins inject (fail-closed).\n3. **Hint generation** — surfaces up to 5 high-value warm memories as actionable one-liners: `Correction` and `Preference` entries first, frequently accessed entries (3+ accesses) second, warm→hot promotion candidates third. No LLM calls — pure DB queries.\n4. **Tier summary** — counts entries across hot, warm, cold, and all KB collections, plus a sticky count (`tierSummary.pinned` is retained for wire compatibility and now reports sticky-hot entries). A `pinned_budget_pressure` hint fires when sticky pins consume over half the token budget (suggested action: `memory_unpin`).\n5. **Session continuity** — reports human-readable time since the last compaction event (proxy for last active session).\n\nEvery `session_start` also runs a skill scan: it reads `~/.claude/skills/` plus any directories listed in `[skills] extra_dirs`, persists the content + a locally-computed embedding to a SQLite skill cache, and advertises discovered skills as an `## Available Skills` block in the session context. Scanned skills are invokable on demand via the `skill_get` MCP tool and discoverable via `skill_search` (hybrid semantic + keyword ranking with a usage-decay tie-breaker) — both work entirely offline with no Cortex required. In Cortex mode the scanned skills are also pushed to Cortex, usage events sync back as a multi-machine rollup, and pulled skills from other machines merge into the same local cache.\n\n### Pinned-Directive Floor\n\nPinned directives are injected once at `session_start`, but in a long session they drift far enough up the transcript that the model stops honoring them. The **pinned floor** re-asserts the pinned block near the live edge on an adaptive throttle, so your pins keep being followed all session long.\n\nA per-turn `UserPromptSubmit` hook runs before each prompt and re-injects the pinned block when **either** trigger trips since the last injection:\n\n- `floor_every_n_turns` user turns have elapsed (default 6), **or**\n- ~`floor_growth_tokens` of transcript growth has accumulated (default 6000).\n\nThe first turn of a session seeds the throttle and skips (the block was just injected at session start). The re-injected block is rendered verbatim — identical to the session-start block — and prefixed with a short reminder line. Project scoping applies here too: the hook reads the cwd from the hook payload and filters pins by the detected repo (same fail-closed semantics as session start). The hook is **fail-safe: it never blocks or rejects a prompt**. Disable it entirely with `floor_enabled = false`.\n\nPer-host support:\n\n| Host | Per-turn floor | Mechanism |\n|---|---|---|\n| Claude Code | Active | `UserPromptSubmit` hook → `additionalContext` |\n| Copilot CLI | Pending upstream fix | Wired the same way, but Copilot CLI currently ignores the returned `additionalContext` |\n| Cursor | Layered fallback | session-start injection + skill-guided `session_refresh` (Cursor's `beforeSubmitPrompt` is block-only and cannot inject context) |\n\n---\n\n## Supported Platforms\n\n| Platform | Support | Notes |\n|---|---|---|\n| Claude Code | Full | Native plugin, session hooks, auto-import |\n| Copilot CLI | Full | Plugin wrapper, session hooks, auto-import from Copilot memory files |\n| Cursor | Full | Plugin wrapper, SessionStart hook; run `/total-recall:commands compact` manually — no SessionEnd hook |\n| OpenCode | Full | Plugin wrapper, auto-import from OpenCode project and agent files |\n| Cline | Full | Auto-import from task history; MCP server config required |\n| Hermes | Importer | Auto-import from SOUL.md and skills on first run; no session hooks |\n\n---\n\n## Web UI\n\ntotal-recall ships a built-in local web UI — a third surface alongside the MCP server (AI assistant integration) and the CLI (`total-recall status`, `total-recall eval`, etc.). It is a React SPA served directly from the single NativeAOT binary, no separate install or Node required.\n\n**Design.** The UI has a developer-native *Terminal / Archive* identity: a monospace-forward type system (self-hosted **JetBrains Mono** + **IBM Plex Sans** — bundled into the binary, no CDN, fully offline), a fixed **left navigation rail**, a faint ruled-grid backdrop, and an amber phosphor accent. It ships **dark and light themes** with a toggle — your choice persists, and on first visit it follows your OS preference. A **⌘K / Ctrl-K command palette** jumps to any page and runs live search across memories and the knowledge base, so the whole UI is reachable from the keyboard.\n\n![total-recall web UI — Dashboard, dark theme](docs/images/web-ui-dashboard.png)\n\n```bash\ntotal-recall ui                  # serve on http://localhost:5577 and open the browser\ntotal-recall ui --port 5600      # custom port\ntotal-recall ui --no-open        # suppress auto-open (e.g. remote / headless)\ntotal-recall ui --host 0.0.0.0   # bind all interfaces (warns about exposure)\ntotal-recall ui --token \u003ctok\u003e    # supply a fixed token instead of a per-launch random one\ntotal-recall ui --smoke          # CI mode: start, GET /api/health, exit 0/1\n```\n\nThe server binds **loopback only** (`localhost`) by default. Every launch generates a fresh ephemeral bearer token that is injected directly into the served HTML, so opening the URL in a browser is sufficient — no copy-paste of credentials. A Host-header allowlist mitigates DNS-rebinding.\n\n**Seven sections** are available in the left navigation rail:\n\n| Section | What it shows |\n|---|---|\n| Dashboard | Tier composition, retrieval quality, token usage, recent activity, trend sparklines |\n| Memory | Browse, search, filter, promote/demote/pin/delete individual entries |\n| Knowledge Base | List collections, search, ingest files/directories, refresh or remove collections |\n| Usage | Token expenditure by host, project, model, and time window; per-session breakdown |\n| ✨ Insights | Memory-health score with an expandable breakdown, plus actionable cards computed server-side from your local store (no LLM): merge near-duplicate memories, promote high-use entries to pinned, surface retrieval gaps, and tune the similarity threshold from a recall curve |\n| Eval | Run the retrieval benchmark, review hit/miss/MRR with per-tier \u0026 per-content-type breakdowns and top misses, grow the benchmark from real retrieval misses, and compare config snapshots |\n| Config | Edit a safe subset of tuning knobs (validated, persisted via `config_set`); storage \u0026 embedding shown read-only |\n\n**Cost figures** in the Usage section are **client-side estimates** derived from a bundled model pricing table. They are not billed amounts.\n\nThe SPA build is **opt-in** (`-p:BuildSpa=true` triggers `npm ci \u0026\u0026 npm run build` in `ClientApp/` and embeds the Vite output in the assembly). Default `dotnet build` and all tests are Node-free — the binary falls back to a placeholder page when built without the SPA. Release builds always include the SPA.\n\n---\n\n## Commands\n\nAll commands are routed through the `/total-recall:commands` skill:\n\n| Command | Description |\n|---|---|\n| `/total-recall:commands help` | Show command reference table |\n| `/total-recall:commands status` | Dashboard overview |\n| `/total-recall:commands search \u003cquery\u003e` | Semantic search across all tiers |\n| `/total-recall:commands store \u003ccontent\u003e` | Manually store a memory |\n| `/total-recall:commands forget \u003cquery\u003e` | Find and delete entries |\n| `/total-recall:commands inspect \u003cid\u003e` | Deep dive on single entry with compaction history |\n| `/total-recall:commands promote \u003cid\u003e` | Move entry to higher tier |\n| `/total-recall:commands demote \u003cid\u003e` | Move entry to lower tier |\n| `/total-recall:commands pin \u003cid\u003e` | Pin entry — always injected at session start, never decays |\n| `/total-recall:commands unpin \u003cid\u003e` | Clear an entry's sticky flag (it stays in hot as an earned resident) |\n| `/total-recall:commands history` | Show recent tier movements |\n| `/total-recall:commands lineage \u003cid\u003e` | Show compaction ancestry |\n| `/total-recall:commands export` | Export to portable JSON format |\n| `/total-recall:commands import \u003cfile\u003e` | Import from export file |\n| `/total-recall:commands ingest \u003cpath\u003e` | Add files or directories to knowledge base |\n| `/total-recall:commands kb search \u003cquery\u003e` | Search knowledge base |\n| `/total-recall:commands kb list` | List KB collections |\n| `/total-recall:commands kb refresh \u003cid\u003e` | Re-ingest a collection |\n| `/total-recall:commands kb remove \u003cid\u003e` | Remove KB entry |\n| `/total-recall:commands compact` | Force compaction |\n| `/total-recall:commands eval` | Retrieval quality metrics |\n| `/total-recall:commands eval --benchmark` | Run synthetic benchmark |\n| `/total-recall:commands eval --compare \u003cname\u003e` | Compare metrics between two config snapshots |\n| `/total-recall:commands eval --snapshot \u003cname\u003e` | Manually create a named config snapshot |\n| `/total-recall:commands eval --grow` | Review and accept/reject benchmark candidates from retrieval misses |\n| `/total-recall:commands config get \u003ckey\u003e` | Read config value |\n| `/total-recall:commands config set \u003ckey\u003e \u003cval\u003e` | Update config |\n| `/total-recall:commands import-host` | Re-run import sync from all host tools |\n\nMemory capture, retrieval, and compaction run automatically in the background — see the \"Automatic Behavior\" section of the `/total-recall:commands` skill.\n\n\u003e **Note:** `/total-recall:commands` is implemented as a Claude Code skill (at `skills/commands/SKILL.md`), not as a slash-command file under `commands/`. The skill handles all `\u003csubcommand\u003e` arguments internally.\n\n---\n\n## Configuration\n\nThe config file lives at `~/.total-recall/config.toml`. All fields have defaults — you only need to override what you want to change.\n\n```toml\n# total-recall configuration\n\n[tiers.pinned]\n# The Pinned tier was merged into Hot as a \"sticky\" flag in 4.0. This section\n# is kept as a deprecated alias — its floor_* / project_scoping fields still\n# drive the per-turn re-injection of sticky pins. max_content_chars no longer\n# applies (sticky entries are unbounded).\nfloor_enabled = true              # Per-turn pinned-directive floor (UserPromptSubmit re-injection)\nfloor_every_n_turns = 6           # Re-inject the sticky block at least every N user turns\nfloor_growth_tokens = 6000        # ...or after ~this many tokens of transcript growth (whichever trips first)\nproject_scoping = true            # Scope sticky injection by git repo: repo-tagged pins inject only in their repo; untagged pins are global; fail-closed when no repo detected\n\n[tiers.hot]\nmax_entries = 50                  # Max entries auto-injected per prompt\ntoken_budget = 4000               # Max tokens for hot tier injection (sticky pins come off the top)\ncarry_forward_threshold = 0.7     # Score threshold to stay in hot\nmax_content_chars = 1200          # Max characters per hot entry (oversize rejected — store a summary or keep it in warm); sticky pins are exempt\n\n[tiers.warm]\nmax_entries = 10000               # Max entries in warm tier\nretrieval_top_k = 5               # Results returned per search\nsimilarity_threshold = 0.65       # Min cosine similarity for retrieval\ncold_decay_days = 30              # Days before unused warm entries decay to cold\n\n[tiers.cold]\nchunk_max_tokens = 512            # Max tokens per knowledge base chunk\nchunk_overlap_tokens = 50         # Overlap between adjacent chunks\nlazy_summary_threshold = 5        # Accesses before generating summary\n\n[compaction]\ndecay_half_life_hours = 168       # Score half-life (168h = 1 week)\nwarm_threshold = 0.3              # Score below which warm→cold\npromote_threshold = 0.7           # Min decay_score to promote (cold→warm, and warm→hot)\npromote_min_access = 5            # Min access_count for warm→hot promotion (paired with promote_threshold on decay_score)\nwarm_sweep_interval_days = 7      # How often to run warm sweep\n\n[search]\nfts_weight = 0.3                  # BM25 weight in hybrid ranking (0.0 = vector only, 1.0 = FTS only)\n\n[scope]\ndefault = \"user\"                  # Default scope for new entries (e.g., \"user\", \"team\")\n\n[usage]\ninitial_backfill_days = 30        # Days of usage history to backfill on first sync\n\n[regression]\nmiss_rate_delta = 0.1             # Alert if miss rate increased by this much vs. previous snapshot\nlatency_ratio = 2.0               # Alert if latency increased by this factor vs. previous snapshot\nmin_events = 20                   # Minimum retrieval events required before regression check runs\n\n[embedding]\nmodel = \"bge-small-en-v1.5\"      # Embedding model name\ndimensions = 384                  # Embedding dimensions\n# provider = \"local\"              # \"local\" (default) | \"openai\" | \"bedrock\"\n# endpoint = \"https://api.openai.com/v1\"   # OpenAI-compatible base URL\n# bedrock_region = \"us-east-1\"             # Bedrock only\n# bedrock_model = \"cohere.embed-v4:0\"      # Bedrock model ID\n# api_key = \"\"                             # or set TOTAL_RECALL_EMBEDDING_API_KEY env var\n\n# --- Skills (optional) ---\n# [skills]\n# extra_dirs = [\n#   \"~/my-skills\",\n#   \"/path/to/team-skills\"\n# ]\n\n# --- Remote storage (optional) ---\n# [storage]\n# connection_string = \"Host=localhost;Database=total_recall;Username=tr;Password=changeme\"\n\n# --- User identity (optional, Postgres only) ---\n# [user]\n# user_id = \"alice\"               # or set TOTAL_RECALL_USER_ID env var\n```\n\n**Relocating the database:** set `TOTAL_RECALL_DB_PATH` to an absolute path or `~/`-prefixed path. See [INSTALL.md](INSTALL.md#relocating-the-database) for cloud-sync and shared-workspace guidance.\n\n**Switching to Postgres:** uncomment the `[storage]` section with your connection string. The binary auto-detects the backend — no code changes, no flag. Pair with `[embedding] provider = \"bedrock\"` or `\"openai\"` for remote embeddings. Run `migrate_to_remote` to copy local memories to the shared database with re-embedding.\n\n### Connecting to Cortex\n\nTotal Recall Cortex is the shared backend platform that adds team knowledge bases, connectors (Jira, Confluence, GitHub), chat/RAG, and a React UI on top of the plugin's memory layer.\n\nIn Cortex mode, the plugin operates as a hybrid:\n- **User memories** are stored locally (fast reads/writes), synced bidirectionally to Cortex every 300 seconds and at session boundaries\n- **Sticky (pinned) entries are local-only** — Cortex has no sticky-pin support yet, so pins are never pushed, pulled, reconciled, or migrated (`migrate_to_remote` skips them)\n- **Global knowledge** (team KB, connector-ingested data) is queried remotely from Cortex\n- **Telemetry** (usage, retrieval events, compaction log) is pushed to Cortex for unified dashboards\n- **Skills** are synced to Cortex so team members share the same skill library\n\nConfigure in your `config.toml`:\n\n```toml\n[storage]\nmode = \"cortex\"\n\n[cortex]\nurl = \"https://your-cortex-instance.example.com\"\npat = \"tr_your_personal_access_token\"\nsync_interval_seconds = 300       # Background sync interval (default: 300)\n```\n\nOr via environment variables:\n\n```bash\nexport TOTAL_RECALL_CORTEX_URL=\"https://your-cortex-instance.example.com\"\nexport TOTAL_RECALL_CORTEX_PAT=\"tr_your_personal_access_token\"\n```\n\nGenerate a PAT from the Cortex web UI under Settings → Personal Access Tokens.\n\n**Offline resilience:** If Cortex is unreachable, the plugin continues working locally. A persistent sync queue buffers outbound changes and flushes automatically when connectivity is restored.\n\n### Skills\n\ntotal-recall can advertise custom skills at every `session_start` so your AI assistant knows which workflows are available. Skills are discovered from two places:\n\n- **`~/.claude/skills/`** — the standard Claude Code user skills directory (always scanned)\n- **`extra_dirs`** — additional directories you configure, scanned on every session start regardless of whether Cortex is available\n\nConfigure extra skill directories in `~/.total-recall/config.toml`:\n\n```toml\n[skills]\nextra_dirs = [\n  \"~/my-custom-skills\",\n  \"/path/to/shared/team-skills\"\n]\n```\n\nPaths can be absolute or `~/`-prefixed. Skills in `extra_dirs` are always advertised from disk — Cortex is not required.\n\n**Skill format:** Each skill is either a single `.md` file or a directory containing a `SKILL.md` entry point. A minimal single-file skill:\n\n```markdown\n---\nname: my-skill\ndescription: Does something useful\n---\n\nFull skill content here...\n```\n\nA bundle (directory with supporting files) uses the same frontmatter in its `SKILL.md`, and can include scripts, templates, or reference files alongside it.\n\n**Merge behavior:** When Cortex is configured and reachable, the session context block merges cortex-stored skills with locally-scanned `extra_dirs` skills, deduplicating by name (Cortex entries take precedence). When Cortex is unavailable or not configured, only local skills appear.\n\n---\n\n## Developer Reference\n\nThe MCP server exposes 41 core tools in every backend mode; local SQLite and Cortex modes add usage, cache, skill, and feedback tools (49 and 50 total, respectively). All tool names follow the pattern `\u003cdomain\u003e_\u003caction\u003e`.\n\n| Category | Tools |\n|---|---|\n| Session | `session_start`, `session_end`, `session_context`, `session_refresh` |\n| Memory | `memory_store`, `memory_get`, `memory_get_all`, `memory_update`, `memory_delete`, `memory_inspect`, `memory_search`, `memory_list`, `memory_recent`, `memory_extract`, `memory_feedback`† |\n| Tier management | `memory_promote`, `memory_demote`, `memory_pin`, `memory_unpin`, `memory_history`, `memory_lineage` |\n| Import / Export | `memory_export`, `memory_import`, `import_host` |\n| Knowledge base | `kb_ingest_file`, `kb_ingest_dir`, `kb_search`, `kb_list_collections`, `kb_refresh`, `kb_remove`, `kb_summarize`, `kb_resolve` |\n| Compaction | `compact_now` |\n| Eval | `eval_report`, `eval_benchmark`, `eval_compare`, `eval_snapshot`, `eval_grow` |\n| Config | `config_get`, `config_set` |\n| Status \u0026 Usage | `status`, `usage_status`† |\n| Cache | `cache_check`†, `cache_store`† |\n| Migration | `migrate_to_remote` |\n| Skills† | `skill_search`, `skill_get`, `skill_list`, `skill_import_host`, `skill_delete` *(skill_delete: Cortex mode only)* |\n\n†Unavailable in Postgres mode (local SQLite + Cortex modes only).\n\nSticky (pinned) surface: `memory_pin` sets the sticky flag on an entry, moving it into the hot tier (with optional `scope: \"project\" | \"global\"`); `memory_unpin` clears the flag, leaving the entry in hot as an earned resident; `memory_store` accepts `pinned: true` to store-and-pin new content directly as sticky-hot; `memory_promote` / `memory_demote` reject a sticky entry as source or target (unpin it first). `memory_list` accepts a `sticky: true` filter, and `status` reports a sticky count (surfaced as `tierSummary.pinned` for wire compatibility). **Project-scoped injection** (enabled by `tiers.pinned.project_scoping`, default on): a pin is tagged to a repo by setting its `project` field to the lowercase `owner/repo` slug (e.g. `radancy-pe/rai-ops-cortex`) or bare folder name when no remote is configured — at injection time `ProjectResolver` detects the current repo from cwd (pure filesystem walk) and `PinnedScope.OptsFor` filters accordingly. Untagged (null-project) pins are global and always inject. When no repo is detected the injection is fail-closed to globals only.\n\nRetrieval-quality feedback: `memory_search` returns `{ retrievalId, results }` and `kb_search` returns a top-level `retrievalId`. The assistant can call `memory_feedback` with that `retrievalId` to confirm whether the retrieval was actually used; un-acted retrievals are inferred as misses after a grace window. This drives the `eval_report` metrics and the web UI's \"Retrieval quality\" card. `memory_feedback` is intentionally assistant-only — it is not exposed to the web UI.\n\nHandler implementations live in `src/TotalRecall.Server/Handlers/\u003cToolName\u003eHandler.cs`. Tool wiring: `src/TotalRecall.Server/ServerComposition.cs → BuildRegistry()`.\n\n---\n\n## Architecture\n\n```\nnpm wrapper layer (Node, zero runtime dependencies):\n  bin/start.js (MCP bootstrap shim) — comes up instantly; answers initialize/ping/tools/list\n    from catalog.json before the engine is ready; provisions (sha256-verified download via\n    release provisioning.manifest.json) + spawns + proxies the engine; supervises and\n    restarts on crash; the MCP connection never drops (no more MCP error -32000 on first\n    launch after an update); emits notifications/tools/list_changed once proxying begins.\n\nMCP Server (.NET 8 NativeAOT — C# imperative shell + F# functional core)\n├── TotalRecall.Core (F#)        — pure functions: tokenizer, decay, hybrid ranking, parsers, chunker\n├── TotalRecall.Infrastructure   — SQLite/Postgres storage, ONNX/remote embedder, importers, migrations\n├── TotalRecall.Server           — MCP JSON-RPC server, 41 core tool handlers (48–49 with mode-dependent tools), lifecycle\n├── TotalRecall.Web              — embedded ASP.NET Core minimal API + React SPA (the web UI)\n├── TotalRecall.Cli              — CLI commands (status, eval, kb, memory, config, migrate, ui)\n└── TotalRecall.Host             — composition root, AOT entry point, migration guard\n\nTiers:\n  Hot (50 entries, 1200 chars/entry) → auto-injected every prompt; earned from warm by access\n    └─ sticky flag → user-pinned; injected first, unbounded, never decays/compacts/evicts\n  Warm (10K entries, default ingress) → BM25 + cosine hybrid search per query; promotes to hot on merit\n  Cold (unlimited)   → hierarchical KB retrieval\n\nBackends (selected by config):\n  Local:    SQLite + sqlite-vec + bundled ONNX embedder (default, zero config)\n  Postgres: Postgres/pgvector + HNSW indexes + tsvector FTS + per-user visibility\n  Cortex:   Local SQLite + write-local-then-enqueue sync to Cortex; remote queries for global KB\n```\n\n**Data flow:**\n\n1. `store` — write a memory, assign tier (warm by default), embed, persist\n2. `search` — embed query, BM25 + cosine vector search across all tiers, merge with F# ranking, return results\n3. `compact` — decay scores, compact hot→warm (summarize), demote warm→cold; earned warm→hot promotion runs in the warm sweep\n4. `ingest` — chunk files with heading-aware Markdown and regex-based code parsing, embed chunks, store in cold tier\n\n**Local mode:** all state lives in `~/.total-recall/total-recall.db`. The embedding model and the sqlite-vec native extension are bundled with the binary. No network calls required at runtime.\n\n**Cortex mode:** user memories write locally first for low latency. A `RoutingStore` wraps every write: persist locally, enqueue to `sync_queue`. A background sync loop flushes the queue to Cortex every `sync_interval_seconds` (default: 300) and at session boundaries. Global knowledge (team KB, connectors) is read directly from Cortex.\n\n---\n\n## Prerequisites\n\nThese apply only if you're building from source. The prebuilt binary is self-contained — no .NET runtime, no system SQLite, no Bun required.\n\n- **.NET 10 SDK** — pinned by `global.json` at the repo root; builds the `net8.0` NativeAOT target\n- **npm** — for `npm ci`, which pulls `sqlite-vec` native libs needed by the csproj copy targets\n- **Embedding model** — run `sh scripts/fetch-bge-small.sh` once to fetch + sha256-verify the `bge-small-en-v1.5` ONNX model (~133 MB) into `models/bge-small-en-v1.5/`. The model is no longer committed to the repo (not in Git LFS); release builds fetch and bundle it into the per-RID artifact.\n\n---\n\n## Installation from Source\n\n```bash\ngit clone https://github.com/strvmarv/total-recall.git\ncd total-recall\nsh scripts/fetch-bge-small.sh              # fetch + sha256-verify the ONNX model (~133 MB)\nnpm ci                                     # pulls sqlite-vec native libs into node_modules/\ndotnet build src/TotalRecall.sln\ndotnet test src/TotalRecall.sln --filter \"Category!=Integration\"   # ~1000 tests\ndotnet publish src/TotalRecall.Host/TotalRecall.Host.csproj -c Release -r win-x64 -p:PublishAot=true\n# (swap win-x64 for your RID: linux-x64, linux-arm64, osx-arm64)\n```\n\nThe publish output lands in `src/TotalRecall.Host/bin/Release/net8.0/\u003crid\u003e/publish/` with the binary plus all sibling native libs (`libonnxruntime.*`, `libe_sqlite3.*`, `runtimes/vec0.*`) ready to run.\n\nSupported RIDs: `linux-x64`, `linux-arm64`, `osx-arm64`, `win-x64`. Intel Mac (`osx-x64`) is not shipped.\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full contributor guide, including how to add a new host importer, extend the chunking pipeline, or add a new MCP tool handler.\n\n---\n\n## Built With \u0026 Inspired By\n\n### [superpowers](https://github.com/obra/superpowers) by [obra](https://github.com/obra)\n\ntotal-recall's plugin architecture, skill format, hook system, multi-platform wrapper pattern, and development philosophy are directly inspired by and modeled after the **superpowers** plugin. superpowers demonstrated that a zero-dependency, markdown-driven skill system could fundamentally improve how AI coding assistants behave — total-recall extends that same philosophy to memory and knowledge management.\n\nIf you're building plugins for TUI coding assistants, start with [superpowers](https://github.com/obra/superpowers). It's the foundation this ecosystem needs.\n\n### Core Technologies\n\n- [.NET 8 / NativeAOT](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/) — single-binary deployment, no runtime dependency\n- [F# Core](https://learn.microsoft.com/en-us/dotnet/fsharp/) — pure functional core: tokenizer, parsers, decay, hybrid ranking\n- [Microsoft.Data.Sqlite](https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/) — embedded SQLite with extension loading\n- [sqlite-vec](https://github.com/asg017/sqlite-vec) — vector similarity search in SQLite (loaded as a native extension via `LoadExtension`)\n- [Microsoft.ML.OnnxRuntime](https://onnxruntime.ai/docs/get-started/with-csharp.html) — local ML inference, AOT-compatible\n- [Microsoft.ML.Tokenizers](https://learn.microsoft.com/en-us/dotnet/api/microsoft.ml.tokenizers) — canonical BERT BasicTokenization + WordPiece\n- [bge-small-en-v1.5](https://huggingface.co/BAAI/bge-small-en-v1.5) — sentence embeddings (384d, CLS pooling)\n- Hand-rolled JSON-RPC stdio MCP server in `TotalRecall.Server` (no SDK dependency)\n- [Spectre.Console](https://spectreconsole.net/) — CLI rendering for `total-recall status` / `eval` / `kb list`\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrvmarv%2Ftotal-recall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrvmarv%2Ftotal-recall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrvmarv%2Ftotal-recall/lists"}