{
  "markdown": "# Prism Coder\n\n**Give your AI agent memory that lasts — and see the cloud tokens it never had to spend.** Persistent sessions, knowledge graphs, offline tool-routing, and an auditable savings meter. Fully local and free.\n\n[![npm](https://img.shields.io/npm/v/prism-mcp-server?color=cb0000&label=npm)](https://www.npmjs.com/package/prism-mcp-server)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-00ADD8)](https://github.com/modelcontextprotocol/servers)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)\n[![Models on HuggingFace](https://img.shields.io/badge/🤗-prism--coder-yellow)](https://huggingface.co/dcostenco)\n\n<p align=\"center\">\n  <img src=\"docs/mind-palace-dashboard-v20.8.png\" alt=\"Prism Mind Palace dashboard v20.8.0 — project state with handoff summary, pending TODOs, intent health, neural graph, and time-travel history\" width=\"700\" />\n</p>\n\nPrism Coder is an [MCP server](https://modelcontextprotocol.io) that gives Claude, Cursor, and other AI tools long-term memory that survives across sessions. It ships with the open-weight `prism-coder` model fleet (2B–27B) for fast, offline tool-routing — no cloud required. And it keeps score: every call served locally is metered, so `prism savings` shows the token volume that never reached your cloud model — [measured honestly, in tokens](#local_savings--what-local-serving-actually-displaced).\n\n**No account needed. No API keys. Runs on your machine.**  \nA paid subscription adds cloud sync, higher model tiers, and team features through the [Synalux portal](https://synalux.ai).\n\n---\n\n## What Prism gives you\n\n- **Session memory that survives restarts** — resume projects with handoff notes,\n  recent work, open TODOs, and configurable quick, standard, or deep context.\n- **Local-first inference** — bounded work is routed through local Ollama models\n  first, with automatic 2B/4B/9B/27B selection based on installed models,\n  available RAM, context fit, and subscription entitlements.\n- **A savings meter you can audit** — `prism savings` (or the `local_savings`\n  tool from any host) reports the token volume local serving kept off your\n  cloud model: headline, local share, per-model breakdown. It reports tokens,\n  never an invented dollar figure, and prints its assumptions and known\n  undercounts inline — a number you can check, not marketing.\n- **Route-output enforcement** — route mode returns only well-formed calls to\n  tools the host actually advertised. Standard and higher plans can add\n  authenticated deterministic correction; `route_guard: \"local\"` keeps the\n  prompt and draft entirely on-device.\n- **One setup for every agent** — `prism connect` configures Claude Code,\n  Claude Desktop, Cursor, Gemini CLI, and Codex while preserving unrelated\n  settings.\n- **Subscription-aware skills** — entitled skills are synchronized before the\n  host launches, with safe upgrades, downgrades, conflict preservation, and\n  offline last-good recovery.\n- **Hook-free startup** — MCP metadata and native instructions request Prism's\n  startup context without requiring lifecycle hooks or a Prism-owned launcher.\n  Where a host offers hooks (Claude Code, Codex), `prism connect` adds two\n  small ones on top: mid-session prompt routing, and a post-compaction\n  re-injection of the protected-floor digest.\n- **Safe escalation and observability** — inference outcomes are explicit,\n  reserved content remains fail-closed, and local/cloud usage is recorded for\n  review.\n\n## Get started\n\n```bash\nnpm install -g prism-mcp-server\nprism connect\n```\n\nUse `prism connect --dry-run` to preview changes, `prism connect --all` to\nconfigure every detected host, or `prism connect --refresh` to reconcile\nPrism-managed entries after an upgrade. Restart the host after connecting.\n\nPrism works locally without an account, API key, or cloud subscription. Add a\nSynalux subscription when you want cloud memory, paid-tier skills, or team\nfeatures.\n\nAfter a few sessions, ask what it's been worth:\n\n```bash\nprism savings --period month\n```\n\n```\n💾 Local serving — LAST 30 DAYS\n  ~510K tokens kept off your cloud model\n  53 call(s) served locally of 58 routed (91%)\n```\n\nYour numbers will differ — that's the point: it reports what *your* machine\nactually served, not a projection. Full report anatomy and the honesty rules\nbehind it are in the\n[`local_savings` section](#local_savings--what-local-serving-actually-displaced).\n\n### Install as a plugin\n\nPrism also ships as a plugin, which registers the MCP server and the startup\nskill for you.\n\n**Claude Code** — from the community marketplace:\n\n```bash\n/plugin marketplace add anthropics/claude-plugins-community\n/plugin install prism-coder@claude-community\n```\n\n**Codex** — this repository is itself a plugin marketplace:\n\n```bash\ncodex plugin marketplace add dcostenco/prism-coder\ncodex plugin add prism-coder@prism\n```\n\nThe plugin registers `prism-mcp` via `npx -y prism-mcp-server`. If you already\nconfigured Prism by hand — `prism connect` writes an `mcp_servers.prism-mcp`\nentry — you have that server twice under one key. Install the plugin **or**\nrun `prism connect`, not both.\n\n### What `prism connect` changes about host subagents\n\n`connect` steers bounded work to `prism_infer` on your machine rather than to\nhost-spawned agents. What it writes differs per host, and **it does not disable\nsubagents everywhere** — Claude Code keeps them and is pointed at an economy\nmodel instead. Prism's local workers stay available over MCP in every case.\n\n| Host | Setting written | Effect |\n|---|---|---|\n| Claude Code | `env.CLAUDE_CODE_SUBAGENT_MODEL = \"sonnet\"` in `~/.claude/settings.json` | Subagents stay **enabled**, pinned to an economy model. Fan-out is discouraged by policy text, not by config |\n| Gemini CLI | `experimental.enableAgents = false` in `~/.gemini/settings.json` | Subagents **off**. Gemini exposes one boolean, so that is all there is to set |\n| Codex | `features.multi_agent = false` in `$CODEX_HOME/config.toml` (default `~/.codex`), plus a bounded fallback: 2 threads, depth 1, cheap subagent model, 900s cap | Subagents **off**, with a bounded profile underneath so a deliberate re-enable lands somewhere sane |\n\nTwo things worth knowing:\n\n- **`experimental` is Gemini's namespace, not ours.** Prism is not enabling\n  anything experimental — it writes `false` to a flag Gemini already defines at\n  that path. Writing anywhere else would have no effect.\n- **That namespace is by definition temporary.** If Gemini promotes\n  `enableAgents` out of `experimental`, Prism keeps writing the old path, Gemini\n  reads the new one, and host subagents quietly turn back on. Nothing errors and\n  the settings file still looks correct. If you see host subagents running while\n  `enableAgents` reads `false`, check whether the key has moved before assuming\n  `connect` failed to write it.\n\nBoth writes are idempotent in the sense that a host already configured this way\nis left untouched — but they are **re-applied on every `prism connect` run**,\nnot only on `--refresh`. If you deliberately re-enable host subagents, the next\n`connect` will turn them off again. Keep them on by not re-running `connect`,\nor by re-enabling after each run.\n\n---\n\n<details>\n<summary>Release history (optional)</summary>\n\n## What's New in v20.18.0\n\n### The protected floor rides the bootstrap — and survives compaction\n\n- **`session_bootstrap` now inlines a digest of the protected floor** on\n  paid tiers at standard and deep depth: one inert line per rule, derived\n  from each skill's first paragraph (or its pinned `digest:`), plus its\n  section map, ~5.6K chars for the full floor. Small-context hosts such as\n  Codex were re-reading the sixteen SKILL.md files every session (median 8\n  re-reads / 36KB, worst 823 / 5.1MB in rollout logs) because the bootstrap\n  only *named* them. The digest is paid for on top of the context budget, so\n  the ledger/handoff share at every depth is byte-identical to before. Quick\n  depth stays names-only — the opt-out.\n- **A second hook re-injects the digest after compaction.** `prism connect`\n  registers the prism-route script on `SessionStart` matched to `compact`\n  (Claude Code and Codex); it runs `prism floor-digest`, which applies the\n  same tier and depth decisions as the bootstrap, and adds nothing on\n  startup/resume/clear. Hosts without hooks (Gemini, Cursor) still get the\n  digest on every bootstrap. **Codex: UNVERIFIED against a live compaction.**\n  The hook is registered and the script accepts the documented payload\n  spellings, but no Codex compaction has been observed end-to-end; on a\n  payload it does not recognise it re-injects nothing rather than something\n  wrong. If the digest comes from a generation whose skill files never\n  finished syncing, the re-injected block carries the same STALE warning the\n  bootstrap shows.\n- **Codex trust is reported honestly after a hook rewrite.** Approvals are\n  keyed by definition hash, so a rewritten `hooks.json` — this release adds\n  the SessionStart entry — voids prior trust: connect prints AWAITING TRUST\n  for both entries instead of a green ✓ for a hook Codex would silently skip,\n  and trust recorded for an older hook version is never mistaken for current.\n- **A host config that no longer parses is left alone.** If\n  `~/.claude/settings.json` or `~/.codex/hooks.json` exists but is not valid\n  JSON, connect keeps it byte-identical, registers no hook there, and says so\n  — it no longer replaces the file with a minimal hooks-only one. The npm\n  postinstall notice says the same, instead of asking you to trust a Codex\n  hook it never registered.\n- Fixed: a symptom-routed skill whose closing frontmatter fence is its last\n  line was inlined with its YAML (triggers included) as if it were the rule.\n- Fixed: a digest line that crosses into a new section keeps that section's\n  heading in front of it — whatever opened the section (an H2, a mid-document\n  H1, an empty heading, a setext underline) — so \"Delegate to\" / \"Do NOT\n  delegate\" rules cannot read with the wrong polarity once joined. A skill\n  file on disk is used only when it digests: empty, cut off inside its\n  frontmatter, or frontmatter-only files fall back to the stored copy instead\n  of rendering YAML as the rule.\n- Fixed: on Windows, a Codex hook approval is recognised even though Codex\n  stores the path with escaped backslashes.\n- The publish gate now refuses release notes that run *ahead* of the package\n  version (CHANGELOG, README, translated READMEs) — reading the newest\n  version on the heading line, so a `v20.17.3 – v20.18.0` range counts as\n  20.18.0, and surviving a typographic apostrophe or a BOM.\n\n## What's New in v20.17.3\n\n- **A plugin install can no longer enable the prompt-routing hook.** The\n  package's maintenance paths (npm postinstall, server startup) now only\n  refresh a hook that an explicit `prism connect` previously installed —\n  a prism MCP registration in host config no longer counts as consent.\n  First install of the hook happens through `prism connect` or not at all.\n- **The Claude Code plugin launcher is fully deterministic.** It runs the\n  exact pinned server version with npm lifecycle scripts disabled, and\n  the plugin now documents its security posture in `plugins/prism/README.md`.\n\n## What's New in v20.17.2\n\n- **Pasted logs can no longer falsely activate skills.** Symptom-triggered\n  routing now strips fenced blocks and routable skill-name mentions (including\n  inside compound identifiers like container/pod names) from the routing view\n  of a prompt, so quoting an agent log or a skill list doesn't load skills the\n  text merely mentions. Skills named by ordinary words keep routing normally.\n- **Symptom-routed skills now arrive whole.** Startup budgets deliver the full\n  rule text at every depth that fits; when a rule genuinely cannot fit, the\n  display says exactly how much is missing and how to load the rest, instead\n  of silently truncating.\n- **Routing can no longer be silently disabled by one bad skill.** Corrupt or\n  hostile trigger tables — wrong value shapes, patterns named after object\n  prototype properties — are skipped per entry instead of taking down all\n  prompt routing (or, in one case, the vault export) for the session.\n\n## What's New in v20.17.1\n\n- **Fixes a broken CLI in 20.17.0** — a command-name collision made every\n  `prism` CLI invocation exit with a commander error at startup (the MCP\n  server was unaffected). The handoff-sync command is `prism handoff …`;\n  `prism sync` remains cross-backend data synchronization. If you installed\n  20.17.0, update.\n\n## What's New in v20.17.0\n\n### Cross-Machine Session Handoff — End-to-End Encrypted\n\n- **Resume a session on any of your machines.** With `prism handoff enable` (paid,\n  off by default), each `session_save_handoff` seals the handoff to all your\n  account's device keys and relays the CIPHERTEXT; another machine pulls with\n  `sync_pull_handoff` (or `prism handoff pull <project>`) and opens it locally.\n- **The relay stores ciphertext only** — X25519 + AES-256-GCM sealed\n  envelopes. No key that opens a handoff ever exists server-side. The channel\n  is deliberately separate from savings sync, which carries counters only.\n- **TOFU device pinning** surfaces a compromised relay: sealing to a key this\n  machine has never seen warns loudly, keyed on the client-derived recipient\n  id so a swapped key can't hide behind a familiar device name.\n- `prism handoff status|devices` to inspect; revoke a lost machine from the portal.\n\n## What's New in v20.16.0\n\n### See What Local Serving Saves You — Meterable, Auditable, Team-Wide\n\n- **`local_savings` tool + `prism savings` CLI** — the token volume local\n  serving kept off your cloud model: all time, trailing 30/7 days, or any\n  `--days N` window. Tokens, never an invented dollar figure, with the\n  assumptions and known undercounts printed inline.\n- **Team roll-up (paid)** — `prism savings --sync-enable` uploads per-day\n  counters only (never content; the payload is a closed field set the server\n  also enforces); `prism savings --team` shows the workspace-wide total with\n  per-member share. Off by default.\n- **E2E sync foundation** — sealed multi-recipient envelopes (X25519 +\n  HKDF-SHA256 + AES-256-GCM on node:crypto, no new dependency) and per-device\n  identities, adversarially reviewed: cross-machine session sync will ship on\n  a relay that only ever stores ciphertext.\n- **Push-time public-leak guard** — outgoing diffs AND commit messages are\n  scanned before anything leaves the machine.\n\n## What's New in v20.12.1\n\n- **`prism connect --refresh` now converges every registration it owns**, not\n  just the top-level one — directory-scoped entries could otherwise keep\n  launching an old build indefinitely.\n- **`prism update` checks the installed package**, not the CLI that happens to\n  be running, so it can no longer report \"current\" while the install is stale.\n- **The opt-in scheduled updater can actually start** — the LaunchAgent now\n  carries a PATH that includes node and npm.\n\n## What's New in v20.12.0\n\n- **Prism now tells you when it's out of date.** Session startup shows a\n  one-line update notice when a newer release exists — cache-backed, at most\n  one registry check per day, silent offline. `PRISM_NO_UPDATE_CHECK=1`\n  opts out.\n- **Hands-free updates, if you want them.** `prism autoupdate enable` sets up\n  a daily `prism update --if-idle`: it updates only the global npm package,\n  defers while any Prism server is running, and never touches host\n  configuration — that stays behind a visible `prism connect`.\n\n## What's New in v20.11.1\n\n- **Saving memory never gets refused.** The save path used to reject\n  `session_save_ledger`/`save_handoff` calls when its path-to-project\n  heuristic disagreed with the project you declared — and the registry the\n  heuristic trusted could contain junk from earlier auto-registration, so\n  legitimate sessions ended unsaved. Your declaration now always wins; the\n  disagreement is returned as an advisory warning, and auto-registration\n  only accepts real repository roots.\n- **Screenshots are evidence again.** `prism browser` captures on macOS were\n  silently *upscaled* to the size cap, so a screenshot no longer showed what\n  actually rendered. Only genuinely oversized captures are resized now, and\n  the cap no longer clips a standard 1920-wide viewport.\n\n## What's New in v20.10.0 – v20.11.0\n\n- **Skill routing now works mid-session.** New prompts are matched on-device\n  as the conversation moves — not just on turn one — and injected within each\n  host's real context limits (Claude Code caps hook output at 10k chars;\n  Codex truncates by default), with pointer-first delivery when a payload\n  can't fit inline.\n- **`prism connect` is a converge command.** It self-updates first, re-execs,\n  then reconciles MCP registration, skills, and hooks — no more\n  \"fresh config, stale code\" machines.\n- **Scoped skills route on prompts too**, and startup output survives hosts\n  that discard structured tool content.\n\n## What's New in v20.9.0 – v20.9.3\n\n- **Your skills follow your account.** `skill_save` stores a skill at the\n  scope you choose: this machine only (`local`, works offline and signed out),\n  your account (`user` — every machine you sign into receives it), or a\n  workspace (`team` — shared with members, admin-managed, optionally targeted\n  to specific people).\n- **Trim the catalog you don't use.** `skill_manage` can release platform\n  skills you never touch — freeing host skill-catalog budget — and restore\n  them any time, losslessly. Deleting a scoped skill archives its final\n  content locally first, so nothing is ever silently unrecoverable.\n\n- **Delivery that queues instead of failing.** Concurrent sessions no longer\n  starve skill sync on the local config store (WAL + busy-timeout) — a failure\n  that previously reported only \"partial\" where nobody could see it.\n- **Withheld rules still bind.** When the context budget can't inline a\n  skill's text, the manifest of withheld names now states that those skills\n  still govern the work and names every way to load them before completion\n  claims.\n- **The budget the floor never spent.** A long-standing accounting bug meant\n  no unprotected skill ever inlined at any normal context level — the\n  always-inlined protected floor was debiting the budget meant for everything\n  else. Task-matched skills (like the completion-evidence checklist) now\n  actually arrive.\n\n## What's New in v20.8.2\n\n- **Skill delivery now admits failure instead of hiding it.** A filesystem\n  permission edge case (a umask stripping the owner-execute bit) could leave\n  skill sync writing nothing while reporting itself current — measured at nine\n  days on a real machine. Broken managed directories are repaired in place,\n  every directory is created umask-proof, and the repair path refuses symlinks\n  via an `O_NOFOLLOW` descriptor.\n- **A stale install tells you at startup.** Prism now tracks the generation\n  that actually reached disk separately from the one the database accepted; if\n  they diverge, the startup banner says so in a warning placed where display\n  truncation cannot cut it. A successful sync clears it automatically.\n\n## What's New in v20.7 – v20.8.0\n\n- **First run proves the memory instead of describing it** — `session_bootstrap`\n  seeds one demo memory and shows it *recalled from disk*, so the save→recall\n  loop is felt in session 1. One-shot, contained in its own `prism-demo`\n  project, removable with one call.\n- **Dashboard fixed** — a quoting typo (shipped 2026-05-29) killed the inline\n  script at parse time, so every dashboard since rendered \"Loading projects...\"\n  forever. Fixed, and the ES5 lint now `node --check`s the built inline script\n  so an unparseable dashboard can never ship again.\n- **Trusted Publishing** — npm releases authenticate via GitHub OIDC. No stored\n  token to expire or leak, and every release carries a signed [provenance\n  attestation](https://docs.npmjs.com/generating-provenance-statements) — you\n  can verify the tarball you install was built from this repo by CI\n  (`npm audit signatures`).\n- **TLS enforced for cloud sync** — a remote `http://` storage URL is upgraded\n  to `https://` instead of silently sending session content in the clear.\n- **Codex plugin collision + enabled-state detection** — `prism connect` skips\n  its own registration only when a plugin *actually* provides `prism-mcp`\n  (cache present **and** enabled), preventing both duplicate and missing\n  servers.\n- Windows CI stabilized; registry/npm listings realigned and deduplicated.\n\n## What's New in v20.6.0\n\n### Delivery Is Not a Suggestion\n\nAn audit of a real incident (an agent wiped demo data after *announcing* the\nwipe — with the ask-first rule committed, bundled, and absent from what any\nagent actually received) found the protected floor had outgrown every delivery\nbudget: \"unprotected\" had quietly come to mean \"never delivered\".\n\n- **`ask-first` and `feature-preservation` join the protected floor** (14 → 16).\n  Protected skills are always inlined; these two now reach every session.\n- **Sync conflicts are loud and named.** Startup used to say \"· 2 local\n  conflicts preserved\" while safety skills sat months stale; it now names each\n  frozen skill and states how to resume updates.\n- **`--storage` accepts `auto` and `synalux`** — the CLI rejected its own\n  documented default and the production backend.\n- **Disclosure:** skill delivery informs; it does not gate. A live probe showed\n  a host agent still edit unverified source with the rule loaded. If your\n  threat model includes an agent acting against a loaded rule under task\n  pressure, pair this package with mechanical gates (hooks, permissions,\n  least-privilege roles). True of every prior release; stated from this one.\n\n## What's New in v20.5.3\n\n### Grounding Evidence Carries Its Age\n\nMemory-grounded answers labelled their sources but never dated them, so a\ntwo-year-old note and yesterday's reached the model identically. Nothing in the\nevidence let it discount the stale one. Prompted by an external review naming\nthe right risk for local-first memory: *the data stays local, but bad grounding\nbecomes permanent* — storing everything on your machine removes the outside\npressure that would otherwise surface a stale note.\n\nEvidence now reads:\n\n```\n[SOURCE 1: ledger:8286581d (recorded 2025-05-29, 431 days ago)]\n```\n\nThe date already existed in storage and was being dropped at the snippet layer,\nso this is plumbing rather than new data collection. Zone-less SQLite\ntimestamps are normalised to UTC — read as local, a ten-minute-old record\nparsed hours into the future and its age was suppressed entirely, meaning the\nfeature silently did nothing on the freshest memories. An absent or unparseable\ndate renders as nothing rather than defaulting to now; defaulting would make\nthe oldest memories, the ones most likely to be stale, appear freshest.\n\n`tests/integration/grounding-staleness.test.ts` runs the reviewer's own probe —\nseed a deliberately outdated note beside a contradicting fresh one and assert\nthe model receives both, visibly dated. Anyone can run it.\n\n**Not solved, and not claimed:** retrieval does not weight recency. A stale note\nshown *beside* a fresh one is the easy case — the model sees both dates and can\nweigh them. The hard case is a stale note retrieved *alone*, because ranking is\nby keyword match and an old store returns old results; then the age label is the\nonly defence and there is no fresher record to compare against. Tracked as\n`TECH_DEBT.md` #4.\n\n## What's New in v20.5.0 – v20.5.2\n\n### The First Message Never Leaves Your Machine\n\nSymptom-triggered skills — the rules that fire on \"can't see X\", \"no rows\",\n\"the list is empty\" — are meant to load on the turn an incident report arrives.\nThey never did: every host template called `session_bootstrap` with `{}`, so\nthere was no prompt to match against.\n\nFixing that raised the question of where matching happens. It now happens\nlocally. The 28 keyword rules are already public, so there was nothing a local\nmatch could not compute, and `callPortal()` has no `prompt` parameter at all —\nthe guarantee is structural, not a promise. The portal request carries the\nproject and role only.\n\nA matched rule now arrives as **content**, not as a name. Native hosts outside\nthe skill-file mirror had no way to read a rule they were only told about, so\nthe rule body is inlined into the startup display, bounded and sized against\nthe real per-project budget.\n\n## What's New in v20.4.0\n\n### An Explicitly Named Cloud Backend Fails Loud\n\nSetting `PRISM_STORAGE=synalux` or `=supabase` with incomplete credentials used\nto downgrade silently to local SQLite. The switch was logged to stderr, which\nMCP hosts discard, so nothing surfaced it: sessions kept serving stale local\ncontext while the cloud held newer history, and `context_source` read `local`\nrather than any kind of warning. A session could run that way for weeks.\n\nNaming a backend outright is a strong statement of intent, so it now throws —\nnaming the missing variables and the `PRISM_STORAGE=local` opt-out — instead of\nquietly splitting your session history. `auto` is unchanged: it keeps its\ndocumented `synalux > supabase > local` degradation, pinned by a test.\n\n**Upgrade note:** if you explicitly set `PRISM_STORAGE=synalux|supabase` and\nyour credentials are incomplete, startup now fails with a named error instead\nof silently using local data. That error is the fix — set the missing variable,\nor choose `PRISM_STORAGE=local` deliberately. Default (`auto`) configs are\nunaffected.\n\nThe throw is deliberately not treated as a recoverable startup fault: that path\nexists for transient errors (rate limits, 5xx, DNS), which may degrade behind a\nvisible notice. A missing credential is a configuration fault and must not be\npapered over.\n\nAlso: the skill block is now budgeted by default rather than only on request,\nso a large skill payload cannot crowd out briefing and history.\n\n## What's New in v20.3.2\n\n### Web Scholar: SSRF Hardening\n\nSecurity release. Web Scholar scrapes article URLs that come from\nsearch-engine output, so the target is attacker-influenceable through SEO\npoisoning — and because what it scrapes is written into the memory corpus and\npassed to the configured LLM, a redirection to a local address meant reading an\ninternal service *and* sending the result onward.\n\nThe host guard matched string prefixes instead of parsing the address, and six\nspellings of a local address got through: `[::1]` (`URL.hostname` keeps the\nbrackets), `127.0.0.2` (only `.1` was enumerated, not all of `127.0.0.0/8`),\n`0.0.0.0`, `[::ffff:127.0.0.1]`, `localhost.` (a trailing dot defeated every\nsuffix check at once), and `[64:ff9b::7f00:1]` (NAT64 embeds IPv4 in its low\nbits). Host classification now parses addresses and also covers CGNAT,\nbenchmarking, multicast, reserved, and IPv6 unique-local and link-local ranges.\n\nDNS rebinding is closed too. Every check read the URL string, so a hostname the\nattacker controls passed all of them and could still resolve to `127.0.0.1`.\nTargets are now resolved first, every returned address is validated, and the\nconnection is pinned to those addresses so the name is never resolved a second\ntime — which also shuts the window between the check and the connect.\n\nScrape failures no longer vanish into a bare `catch {}`, a run is bounded by\n`PRISM_SCHOLAR_SCRAPE_BUDGET_MS` (default 60s) instead of stalling on a raised\narticle count, and responses are capped at 8 MiB.\n\nThis is reachable only when scholar actually runs — `scholar_research`, or the\nbackground loop under `PRISM_SCHOLAR_ENABLED=true` — and when the attacker also\ncontrols DNS or a search result. Upgrade if you use Web Scholar.\n\n---\n\n## What's New in v20.3.1\n\n### Prism Browser Reports Real Failures\n\n`prism browser` could not fail a test. `eval 1 === 2` returned `status: ok`\nwith exit code 0, a page serving HTTP 500 reported `status: ok`, and console\nerrors and uncaught page exceptions were discarded entirely. This release adds\nassertions — `assert-text`, `assert-visible`, `assert-count`, `assert-url`,\n`assert-title`, `assert-eval`, `assert-no-page-errors` — that return\n`status: failed` and a non-zero exit. `open` now reports `http_status` and\nfails on 400 or higher, screenshots are validated rather than assumed, and\n`eval` returns native JSON with its type instead of a Python `repr`.\n\nThe fingerprint layer had never been applied: a wrong keyword argument made\nthe stealth library throw on every launch — 1,139 failures and 0 successes\nsince April — while the runner reported it as active. It is fixed, and a layer\nthat cannot be applied now fails loudly. The headless build no longer\nadvertises itself through `navigator.userAgentData` or the `Sec-CH-UA` header,\nand a patch that corrupted `Object.getOwnPropertyDescriptor` on every page\nunder test has been removed. These remain best-effort test aids, not a\nguarantee against bot detection.\n\n`--local-only` now actually isolates: WebSocket, EventSource, WebRTC and\n`sendBeacon` egress bypass request routing and were never blocked, and service\nworkers were allowed through. `--cleanup` was a no-op in the two modes agents\nuse. Site isolation, phishing detection and popup blocking are no longer\ndisabled by default, since these profiles hold live authenticated cookies.\n\nNew for test runs: `--ephemeral-profile` and `--storage-state` for hermetic\nauthenticated flows, `pages`/`switch-page` so OAuth popups are reachable,\n`--fail-fast`, `--fast`, `--trace`/`--video`/`--har`, and\n`profiles --prune-older-than` for profile maintenance.\n\n---\n\n## What's New in v20.2.7\n\n### Session Saves Survive Agent Restarts\nPrism now remembers that a conversation successfully loaded its project context\nwhen the MCP server restarts or another Prism process handles the next request.\n`session_save_ledger` and `session_save_handoff` no longer fail with a false\n`context_not_loaded` error in that flow.\n\nThe recovery remains fail-closed: authorization is limited to the exact project\nand conversation, expires with the existing context window, and stores no\nplaintext conversation identifier. Cross-project, forged, malformed, expired,\nor future-dated receipts are still rejected. The release also updates PostCSS\nto the patched 8.5.23 release.\n\n---\n\n## What's New in v20.3.0\n\n### Hybrid Memory Search (Portal Tier)\n\n`session_search_memory` on the portal tier (Synalux-backed installs) now\nfuses semantic similarity with exact-term lexical matching via weighted\nreciprocal-rank fusion. Measured on blind probes against a real\n8.5k-entry corpus: fused retrieval was **never worse** than semantic\nalone at top-5, and exact identifiers — TPNs, function names, error\nstrings — now rescue queries that embedding similarity blurs. Results say how they were found — `hybrid retrieval`\nheaders, per-hit `sem#/lex#` arms — and a lexical-only rescue is labelled\n`exact-term match` instead of pretending to a similarity score. Local\nSQLite installs keep pure vector search; hybrid needs the portal's\nlexical index.\n\n## What's New in v20.2.6\n\n### Safer Configuration Updates Across Every Agent\n`prism connect` now reads Claude, Cursor, Gemini, and Codex configuration\nthrough a single verified file snapshot, preventing another process from\nswapping a file between Prism's safety check and its read. Supported symlinked\ndotfiles still work, while dangling or planted symlinks fail loudly instead of\nbeing followed or overwritten. This release also carries the patched\ndependencies and cross-platform release checks introduced in v20.2.5.\n\nCloud fallback is now documented consistently as Gemini 3.6 Flash. Plan\nceilings govern automatic `prism_infer` routing; direct use of any downloaded\nmodel through local Ollama remains free on every tier.\n\n---\n\n## What's New in v20.2.4\n\n### Reliable Session Memory That Shows Work, Not Greetings\nGreeting-only assistant replies are skipped before ledger writes. Existing\ngreeting rows are filtered at read time across native startup, MCP context, and\n`prism load --json`, while entries containing decisions, TODOs, changed files,\nor non-session events remain visible. Historical rows are not destructively\ndeleted. If Synalux has a transient startup failure, Prism displays one bounded\nlocal last-good snapshot and clearly labels it; permanent authorization or\nvalidation failures still fail loud, and later writes remain cloud-routed.\n\n---\n\n## What's New in v20.2.2\n\n### One Local-First Workflow Across Every Agent\n`prism connect` now installs one orchestration contract for Claude Code,\nClaude Desktop, Cursor, Gemini CLI, and Codex. Bounded delegated work goes to\n`session_task_route` and the local `prism_infer` worker first; routine work must\nnot create background host agents. Local workers can receive the active\nproject's dashboard-configured quick, standard, or deep memory and select a\nRAM-safe 2B/4B/9B/27B model at call time. The router forwards complexity but\ndoes not choose the model; `prism_infer` owns the final decision using memory\nand context fit, installed models, live RAM, entitlements, and explicit caller\noverrides.\n\nCodex and Gemini native agent fan-out are disabled during connect. Codex keeps\na two-thread, one-level Terra/low fallback profile if the developer explicitly\nre-enables native agents later. Claude Code keeps native agents as a last-resort\npath but pins their model to Sonnet. Cursor and Claude Desktop do not expose a\nsupported global subagent-policy file, so they receive the identical workflow\nthrough Prism's MCP server instructions. `prism_infer` safety boundaries and\nthe host's final verification responsibility are unchanged.\n\n### Subscription-Tier Skills Arrive Before the First Host Launch\n`prism connect` now downloads the authoritative Synalux skill manifest and\nmaterializes entitled packages in the native `~/.agents/skills` directory\nbefore the command exits. Codex therefore sees the current skillset on its\nfirst launch instead of requiring a second restart. Prism rechecks the same\nsnapshot at MCP startup, session load, and every five minutes—skill delivery\nnever depends on a host lifecycle hook.\n\nOn the first user turn, Prism's native skill, MCP metadata, and managed host\ninstructions request one `session_bootstrap({})` call. Prism then uses the\ndashboard's developer name, Auto-Load Projects, and quick, standard, or deep\nsetting. The response stays focused on greeting and session state because tier\nskills are already present in the host's native skill directory.\n\nHook-free MCP can provide and prioritize that ready-to-display block, but the\nhost model still owns the final assistant message and may summarize it. Prism\ndoes not claim a deterministic verbatim greeting on third-party chat surfaces;\nthat would require a host lifecycle hook, launcher, extension, or Prism-owned\npanel. Context loading itself remains complete even when a host shortens the\nvisible reply.\n\nFree accounts receive only the public hook-free `prism-startup` package; the MCP\nserver still supplies a compact, non-proprietary safety and evidence contract.\nAuthenticated paid accounts receive the protected behavioral and engineering\npackages plus the current subscribed routing set. The paid\n`evidence-first-protocol` keeps ordinary coding lightweight: one correlated\nreproduction is enough to begin an edit, while strict acceptance starts only\nbefore a completion claim, push, or release and inspects only the exact artifacts\nused as proof. Upgrades install newly entitled packages; verified downgrades\nremove only Prism-owned packages while preserving local skills and locally\nmodified conflicts.\n\nWhen upgrading an older Claude Code installation, `prism connect` removes only\nthe exact Prism-owned startup, skill-sync, handoff, and drift hook actions from\nthe legacy bootstrap. It also removes the recognized legacy Prism startup\nsections from `~/CLAUDE.md`, preserves every other instruction, and installs a\nsmall ownership-marked native block that selects `session_bootstrap({})` on the\nfirst turn. User hooks, custom instruction sections, and near matches remain\nuntouched; native skills and server-side reminders preserve those Prism\nfeatures without depending on host lifecycle hooks. On Claude Code and Codex\nconnect additionally registers the prism-route script twice: on every prompt\n(mid-session skill routing) and on `SessionStart` matched to `compact` only\n(post-compaction protected-floor digest). Because hosts expose no native\nsession-end callback, handoff at shutdown is instruction-driven rather than a\nguaranteed lifecycle event.\n\nAfter Claude Code's native user registration succeeds, the same default or\n`--refresh` command checks the nearest `.mcp.json` from the current directory\nthrough the home directory. It removes only the exact legacy\n`prism-mcp` entry `{ \"command\": \"npx\", \"args\": [\"-y\", \"prism-mcp-server\"] }`\nthat would otherwise shadow the user registration. Custom Prism entries and\ntheir additional fields, plus unrelated servers, are preserved; malformed\nfiles fail loud without changes. `--dry-run` reports the recognized migration\nwithout changing the file.\n\n---\n\n## What's New in v20.2.1\n\n### Subscription-Aware Memory Storage\n`prism connect` now carries an explicit `PRISM_STORAGE=auto|local|synalux|supabase`\ninto every managed host registration and rejects invalid values before changing a\nconfig file. In `auto`, a portal-confirmed free tier uses local SQLite, while\nStandard, Advanced, and Enterprise use Synalux cloud memory. If entitlement\nresolution is unavailable, Prism fails closed instead of splitting history across\nbackends. Storage remains independent of local-first model routing.\n\n---\n\n## What's New in v20.2.0\n\n### One Command Connects Every Supported Host\nInstall Prism globally and run `prism connect`. It detects Claude Code, Claude\nDesktop on macOS, Windows, and Linux (beta), Cursor, Gemini CLI, and Codex, then safely registers the\nserver from the installed package. Existing custom entries are untouched;\n`--dry-run` previews changes and `--refresh` updates only Prism-managed entries.\n\n---\n\n## What's New in v20.1.0\n\n### Every Inference Outcome Is Now Observable\n`prism_infer` gains a failure contract: pass `escalation: \"report\"` and every call returns a structured `gate_outcome` — `success`, `degraded` (gate-failed output served anyway, explicitly flagged), or `refused` (typed, with reason, instead of a thrown error). Degraded output can no longer serve silently.\n\n### Big Prompts Work Locally\nPrompts over 4000 chars were blanket-refused when cloud was off. Now the full text gets a deterministic reserved-keyword scan plus a head+middle+tail excerpt classification — clean oversize prompts serve locally with a distinct `UNCERTAIN_LENGTH` audit marker. Clinical/reserved handling is unchanged (and its keyword floor got stronger).\n\n### No More Silent Truncation\nTier context limits now match the live Modelfiles (27b/9b are 4096-token models; 4b/2b are 32768 — the old table had it backwards). Tiers that can't hold your prompt are skipped with a visible `ctx_insufficient` reason; if nothing fits, you get the full prompt on cloud or a loud error — never an answer computed from a silently-clipped prompt.\n\n### Know Which Plan You're Actually Running Under\nEntitlements carry a `source` field: `portal` (real), `unconfigured` (free by design), or `fallback_free` (portal unreachable — free limits ASSUMED). Pass `strict_entitlements: true` to fail loud instead of running degraded.\n\n---\n\n## What's New in v20.0.8\n\n### verify_behavior Works Again\nThe `verify_behavior` tool crashed on every call (`-32602 expected object, received string`) — the handler returned a bare string instead of an MCP `CallToolResult` object. Fixed, with contract + fail-closed regression tests so the safety gate can never silently break again. If you're on 20.0.6/20.0.7, update.\n\n### From v20.0.7: Reserved-Content Safety, Skills Auth, Delegation Metrics\nReserved clinical content is now Claude-or-refuse (never served by a smaller model than the one that refused it), skill delivery gained a JWT auth fallback (paid-tier skills now reach machines using only `PRISM_SYNALUX_API_KEY`), and every `prism_infer` call is recorded in a persistent `infer_metrics` ledger. Full details in [CHANGELOG.md](CHANGELOG.md).\n\n---\n\n## What's New in v20.0.5\n\n### Local-First Delegation — 15 Categories, Measured Rate\nThe `local-inference-first` skill covers 15 hard-trigger categories (code gen, regex, format conversion, summarization, documentation, factual lookup, classification, shell commands, config gen, and more). Pasted code blocks now trigger delegation regardless of question phrasing. Measured delegation rate: **30-35% on engineering sessions, 40-60% on transform/content sessions**. Rate depends on prompt mix, not the skill — the instruments now self-validate with `nonDelegatedCount` to prevent curated-set tautologies.\n\n### Think-Only Retry (v20.0.4)\nQwen 3.5 models (9B/27B) with thinking enabled could burn all tokens on `<think>` blocks and return empty content, causing a cascade to 4B. Now detects think-only responses and retries the same tier with thinking disabled — preserving model quality instead of falling to a smaller model.\n\n---\n\n## What's New in v20.0.3\n\n### Layer 1 Cold-Model Resilience\nThe reserved-category classifier now retries once with a longer timeout on cold-model failure, then falls back to a deterministic keyword backstop before refusing. Over-length prompts (>4K chars) are classified as UNCERTAIN before reaching the classifier — prompt padding can no longer force the ERROR branch. This eliminates the cold-start refusal problem without weakening the safety gate.\n\n### Keyword Backstop for Reserved Content\nWhen the LLM classifier fails (timeout, injection, resource pressure), a deterministic regex floor catches reserved vocabulary (restraint, seclusion, self-harm, suicide, overdose, crisis de-escalation, etc.) including inflected and verb forms. Blocks prompt-padding and classifier-injection attacks on the ERROR path.\n\n### Single-Source Safety Text\nThe safety statement in the MCP server `instructions` field now imports from `boundaries.ts` — one source of truth instead of two hand-maintained copies. Boundaries version bumped to v3 with an explicit delivery decision documented in code.\n\n### Reserved-Category Safety Gate — All Tiers (v20.0.2)\nThe Layer 1 semantic classifier now runs for **every** user, not just paid tiers. Reserved clinical content is refused on free tier when cloud is unavailable — fail-closed.\n\n### Ledger Dedup (v20.0.2)\n`session_save_ledger` deduplicates identical entries within a 5-minute window.\n\n### Evidence Script (v20.0.2)\n`scripts/generate-evidence.sh` regenerates all 5 evidence files with built-in assertions. Run `bash scripts/generate-evidence.sh` to verify the full pipeline.\n\n---\n\n## What's New in v20.0.0\n\n### License: AGPL-3.0 → Apache-2.0\nPrism MCP is now Apache-2.0. The thin-client architecture means all proprietary value (skill resolution, tier gating, billing, cloud inference) lives server-side — the open client carries no moat to protect. Apache-2.0 removes the enterprise adoption friction that AGPL caused.\n\n### Thin Client Architecture\nSkill routing, budget management, and content resolution have moved server-side to the Synalux portal. The MCP client is now a thin API caller — simpler, smaller, and portable across any host (Claude Code, Gemini, Cursor, autonomous scripts). Offline fallback reads the last successful response from local SQLite.\n\n### Clean-Room Voyage AI Adapter\nThe Voyage AI embedding adapter was independently reimplemented from the [Voyage API docs](https://docs.voyageai.com/reference/embeddings-api) to ensure 100% project-owned copyright. Default model updated to `voyage-3.5`. See [PROVENANCE.md](./PROVENANCE.md) for details.\n\n### Server-Side Drift Detection\nSession drift detection (GATE 5) no longer requires Claude Code hooks. The timer runs server-side per conversation, piggybacked on every MCP tool response. Works for any host.\n\n### CLA Requirement\nExternal contributions now require signing the [Individual CLA](./CLA.md). The CLA check is merge-blocking on the `main` branch.\n\n---\n\n</details>\n\n## Quickstart\n\nThe free tier needs no account, no API key, and no cloud. Install Prism, then\nregister it with every supported MCP host already installed on your machine:\n\n```bash\nnpm install --global prism-mcp-server\nprism connect\n```\n\n`prism connect` detects Claude Code, Claude Desktop (macOS/Windows/Linux), Cursor,\nGemini CLI, and Codex.\nUse `prism connect --all` to target all five, `--host <name>` for one host, or\n`--dry-run` to preview the files that would change. Existing `prism` and\n`prism-mcp` entries are never overwritten by default. `--refresh` updates only\nan entry previously created by Prism; custom entries remain untouched.\nFor Claude Code, both the default command and `--refresh` also remove the exact\nlegacy project-scoped `npx -y prism-mcp-server` entry from the effective\nancestor `.mcp.json` after the native user registration succeeds. No custom or\nnear-match project entry is changed.\nClose the target MCP hosts before a non-dry-run registration so they cannot\nedit their configuration at the same time.\n\nThe same connection installs the local-first orchestration contract:\n\n| Host | Managed containment |\n|---|---|\n| Codex | `features.multi_agent=false`; a 2-thread, depth-1 Terra/low fallback profile is retained for explicit re-enable |\n| Gemini CLI | `experimental.enableAgents=false` |\n| Claude Code | `CLAUDE_CODE_SUBAGENT_MODEL=sonnet`; managed instructions reserve it for last-resort fallback |\n| Cursor | Canonical policy delivered through MCP initialize instructions |\n| Claude Desktop | Canonical policy delivered through MCP initialize instructions |\n\nAll five receive `PRISM_AGENT_POLICY=local-first` in their managed Prism MCP\nentry. Routine tasks use the RAM-aware local worker; native/background fan-out\nis not the default workflow. `session_task_route` supplies a complexity hint;\n`prism_infer` remains the single owner of model and thinking selection and can\nchoose 27B when its viability gates support it.\n\nSet `PRISM_STORAGE` before running `prism connect` to preserve an explicit\nstorage choice in the generated host entries. This does not change local-model\nrouting; Synalux cloud storage separately requires an active cloud-memory\nentitlement.\n\nCodex registration preserves unrelated `~/.codex/config.toml` content, appends\nonly the marked Prism MCP block, and updates only the documented local-first\nfeature/agent keys. `CODEX_HOME` is respected when set and must already exist,\nmatching Codex's own contract. Restart Codex CLI, the\nIDE extension, or the ChatGPT desktop app after connecting.\n\nRestart the connected host and your agent now has memory backed by a local\nSQLite database (`~/.prism-mcp/data.db`). See [IDE setup](docs/IDE_SETUP.md)\nfor manual configuration and host-specific paths.\n\n**Optional — local model fleet** for offline tool-routing. Pull whichever fits your hardware:\n\n```bash\nollama pull dcostenco/prism-coder:2b    # 3.3 GB  · on-device / lowest RAM · sees images (100% on our routing suite)\nollama pull dcostenco/prism-coder:4b    # 3.5 GB  · verifier · sees images (100%)\nollama pull dcostenco/prism-coder:9b    # 6.7 GB  · default router · sees images (95.7%, reasons before answering)\nollama pull dcostenco/prism-coder:27b   # 16.8 GB · complex code / quality · text only (100%)\n```\n\nPrism detects both the namespaced (`dcostenco/prism-coder:9b`) and bare (`prism-coder:9b`) Ollama tags automatically.\n\nThe 2b/4b/9b tiers carry a vision tower and accept screenshots through\n`prism_infer({ images: [...] })` — pass absolute paths or base64. Image\nrequests are refused rather than answered blind when no tier (or the Layer 1\nsafety classifier) can actually see the image, so a text-only model is never\nhanded a prompt about a screenshot it never received. The 27b is text only.\n\n---\n\n## What it does\n\nYour AI agent forgets everything between sessions. Prism fixes that — and adds verification, drift detection, and multi-agent coordination on top.\n\n### Mind Palace — persistent memory that survives across sessions\n\nEvery conversation feeds a persistent store. The next session loads the right context automatically — no re-explaining.\n\n<p align=\"center\">\n  <img src=\"docs/mind-palace-dashboard-v20.8-full.png\" alt=\"Mind Palace Dashboard — full page: session ledger, memory analytics, lifecycle controls, background scheduler\" width=\"700\" />\n</p>\n\nThe dashboard shows your current project state, pending TODOs, intent health, and a neural knowledge graph — all built automatically from your agent sessions.\n\nIt runs on loopback and is gated by a per-startup token by default — open the\ntokenized URL printed in the startup log (`http://localhost:3000/?token=…`).\nRequests with an untrusted `Host`/`Origin` are refused, closing the DNS-rebinding\nexposure fixed in GHSA-9cvx-7x8q-3g6m. See [docs/IDE_SETUP.md](docs/IDE_SETUP.md#securing-the-dashboard)\nto pin the token, disable it, or configure Basic Auth / JWKS.\n\n### Export — read the record outside the agent\n\n`session_export_memory` writes your memory out as plain files you can read,\ndiff, and commit. Nothing goes through a model to produce it.\n\n```\nmarkdown   human-readable — drop it in a PR to show what the agent actually did\njson       machine-readable — import into another Prism instance\nvault      zipped Markdown with YAML frontmatter and [[wikilinks]] (Obsidian, Logseq)\n```\n\nThis is the surface to reach for when you want to answer \"did the agent verify\nthis, or is it claiming it did?\" — the export is a record you review after the\nfact, in a diff or a pull request, rather than a live view you have to go and\nopen. The same data is available from the dashboard's **Export ZIP** and\n**Export Vault** buttons.\n\n### Knowledge Graph — semantic + keyword + graph search\n\nAsk \"what did I decide about the auth flow last month?\" and get an answer with citations, combining vector similarity, full-text search, and graph traversal.\n\n<p align=\"center\">\n  <img src=\"docs/knowledge-graph.jpg\" alt=\"Knowledge Graph — 190 keywords, 47 edges, 12 projects visualized\" width=\"500\" />\n</p>\n\n### Session History — immutable audit trail\n\nEvery session is logged with files changed, decisions made, and TODOs. Search, filter, and replay any past session.\n\n<p align=\"center\">\n  <img src=\"docs/session-ledger.jpg\" alt=\"Session Ledger — 93 sessions, 847 decisions logged across 12 projects\" width=\"700\" />\n</p>\n\n### Inference Metrics — see where your tokens go\n\nEvery `prism_infer` call tracks which model handled it (local Ollama vs cloud) and how many tokens were consumed. When you save a session, Prism shows a summary:\n\n```\n📊 Inference Metrics (this session):\n  Total calls: 12 — Local: 10 (83%) | Cloud: 2 (17%)\n  Prompt tokens: 7,840 evaluated / 8,420 submitted est.\n  Completion tokens: 3,150\n  Cloud tokens saved (est.): 11,570 — token volume handled locally instead of cloud\n  Avg latency: 1,240ms\n  By model:\n    prism-coder:27b: 6 calls, 7,200 tokens, avg 1,800ms\n    prism-coder:9b: 4 calls, 2,870 tokens, avg 620ms\n    synalux-27b: 2 calls, 1,500 tokens, avg 1,100ms\n```\n\n**Cloud tokens saved** is the honest routing metric — it accrues only when local Ollama handles a call that would otherwise have gone to Synalux cloud inference. A compact version appears inline after every 5th `prism_infer` call: `📊 local 10 (83%) · cloud 2 (17%) · ~11,570 tok · avg 1,240ms · 11,570 cloud tok saved`.\n\nLocal calls use actual Ollama token counts (`prompt_eval_count` / `eval_count` from Ollama); cloud calls use char/4 estimates. Metrics are tracked locally — no portal dependency, no env vars, works offline. Per-call data is also forwarded to the Synalux portal as best-effort analytics (independent of the display).\n\n### Session Drift Detection\n\nLong agent sessions can wander from their original goal. `session_detect_drift` compares current work against the stated goal and returns `on_track / minor_drift / major_drift` so the agent can self-correct.\n\n### Behavioral Verification — catch bad edits before they happen\n\nAI agents apply patterns from checklists without understanding the real-world impact. The `verify_behavior` tool challenges the agent with a scenario it must answer **before** editing — forcing it to think through what the end user will experience.\n\n```\nAgent: \"I'll revert this kitchen display change\"\nPrism: \"⚠️ Scenario: A cook sees a 3-item ticket. One item is voided.\n        What should the cook see after the void?\"\nAgent: \"The ticket stays visible with the remaining 2 items.\"\nPrism: \"Correct — your revert would hide the ticket entirely.\"\n```\n\n17 built-in domains (billing, auth, ordering, clinical, HR, and more). Custom domains per workspace on Enterprise. No hooks needed — works in any MCP client.\n\n### Time Travel\n\nRoll back to any previous session state. Compare diffs between versions. Restore a known-good state with one click.\n\n<p align=\"center\">\n  <img src=\"docs/time-travel-timeline.jpg\" alt=\"Time Travel — version timeline with diff view and one-click restore\" width=\"500\" />\n</p>\n\n### Cognitive Routing\n\nThree memory types, automatically sorted: **episodic** (what happened — session logs, decisions), **semantic** (what's true — facts, architecture), and **procedural** (how to do X — workflows, patterns). When you search, the router picks the right store instead of dumping everything.\n\n### Multi-Agent Hivemind\n\nCoordinate multiple AI agents working on the same project. Each agent has its own session, but they share memory through the knowledge graph. The Hivemind Radar shows real-time agent status, tasks, and activity.\n\n<p align=\"center\">\n  <img src=\"docs/hivemind-radar.jpg\" alt=\"Hivemind Radar — 5 agents with real-time status, tasks, and activity feed\" width=\"500\" />\n</p>\n\n### Neural Search\n\nSearch across all memories with highlighted results, knowledge graph editing, and memory density metrics.\n\n<p align=\"center\">\n  <img src=\"docs/v6_cognitive_load_dashboard.jpg\" alt=\"Neural Search with Knowledge Graph Editor and Memory Density\" width=\"500\" />\n</p>\n\n---\n\n## Local-first and privacy\n\nThe free tier runs entirely on your machine. Paid tiers add cloud sync through the Synalux portal, which is what enables cross-device memory and team sharing.\n\n| | Local tier (free) | Cloud tier (paid) |\n|---|---|---|\n| Memory storage | Local SQLite | Synalux portal (Supabase-backed) |\n| Inference | Local Ollama models | Local models + Gemini 3.6 Flash fallback |\n| API keys required | None | Synalux subscription key |\n| Web search / scrape | Not included | Via Synalux portal (provider keys server-side) |\n| What leaves your machine | Nothing | Memory text, file paths, search queries, and inference prompts/drafts when their cloud feature is used, sent to the portal over TLS. Cloud memory writes are PHI-redacted; inference and route requests are transient. |\n| Works offline | ✅ | Local features yes; sync/cloud no |\n\n**Handling sensitive data.** Cloud memory writes pass through automatic\nredaction (SSNs, dates of birth, medical record numbers, phone numbers, emails,\nand clinical identifiers are stripped before storage). Cloud inference and\nroute correction send the request over TLS for processing and do not store it\nas Prism memory; use `route_guard: \"local\"` or the **local tier** for a full\nair-gap. **Enterprise** includes a HIPAA Business Associate Agreement.\n\n---\n\n## Models\n\nThe `prism-coder` fleet uses Qwen3.5 for MCP tool-routing AND general inference. The 9B and 27B are fine-tuned; the 2B and 4B use stock Qwen3.5-4B at different quantization levels. The 27B scored 100% on our internal 115-case tool-routing suite and 100% on an internal 15-problem coding eval, at $0 inference cost. These are self-run evaluations, not [BFCL](https://gorilla.cs.berkeley.edu/leaderboard.html) leaderboard submissions.\n\n`prism_infer` supports three modes: `route` (tool routing, fast), `chat` (conversation) and `code` (code generation). Reasoning is decided by the **tier**, not the mode: a tier carrying `MODEL_TIERS.prefersThinking` also carries a `minLocalTokens` floor so reasoning cannot crowd out the answer, and only those tiers use `<think>` blocks (stripped before the response is served). The 9B does; the 4B and 2B do not, because on those tiers reasoning drew down the same `num_predict` budget the answer needed and returned an empty response. An explicit `think: true` still overrides, for a caller who has sized `max_tokens` for it. If the local model fails a quality gate (empty, think-only, or truncated), paid tiers automatically escalate to Gemini 3.6 Flash via the Synalux portal.\n\nEvery route-mode result is parsed locally and checked against `allowed_tools`\nbefore it reaches the host. Malformed or unadvertised calls become `NO_TOOL`.\nWith `route_guard: \"auto\"` (the default), Standard and higher plans also send\na well-formed draft for one of Prism's seven trained tools—or an unadvertised\ndraft that may need correction—to Synalux for authenticated deterministic\ncorrection. Advertised custom host tools remain local. Set\n`route_guard: \"local\"` for a fully on-device route path.\n\n| Model | Ollama tag | Size | Vision | Routing accuracy¹ | Role | Automatic routing tier |\n|---|---|---|---|---|---|---|\n| Qwen3.5-4B Q4_K_S | `prism-coder:2b` | 3.3 GB | ✅ | 100% | On-device / lowest RAM (4.5 GiB free) | Free |\n| Qwen3.5-4B Q4_K_M | `prism-coder:4b` | 3.5 GB | ✅ | 100% | Verifier (5.2 GiB free) | Free |\n| Qwen3.5-9B (LoRA) | `prism-coder:9b` | 6.7 GB | ✅ | 95.7%² | Default router / workhorse (9 GiB free) | Standard+ |\n| Qwen3.5-27B (LoRA) | `prism-coder:27b` | 16.8 GB | — | 100% | Complex code / quality (21 GiB free) | Advanced+ |\n\n¹ Self-run on a narrow 115-case MCP tool-selection suite, `temperature: 0`,\nmeasured through the call path `prism_infer` actually uses (`/api/chat`, each\nmodel's own template). It says these models pick the right tool on our own eval,\nnothing more — not a general capability measure, and not an independent\nbenchmark result. Earlier revisions of this table quoted 99.1–100% from a\nharness that hand-rolled a ChatML prompt with `raw: true`, bypassing the\ntemplate; those numbers described a path no caller exercises. Full methodology\ncaveats below.\n\n² The 9B is the one tier that reasons before answering, and it is measured with\nreasoning enabled: 95.7% with thinking, 83.5% without. `prism_infer` sets this\nper-tier (`MODEL_TIERS.prefersThinking`), so callers get the 95.7% path by\ndefault. Reasoning costs roughly 600 tokens, which is why the 9B also carries a\n2,048-token local floor.\n\n**Vision.** The 2B/4B/9B tags ship a separate `projector` layer (0.68–0.92 GB)\nand read images; the 27B is text-only. `prism_infer` probes for that layer and\nskips a tier with no vision rather than sending it an image — asked directly, a\ntext-only model will still answer confidently about pixels it never received.\nExercised against the real models in `tests/integration/visionScreenshot.test.ts`.\n\nThese tiers control automatic `prism_infer` selection, not Ollama itself. Any\nuser can run any downloaded on-device model directly through Ollama on every\nplan.\n\nWeights: [huggingface.co/dcostenco](https://huggingface.co/dcostenco) (public GGUF). Latency depends on model size and hardware — see [Benchmarks](#benchmarks) to measure it on your own machine rather than trusting a printed number.\n\n### Cascade\n\n```\nquery → prism-coder:9b (local router, default)\n      → prism-coder:4b (grounding verifier)\n      → prism-coder:2b (iPhone / mobile, auto-selected by RAM)\n      → prism-coder:27b (complex tasks, on demand)\n      → Gemini 3.6 Flash cloud fallback (paid tiers, for max quality)\n```\n\n### Multi-Layer Verification\n\nRoute output and evidence-grounded answers use separate gates. Every tier gets\nthe local route parser and advertised-tool registry; Standard and higher plans\ncan add the privat",
  "bytes": 60000,
  "sha": "e70ae68f3ececb75233eab61d105ad3500139db0da0fe21527d89c852ad3a013",
  "repo_slug": "dcostenco/prism-coder",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_dcostenco_prism_mcp_c6781835/readme"
}