Prism Coder
About
Persistent session memory for AI coding agents - local-first recall, drift detection, and on-device inference.
Details
- Author
- dcostenco
- Categories
- AI
Jump to
Safer Configuration Updates Across Every Agent
prism connectnow reads Claude, Cursor, Gemini, and Codex configuration through a single verified file snapshot, preventing another process from swapping a file between Prism's safety check and its read. Supported symlinked dotfiles still work, while dangling or planted symlinks fail loudly instead of being followed or overwritten. This release also carries the patched dependencies and cross-platform release checks introduced in v20.2.5.
Cloud fallback is now documented consistently as Gemini 3.6 Flash. Plan ceilings govern automaticprism_inferrouting; direct use of any downloaded model through local Ollama remains free on every tier.
Give your AI agent memory that lasts.Persistent sessions, knowledge graphs, and offline tool-routing — fully local and free.
No account needed. No API keys. Runs on your machine.
A paid subscription adds cloud sync, higher model tiers, and team features through theSynalux portal.
- Session memory that survives restarts— resume projects with handoff notes, recent work, open TODOs, and configurable quick, standard, or deep context.
- Local-first inference— bounded work is routed through local Ollama models first, with automatic 2B/4B/9B/27B selection based on installed models, available RAM, context fit, and subscription entitlements.
- Route-output enforcement— route mode returns only well-formed calls to tools the host actually advertised. Standard and higher plans can add authenticated deterministic correction;route_guard: "local"keeps the prompt and draft entirely on-device.
- One setup for every agent—prism connectconfigures Claude Code, Claude Desktop, Cursor, Gemini CLI, and Codex while preserving unrelated settings.
- Subscription-aware skills— entitled skills are synchronized before the host launches, with safe upgrades, downgrades, conflict preservation, and offline last-good recovery.
- Hook-free startup— MCP metadata and native instructions request Prism's startup context without requiring lifecycle hooks or a Prism-owned launcher.
- Safe escalation and observability— inference outcomes are explicit, reserved content remains fail-closed, and local/cloud usage is recorded for review.
npm install -g prism-mcp-server prism connect
Useprism connect --dry-runto preview changes,prism connect --allto configure every detected host, orprism connect --refreshto reconcile Prism-managed entries after an upgrade. Restart the host after connecting.
Prism works locally without an account, API key, or cloud subscription. Add a Synalux subscription when you want cloud memory, paid-tier skills, or team features.
Prism also ships as a plugin, which registers the MCP server and the startup skill for you.
Claude Code— from the community marketplace:
/plugin marketplace add anthropics/claude-plugins-community /plugin install synalux-prism@claude-community
Codex— this repository is itself a plugin marketplace:
codex plugin marketplace add dcostenco/prism-coder codex plugin add synalux-prism@prism
The plugin registersprism-mcpvianpx -y prism-mcp-server. If you already configured Prism by hand —prism connectwrites anmcp_servers.prism-mcpentry — you have that server twice under one key. Install the pluginorrunprism connect, not both.
Whatprism connectchanges about host subagents
connectsteers bounded work toprism_inferon your machine rather than to host-spawned agents. What it writes differs per host, andit does not disable subagents everywhere— Claude Code keeps them and is pointed at an economy model instead. Prism's local workers stay available over MCP in every case.
- experimentalis Gemini's namespace, not ours.Prism is not enabling anything experimental — it writesfalseto a flag Gemini already defines at that path. Writing anywhere else would have no effect.
- That namespace is by definition temporary.If Gemini promotesenableAgentsout ofexperimental, Prism keeps writing the old path, Gemini reads the new one, and host subagents quietly turn back on. Nothing errors and the settings file still looks correct. If you see host subagents running whileenableAgentsreadsfalse, check whether the key has moved before assumingconnectfailed to write it.
Both writes are idempotent in the sense that a host already configured this way is left untouched — but they arere-applied on everyprism connectrun, not only on--refresh. If you deliberately re-enable host subagents, the nextconnectwill turn them off again. Keep them on by not re-runningconnect, or by re-enabling after each run.
- prism connect --refreshnow converges every registration it owns, not just the top-level one — directory-scoped entries could otherwise keep launching an old build indefinitely.
- prism updatechecks the installed package, not the CLI that happens to be running, so it can no longer report "current" while the install is stale.
- The opt-in scheduled updater can actually start— the LaunchAgent now carries a PATH that includes node and npm.
- Prism now tells you when it's out of date.Session startup shows a one-line update notice when a newer release exists — cache-backed, at most one registry check per day, silent offline.PRISM_NO_UPDATE_CHECK=1opts out.
- Hands-free updates, if you want them.prism autoupdate enablesets up a dailyprism update --if-idle: it updates only the global npm package, defers while any Prism server is running, and never touches host configuration — that stays behind a visibleprism connect.
- Saving memory never gets refused.The save path used to rejectsession_save_ledger/save_handoffcalls when its path-to-project heuristic disagreed with the project you declared — and the registry the heuristic trusted could contain junk from earlier auto-registration, so legitimate sessions ended unsaved. Your declaration now always wins; the disagreement is returned as an advisory warning, and auto-registration only accepts real repository roots.
- Screenshots are evidence again.prism browsercaptures on macOS were silentlyupscaledto the size cap, so a screenshot no longer showed what actually rendered. Only genuinely oversized captures are resized now, and the cap no longer clips a standard 1920-wide viewport.
- Skill routing now works mid-session.New prompts are matched on-device as the conversation moves — not just on turn one — and injected within each host's real context limits (Claude Code caps hook output at 10k chars; Codex truncates by default), with pointer-first delivery when a payload can't fit inline.
- prism connectis a converge command.It self-updates first, re-execs, then reconciles MCP registration, skills, and hooks — no more "fresh config, stale code" machines.
- Scoped skills route on prompts too, and startup output survives hosts that discard structured tool content.
Trim the catalog you don't use.skill_managecan release platform skills you never touch — freeing host skill-catalog budget — and restore them any time, losslessly. Deleting a scoped skill archives its final content locally first, so nothing is ever silently unrecoverable.
Delivery that queues instead of failing.Concurrent sessions no longer starve skill sync on the local config store (WAL + busy-timeout) — a failure that previously reported only "partial" where nobody could see it.
Withheld rules still bind.When the context budget can't inline a skill's text, the manifest of withheld names now states that those skills still govern the work and names every way to load them before completion claims.
The budget the floor never spent.A long-standing accounting bug meant no unprotected skill ever inlined at any normal context level — the always-inlined protected floor was debiting the budget meant for everything else. Task-matched skills (like the completion-evidence checklist) now actually arrive.
- Skill delivery now admits failure instead of hiding it.A filesystem permission edge case (a umask stripping the owner-execute bit) could leave skill sync writing nothing while reporting itself current — measured at nine days on a real machine. Broken managed directories are repaired in place, every directory is created umask-proof, and the repair path refuses symlinks via anO_NOFOLLOWdescriptor.
- A stale install tells you at startup.Prism now tracks the generation that actually reached disk separately from the one the database accepted; if they diverge, the startup banner says so in a warning placed where display truncation cannot cut it. A successful sync clears it automatically.
- First run proves the memory instead of describing it—session_bootstrapseeds one demo memory and shows itrecalled from disk, so the save→recall loop is felt in session 1. One-shot, contained in its ownprism-demoproject, removable with one call.
- Dashboard fixed— a quoting typo (shipped 2026-05-29) killed the inline script at parse time, so every dashboard since rendered "Loading projects..." forever. Fixed, and the ES5 lint nownode --checks the built inline script so an unparseable dashboard can never ship again.
- Trusted Publishing— npm releases authenticate via GitHub OIDC. No stored token to expire or leak, and every release carries a signedprovenance attestation— you can verify the tarball you install was built from this repo by CI (npm audit signatures).
- TLS enforced for cloud sync— a remotehttp://storage URL is upgraded tohttps://instead of silently sending session content in the clear.
- Codex plugin collision + enabled-state detection—prism connectskips its own registration only when a pluginactuallyprovidesprism-mcp(cache presentandenabled), preventing both duplicate and missing servers.
- Windows CI stabilized; registry/npm listings realigned and deduplicated.
An audit of a real incident (an agent wiped demo data afterannouncingthe wipe — with the ask-first rule committed, bundled, and absent from what any agent actually received) found the protected floor had outgrown every delivery budget: "unprotected" had quietly come to mean "never delivered".
- ask-firstandfeature-preservationjoin the protected floor(14 → 16). Protected skills are always inlined; these two now reach every session.
- Sync conflicts are loud and named.Startup used to say "· 2 local conflicts preserved" while safety skills sat months stale; it now names each frozen skill and states how to resume updates.
- --storageacceptsautoandsynalux— the CLI rejected its own documented default and the production backend.
- Disclosure:skill delivery informs; it does not gate. A live probe showed a host agent still edit unverified source with the rule loaded. If your threat model includes an agent acting against a loaded rule under task pressure, pair this package with mechanical gates (hooks, permissions, least-privilege roles). True of every prior release; stated from this one.
Memory-grounded answers labelled their sources but never dated them, so a two-year-old note and yesterday's reached the model identically. Nothing in the evidence let it discount the stale one. Prompted by an external review naming the right risk for local-first memory:the data stays local, but bad grounding becomes permanent— storing everything on your machine removes the outside pressure that would otherwise surface a stale note.
[SOURCE 1: ledger:8286581d (recorded 2025-05-29, 431 days ago)]
The date already existed in storage and was being dropped at the snippet layer, so this is plumbing rather than new data collection. Zone-less SQLite timestamps are normalised to UTC — read as local, a ten-minute-old record parsed hours into the future and its age was suppressed entirely, meaning the feature silently did nothing on the freshest memories. An absent or unparseable date renders as nothing rather than defaulting to now; defaulting would make the oldest memories, the ones most likely to be stale, appear freshest.
tests/integration/grounding-staleness.test.tsruns the reviewer's own probe — seed a deliberately outdated note beside a contradicting fresh one and assert the model receives both, visibly dated. Anyone can run it.
Not solved, and not claimed:retrieval does not weight recency. A stale note shownbesidea fresh one is the easy case — the model sees both dates and can weigh them. The hard case is a stale note retrievedalone, because ranking is by keyword match and an old store returns old results; then the age label is the only defence and there is no fresher record to compare against. Tracked asTECH_DEBT.md#4.
The First Message Never Leaves Your Machine
Symptom-triggered skills — the rules that fire on "can't see X", "no rows", "the list is empty" — are meant to load on the turn an incident report arrives. They never did: every host template calledsession_bootstrapwith{}, so there was no prompt to match against.
Fixing that raised the question of where matching happens. It now happens locally. The 28 keyword rules are already public, so there was nothing a local match could not compute, andcallPortal()has nopromptparameter at all — the guarantee is structural, not a promise. The portal request carries the project and role only.
A matched rule now arrives ascontent, not as a name. Native hosts outside the skill-file mirror had no way to read a rule they were only told about, so the rule body is inlined into the startup display, bounded and sized against the real per-project budget.
An Explicitly Named Cloud Backend Fails Loud
SettingPRISM_STORAGE=synaluxor=supabasewith incomplete credentials used to downgrade silently to local SQLite. The switch was logged to stderr, which MCP hosts discard, so nothing surfaced it: sessions kept serving stale local context while the cloud held newer history, andcontext_sourcereadlocalrather than any kind of warning. A session could run that way for weeks.
Naming a backend outright is a strong statement of intent, so it now throws — naming the missing variables and thePRISM_STORAGE=localopt-out — instead of quietly splitting your session history.autois unchanged: it keeps its documentedsynalux > supabase > localdegradation, pinned by a test.
Upgrade note:if you explicitly setPRISM_STORAGE=synalux|supabaseand your credentials are incomplete, startup now fails with a named error instead of silently using local data. That error is the fix — set the missing variable, or choosePRISM_STORAGE=localdeliberately. Default (auto) configs are unaffected.
The throw is deliberately not treated as a recoverable startup fault: that path exists for transient errors (rate limits, 5xx, DNS), which may degrade behind a visible notice. A missing credential is a configuration fault and must not be papered over.
Also: the skill block is now budgeted by default rather than only on request, so a large skill payload cannot crowd out briefing and history.
Security release. Web Scholar scrapes article URLs that come from search-engine output, so the target is attacker-influenceable through SEO poisoning — and because what it scrapes is written into the memory corpus and passed to the configured LLM, a redirection to a local address meant reading an internal serviceandsending the result onward.
The host guard matched string prefixes instead of parsing the address, and six spellings of a local address got through:[::1](URL.hostnamekeeps the brackets),127.0.0.2(only.1was enumerated, not all of127.0.0.0/8),0.0.0.0,[::ffff:127.0.0.1],localhost.(a trailing dot defeated every suffix check at once), and[64:ff9b::7f00:1](NAT64 embeds IPv4 in its low bits). Host classification now parses addresses and also covers CGNAT, benchmarking, multicast, reserved, and IPv6 unique-local and link-local ranges.
DNS rebinding is closed too. Every check read the URL string, so a hostname the attacker controls passed all of them and could still resolve to127.0.0.1. Targets are now resolved first, every returned address is validated, and the connection is pinned to those addresses so the name is never resolved a second time — which also shuts the window between the check and the connect.
Scrape failures no longer vanish into a barecatch {}, a run is bounded byPRISM_SCHOLAR_SCRAPE_BUDGET_MS(default 60s) instead of stalling on a raised article count, and responses are capped at 8 MiB.
This is reachable only when scholar actually runs —scholar_research, or the background loop underPRISM_SCHOLAR_ENABLED=true— and when the attacker also controls DNS or a search result. Upgrade if you use Web Scholar.
prism browsercould not fail a test.eval 1 === 2returnedstatus: okwith exit code 0, a page serving HTTP 500 reportedstatus: ok, and console errors and uncaught page exceptions were discarded entirely. This release adds assertions —assert-text,assert-visible,assert-count,assert-url,assert-title,assert-eval,assert-no-page-errors— that returnstatus: failedand a non-zero exit.opennow reportshttp_statusand fails on 400 or higher, screenshots are validated rather than assumed, andevalreturns native JSON with its type instead of a Pythonrepr.
The fingerprint layer had never been applied: a wrong keyword argument made the stealth library throw on every launch — 1,139 failures and 0 successes since April — while the runner reported it as active. It is fixed, and a layer that cannot be applied now fails loudly. The headless build no longer advertises itself throughnavigator.userAgentDataor theSec-CH-UAheader, and a patch that corruptedObject.getOwnPropertyDescriptoron every page under test has been removed. These remain best-effort test aids, not a guarantee against bot detection.
New for test runs:--ephemeral-profileand--storage-statefor hermetic authenticated flows,pages/switch-pageso OAuth popups are reachable,--fail-fast,--fast,--trace/--video/--har, andprofiles --prune-older-thanfor profile maintenance.
Prism now remembers that a conversation successfully loaded its project context when the MCP server restarts or another Prism process handles the next request.session_save_ledgerandsession_save_handoffno longer fail with a falsecontext_not_loadederror in that flow.
The recovery remains fail-closed: authorization is limited to the exact project and conversation, expires with the existing context window, and stores no plaintext conversation identifier. Cross-project, forged, malformed, expired, or future-dated receipts are still rejected. The release also updates PostCSS to the patched 8.5.23 release.
session_search_memoryon the portal tier (Synalux-backed installs) now fuses semantic similarity with exact-term lexical matching via weighted reciprocal-rank fusion. Measured on blind probes against a real 8.5k-entry corpus: fused retrieval wasnever worsethan semantic alone at top-5, and exact identifiers — TPNs, function names, error strings — now rescue queries that embedding similarity blurs. Results say how they were found —hybrid retrievalheaders, per-hitsem#/lex#arms — and a lexical-only rescue is labelledexact-term matchinstead of pretending to a similarity score. Local SQLite installs keep pure vector search; hybrid needs the portal's lexical index.
Safer Configuration Updates Across Every Agent
prism connectnow reads Claude, Cursor, Gemini, and Codex configuration through a single verified file snapshot, preventing another process from swapping a file between Prism's safety check and its read. Supported symlinked dotfiles still work, while dangling or planted symlinks fail loudly instead of being followed or overwritten. This release also carries the patched dependencies and cross-platform release checks introduced in v20.2.5.
Cloud fallback is now documented consistently as Gemini 3.6 Flash. Plan ceilings govern automaticprism_inferrouting; direct use of any downloaded model through local Ollama remains free on every tier.
Reliable Session Memory That Shows Work, Not Greetings
Greeting-only assistant replies are skipped before ledger writes. Existing greeting rows are filtered at read time across native startup, MCP context, andprism load --json, while entries containing decisions, TODOs, changed files, or non-session events remain visible. Historical rows are not destructively deleted. If Synalux has a transient startup failure, Prism displays one bounded local last-good snapshot and clearly labels it; permanent authorization or validation failures still fail loud, and later writes remain cloud-routed.
One Local-First Workflow Across Every Agent
prism connectnow installs one orchestration contract for Claude Code, Claude Desktop, Cursor, Gemini CLI, and Codex. Bounded delegated work goes tosession_task_routeand the localprism_inferworker first; routine work must not create background host agents. Local workers can receive the active project's dashboard-configured quick, standard, or deep memory and select a RAM-safe 2B/4B/9B/27B model at call time. The router forwards complexity but does not choose the model;prism_inferowns the final decision using memory and context fit, installed models, live RAM, entitlements, and explicit caller overrides.
Codex and Gemini native agent fan-out are disabled during connect. Codex keeps a two-thread, one-level Terra/low fallback profile if the developer explicitly re-enables native agents later. Claude Code keeps native agents as a last-resort path but pins their model to Sonnet. Cursor and Claude Desktop do not expose a supported global subagent-policy file, so they receive the identical workflow through Prism's MCP server instructions.prism_infersafety boundaries and the host's final verification responsibility are unchanged.
Subscription-Tier Skills Arrive Before the First Host Launch
prism connectnow downloads the authoritative Synalux skill manifest and materializes entitled packages in the native~/.agents/skillsdirectory before the command exits. Codex therefore sees the current skillset on its first launch instead of requiring a second restart. Prism rechecks the same snapshot at MCP startup, session load, and every five minutes—without host lifecycle hooks.
On the first user turn, Prism's native skill, MCP metadata, and managed host instructions request onesession_bootstrap({})call. Prism then uses the dashboard's developer name, Auto-Load Projects, and quick, standard, or deep setting. The response stays focused on greeting and session state because tier skills are already present in the host's native skill directory.
Hook-free MCP can provide and prioritize that ready-to-display block, but the host model still owns the final assistant message and may summarize it. Prism does not claim a deterministic verbatim greeting on third-party chat surfaces; that would require a host lifecycle hook, launcher, extension, or Prism-owned panel. Context loading itself remains complete even when a host shortens the visible reply.
When upgrading an older Claude Code installation,prism connectremoves only the exact Prism-owned startup, skill-sync, handoff, and drift hook actions from the legacy bootstrap. It also removes the recognized legacy Prism startup sections from~/CLAUDE.md, preserves every other instruction, and installs a small ownership-marked native block that selectssession_bootstrap({})on the first turn. User hooks, custom instruction sections, and near matches remain untouched; native skills and server-side reminders preserve those Prism features without host lifecycle hooks. Because hosts expose no native session-end callback, handoff at shutdown is instruction-driven rather than a guaranteed lifecycle event.
After Claude Code's native user registration succeeds, the same default or--refreshcommand checks the nearest.mcp.jsonfrom the current directory through the home directory. It removes only the exact legacyprism-mcpentry{ "command": "npx", "args": ["-y", "prism-mcp-server"] }that would otherwise shadow the user registration. Custom Prism entries and their additional fields, plus unrelated servers, are preserved; malformed files fail loud without changes.--dry-runreports the recognized migration without changing the file.
prism connectnow carries an explicitPRISM_STORAGE=auto|local|synalux|supabaseinto every managed host registration and rejects invalid values before changing a config file. Inauto, a portal-confirmed free tier uses local SQLite, while Standard, Advanced, and Enterprise use Synalux cloud memory. If entitlement resolution is unavailable, Prism fails closed instead of splitting history across backends. Storage remains independent of local-first model routing.
One Command Connects Every Supported Host
Install Prism globally and runprism connect. It detects Claude Code, Claude Desktop on macOS, Windows, and Linux (beta), Cursor, Gemini CLI, and Codex, then safely registers the server from the installed package. Existing custom entries are untouched;--dry-runpreviews changes and--refreshupdates only Prism-managed entries.
Every Inference Outcome Is Now Observable
prism_infergains a failure contract: passescalation: "report"and every call returns a structuredgate_outcome—success,degraded(gate-failed output served anyway, explicitly flagged), orrefused(typed, with reason, instead of a thrown error). Degraded output can no longer serve silently.
Prompts 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 distinctUNCERTAIN_LENGTHaudit marker. Clinical/reserved handling is unchanged (and its keyword floor got stronger).
Tier 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 visiblectx_insufficientreason; if nothing fits, you get the full prompt on cloud or a loud error — never an answer computed from a silently-clipped prompt.
Know Which Plan You're Actually Running Under
Entitlements carry asourcefield:portal(real),unconfigured(free by design), orfallback_free(portal unreachable — free limits ASSUMED). Passstrict_entitlements: trueto fail loud instead of running degraded.
Theverify_behaviortool crashed on every call (-32602 expected object, received string) — the handler returned a bare string instead of an MCPCallToolResultobject. 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.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.
