Cognitive memory for AI agents — FSRS-6 spaced repetition, 29 brain modules, 3D dashboard, single 22MB Rust binary. MCP server for Claude, Cursor, VS Code, Xcode, JetBrains. https://github.com/samvallad33/vestige
Find a file
Sam Valladares 6a807698ef
v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44)
* docs: anti-hedging banner + master state-and-plan + UI roadmap

Project-level CLAUDE.md line 1 is now the anti-hedging banner referencing
the global rule at /Users/entity002/CLAUDE.md. When Sam commits to an
execution path (content cadence, shipping velocity, outreach, launch),
forecasts compute as if the commitment is already met — no discounting by
execution probability.

VESTIGE_STATE_AND_PLAN.md (1135 lines, 14 parts): single-page reference
any AI agent can read to plan the next phase without re-reading the repo.
Covers current state of every crate, the 24 MCP tools, the 19 WebSocket
event types, the 8 IDE integrations, and v2.1 through v3.0 roadmap.

UI_ROADMAP_v2.1_v2.2.md: compiled UI-gap analysis from 4 parallel research
agents (April 19). 10 critical UI gaps + 2026 bleeding-edge patterns +
unclaimed territory (menu bar widget, voice-first, AR/VR, time-scrubber).

* feat(v2.2-pulse): InsightToast + multi-process STORAGE docs

Two independent ship items landing together on the v2.2 branch ahead of
the Tuesday launch — a new UI surface that makes Vestige's cognitive
events visible in real time, and honest documentation of the multi-process
safety story that underpins the Stigmergic Swarm narrative.

**InsightToast** (apps/dashboard/src/lib/components/InsightToast.svelte,
apps/dashboard/src/lib/stores/toast.ts):
  The dashboard already had a working WebSocket event stream on
  ws://localhost:3927/ws that broadcast every cognitive event (dream
  completions, consolidation sweeps, memory promotions/demotions, active-
  forgetting suppression and Rac1 cascades, bridge discoveries). None of
  that was surfaced to a user looking at anything other than the raw feed
  view. InsightToast subscribes to the existing eventFeed derived store,
  filters the spammy lifecycle events (Heartbeat, SearchPerformed,
  RetentionDecayed, ActivationSpread, ImportanceScored, MemoryCreated),
  and translates the narrative events into ephemeral toasts with a
  bioluminescent colored accent matching EVENT_TYPE_COLORS.

  Design notes:
  - Rate-limited ConnectionDiscovered at 1.5s intervals (dreams emit many).
  - Max 4 visible toasts, auto-dismiss at 4.5-7s depending on event weight.
  - Click or Enter/Space to dismiss early.
  - Bottom-right on desktop, top-banner on mobile.
  - Reduced-motion honored via prefers-reduced-motion.
  - Zero new websocket subscriptions — everything piggybacks on the
    existing derived store.

  Also added a "Preview Pulse" button to Settings -> Cognitive Operations
  that fires a synthetic sequence of four toasts (DreamCompleted,
  ConnectionDiscovered, MemorySuppressed, ConsolidationCompleted) so
  the animation is demoable without waiting for real cognitive activity.

**Multi-Process Safety section in docs/STORAGE.md**:
  Grounds the Stigmergic Swarm story with concrete tables of what the
  current WAL + 5s busy_timeout configuration actually supports vs what
  remains experimental. Key honest points:
  - Shared --data-dir + ONE vestige-mcp + N clients is the shipping
    pattern for multi-agent coordination.
  - Two vestige-mcp processes writing the same file is experimental —
    documented with the lsof + pkill recovery path.
  - Roadmap lists the three items that would promote it to "supported":
    advisory file lock, retry-with-jitter on SQLITE_BUSY, and a
    concurrent-writer load test.

Build + typecheck:
- npm run check: 0 errors, 0 warnings across 583 files
- npm run build: clean static build, adapter-static succeeds

* feat(v2.3-terrarium): Memory Birth Ritual + event pipeline fix

v2.3 "Terrarium" headline feature. When a MemoryCreated event arrives, a
glowing orb materialises in the cosmic center (camera-relative z=-40),
gestates for ~800ms growing from a tiny spark into a full orb, then arcs
along a dynamic quadratic Bezier curve to the live position of the real
node, and on arrival hands off to the existing RainbowBurst + Shockwave +
RippleWave cascade. The target position is re-resolved every frame so
the force simulation can move the destination during flight without the
orb losing its mark.

**New primitive — EffectManager.createBirthOrb()** (effects.ts):
  Accepts a camera, a color, a live target-position getter, and an
  arrival callback. Owns a sprite pair (outer halo + inner bright core),
  both depthTest:false with renderOrder 999/1000 so the orb is always
  visible through the starfield and the graph.
  - Gestation phase: easeOutCubic growth + sinusoidal pulse, halo tints
    from neutral to event color as the ritual charges.
  - Flight phase: QuadraticBezierCurve3 with control point at midpoint
    raised on Y by 30 + 15% of orb-to-target distance (shooting-star
    arc). Sampled with easeInOutQuad. Orb shrinks ~35% approaching target.
  - Arrival: fires onArrive callback once, then fades out over 8 frames
    while expanding slightly (energy dispersal).
  - Caller's onArrive triggers the burst cascade at arrivePos (NOT the
    original spawnPos — the force sim may have moved the target during
    the ritual, so we re-read nodeManager.positions on arrival).
  - Dispose path integrated with existing EffectManager.dispose().

**Event pipeline fix — Graph3D.processEvents()**:
  Previously tracked `processedEventCount` assuming APPEND order, but
  websocket.ts PREPENDS new events (index 0) and caps the array at
  MAX_EVENTS. Result: only the first MemoryCreated event after page
  load fired correctly; subsequent ones reprocessed the oldest entry.
  Fixed to walk from index 0 until hitting the last-processed event
  by reference identity — correct regardless of array direction or
  eviction pressure. Events are then processed oldest-first so causes
  precede effects. Found while wiring the v2.3 demo button; would have
  manifested as "first orb only" in production.

**Demo trigger** (Settings -> Birth Ritual Preview):
  Button that calls websocket.injectEvent() with a synthetic
  MemoryCreated event, cycling through node types (fact / concept /
  pattern / decision / person / place) to showcase the type-color
  mapping. Downstream consumers can't distinguish synthetic from real,
  so this drives the full ritual end-to-end. Intended for demo clip
  recording for the Wednesday launch.

**Test coverage:**
  - events.test.ts now tests the v2.3 birth ritual path: spawns 2+
    sprites in the scene immediately, and fires the full arrival
    cascade after driving the effects.update() loop past the ritual
    duration.
  - three-mock.ts extended with Vector3.addVectors, Vector3.applyQuaternion,
    Color.multiplyScalar, Quaternion, QuadraticBezierCurve3, Texture,
    and Object3D.quaternion/renderOrder so production code runs unaltered
    in tests.

Build + typecheck:
- npm run check: 0 errors, 0 warnings across 583 files
- npm test: 251/251 pass (net +0 from v2.2)
- npm run build: clean adapter-static output

The Sanhedrin Shatter (anti-birth ritual for hallucination veto) needs
server-side event plumbing and is deferred. Ship this as the Wednesday
visual mic-drop.

* fix(v2.3): 5 FATAL bugs + 4 god-tier upgrades from post-ship audit

Post-ship audit surfaced 6 FATALs and 4 upgrades. Shipping 5 of the 6 +
all 4 upgrades. FATAL 4 (VRAM hemorrhage from un-pooled label canvases
in createTextSprite) is pre-existing, not from this session, and scoped
separately for a proper texture-pool refactor.

**FATAL 1 — Toast Silent Lobotomy** (stores/toast.ts)
Subscriber tracked events[0] only. When Svelte batched multiple events
in one update tick (swarm firing DreamCompleted + ConnectionDiscovered
within the same millisecond), every event but the newest got silently
dropped. Fixed to walk from index 0 until hitting lastSeen — same
pattern as Graph3D.processEvents. Processes oldest-first to preserve
narrative order.

**FATAL 2 — Premature Birth** (graph/nodes.ts + graph/events.ts)
Orb flight is 138 frames; materialization was 30 frames. Node popped
fully grown ~100 frames before orb arrived — cheap UI glitch instead
of a biological birth. Added `addNode(..., { isBirthRitual: true })`
option that reserves the physics slot but hides mesh/glow/label and
skips the materializing queue. New `igniteNode(id)` flips visibility
and enqueues materialization. events.ts onArrive now calls igniteNode
at the exact docking moment, so the elastic spring-up peaks on impact.

**FATAL 3 — 120Hz ProMotion Time-Bomb** (components/Graph3D.svelte)
All physics + effect counters are frame-based. On a 120Hz display every
ritual ran at 2x speed. Added a `lastTime`-based governor in animate()
that early-returns if dt < 16ms, clamping effective rate to ~60fps.
`- (dt % 16)` carry avoids long-term drift. Zero API changes; tonight's
fast fix until physics is rewritten to use dt.

**FATAL 5 — Bezier GC Panic** (graph/effects.ts birth-orb update)
Flight phase allocated a new Vector3 (control point) and a new
QuadraticBezierCurve3 every frame per orb. With 3 orbs in flight that's
360 objects/sec for the GC to collect. Rewrote as inline algebraic
evaluation — zero allocations per frame, identical curve.

**FATAL 6 — Phantom Shockwave** (graph/events.ts)
A 166ms setTimeout fired the 2nd shockwave. If the user navigated
away during that window the scene was disposed, the timer still
fired, and .add() on a dead scene threw unhandled rejection. Dropped
the setTimeout entirely; both shockwaves fire immediately in onArrive
with different scales/colors for the same layered-crash feel.

**UPGRADE 1 — Sanhedrin Shatter** (graph/effects.ts birth-orb update)
If getTargetPos() returns undefined AFTER gestation (target node was
deleted mid-ritual — Stop hook sniping a hallucination), the orb
turns blood-red, triggers a violent implosion in place, and skips
the arrival cascade. Cognitive immune system made visible.

**UPGRADE 2 — Newton's Cradle** (graph/events.ts onArrive)
On docking the target mesh's scale gets bumped 1.8×, so the elastic
materialization + force-sim springs physically recoil instead of the
orb landing silently. The graph flinches when an idea is born into it.

**UPGRADE 3 — Hover Panic** (stores/toast.ts + InsightToast.svelte)
Paused dwell timer on mouseenter/focus, resume on mouseleave/blur.
Stored remaining ms at pause so resume schedules a correctly-sized
timer. CSS pairs via `animation-play-state: paused` on the progress
bar. A toast the user is reading no longer dismisses mid-sentence.

**UPGRADE 4 — Event Horizon Guard** (components/Graph3D.svelte)
If >MAX_EVENTS (200) events arrive in one tick, lastProcessedEvent
falls off the end of the array and the walk consumes ALL 200 entries
as "fresh" — GPU meltdown from 200 simultaneous births. Detect the
overflow and drop the batch with a console.warn, advancing the
high-water mark so next frame is normal.

Build + test:
- npm run check: 0 errors, 0 warnings
- npm test: 251/251 pass
- npm run build: clean static build

* test(v2.3): full e2e + integration coverage for Pulse + Birth Ritual

Post-ship verification pass — five parallel write-agents produced 229 new
tests across vitest units, vitest integration, and Playwright browser e2e.
Net suite: 361 vitest pass (up from 251, +110) and 9/9 Playwright pass on
back-to-back runs.

**toast.test.ts (NEW, 661 lines, 42 tests)**
  Silent-lobotomy batch walk proven (multi-event tick processes ALL, not
  just newest, oldest-first ordering preserved). Hover-panic pause/resume
  with remaining-ms math. All 9 event type translations asserted, all 11
  noise types asserted silent. ConnectionDiscovered 1500ms throttle.
  MAX_VISIBLE=4 eviction. clear() tears down all timers. fireDemoSequence
  staggers 4 toasts at 800ms intervals. vi.useFakeTimers + vi.mock of
  eventFeed; vi.resetModules in beforeEach for module-singleton isolation.

**websocket.test.ts (NEW, 247 lines, 30 tests)**
  injectEvent adds to front, respects MAX_EVENTS=200 with FIFO eviction,
  triggers eventFeed emissions. All 6 derived stores (isConnected,
  heartbeat, memoryCount, avgRetention, suppressedCount, uptimeSeconds)
  verified — defaults, post-heartbeat values, clearEvents preserves
  lastHeartbeat. 13 formatUptime boundary cases (0/59/60/3599/3600/
  86399/86400 seconds + negative / NaN / ±Infinity).

**effects.test.ts (EXTENDED, +501 lines, +21 tests, 51 total)**
  createBirthOrb full lifecycle — sprite count (halo + core), cosmic
  center via camera.quaternion, gestation phase (position lock, opacity
  rise, scale easing, color tint), flight Bezier arc above linear
  midpoint at t=0.5, dynamic mid-flight target redirect. onArrive fires
  exactly once at frame 139. Post-arrival fade + disposal cleans scene
  children. Sanhedrin Shatter: target goes undefined mid-flight →
  onArrive NEVER called, implosion spawned, halo blood-red, eventual
  cleanup. dispose() cleans active orbs. Multiple simultaneous orbs.
  Custom gestation/flight frame opts honored. Zero-alloc invariant
  smoke test (6 orbs × 150 frames, no leaks).

**nodes.test.ts (EXTENDED, +197 lines, +10 tests, 42 total)**
  addNode({isBirthRitual:true}) hides mesh/glow/label immediately,
  stamps birthRitualPending sentinel with correct totalFrames +
  targetScale, does NOT enqueue materialization. igniteNode flips
  visibility + enqueues materialization. Idempotent — second call
  no-op. Non-ritual nodes unaffected. Unknown id is safe no-op.
  Position stored in positions map while invisible (force sim still
  sees it). removeNode + late igniteNode is safe.

**events.test.ts (EXTENDED, +268 lines, +7 tests, 55 total)**
  MemoryCreated → mesh hidden immediately, 2 birth-orb sprites added,
  ZERO RingGeometry meshes and ZERO Points particles at spawn. Full
  ritual drive → onArrive fires, node visible + materializing, sentinel
  cleared. Newton's Cradle: target mesh scale exactly 0.001 * 1.8 right
  after arrival. Dual shockwave: exactly 2 Ring meshes added. Re-read
  live position on arrival — force-sim motion during ritual → burst
  lands at the NEW position. Sanhedrin abort path → rainbow burst,
  shockwave, ripple wave are NEVER called (vi.spyOn).

**three-mock.ts (EXTENDED)**
  Added Color.setRGB — production Three.js has it, the Sanhedrin-
  Shatter path in effects.ts uses it. Two write-agents independently
  monkey-patched the mock inline; consolidated as a 5-line mock
  addition so tests stay clean.

**e2e/pulse-toast.spec.ts (NEW, 235 lines, 6 Playwright tests)**
  Navigate /dashboard/settings → click Preview Pulse → assert first
  toast appears within 500ms → assert >= 2 toasts visible at peak.
  Click-to-dismiss removes clicked toast (matched by aria-label).
  Hover survives >8s past the 5.5s dwell. Keyboard Enter dismisses
  focused toast. CSS animation-play-state:paused on .toast-progress-
  fill while hovered, running on mouseleave. Screenshots attached to
  HTML report. Zero backend dependency (fireDemoSequence is purely
  client-side).

**e2e/birth-ritual.spec.ts (NEW, 199 lines, 3 Playwright tests)**
  Canvas mounts on /dashboard/graph (gracefully test.fixme if MCP
  backend absent). Settings button injection + SPA route to /graph
  → screenshot timeline at t=0/500/1200/2000/2400/3000ms attached
  to HTML report. pageerror + console-error listeners catch any
  crash (would re-surface FATAL 6 if reintroduced). Three back-to-
  back births — no errors, canvas still dispatches clicks.

Run commands:
  cd apps/dashboard && npm test           # 361/361 pass, ~600ms
  cd apps/dashboard && npx playwright test # 9/9 pass, ~25s

Typecheck: 0 errors, 0 warnings. Build: clean adapter-static.

* fix(graph): default /api/graph to newest-memory center, add sort param

memory_timeline PR #37 exposed the same class of bug in the graph
endpoint: the dashboard Graph page (and the /api/graph endpoint it
hits) defaulted to centering on the most-connected memory, ran BFS at
depth 3, and capped the subgraph at 150 nodes. On a mature corpus this
clustered the visualization around a historical hotspot and hid freshly
ingested memories that hadn't accumulated edges yet. User-visible
symptom: TimeSlider on /graph showing "Feb 21 → Mar 1 2026" when the
database actually contains memories through today (Apr 20).

**Backend (`crates/vestige-mcp/src/dashboard/handlers.rs`):**
- `GraphParams` gains `sort: Option<String>` (accepted: "recent" |
  "connected", unknown falls back to "recent").
- New internal `GraphSort` enum + case-insensitive `parse()`.
- Extracted `default_center_id(storage, sort)` so handler logic and
  tests share the same branching. Recent path picks `get_all_nodes(1,
  0)` (ORDER BY created_at DESC). Connected path picks
  `get_most_connected_memory`, degrading gracefully to recent if the
  DB has no edges yet.
- Default behaviour flipped from "connected" to "recent" — matches
  user expectation of "show me my recent stuff".

**Dashboard (`apps/dashboard`):**
- `api.graph()` accepts `sort?: 'recent' | 'connected'` with JSDoc
  explaining the rationale.
- `/graph/+page.svelte` passes `sort: 'recent'` when no query or
  center_id is active. Query / center_id paths unchanged — they
  already carry their own centering intent.

**Tests:** 6 new unit tests in `handlers::tests`:
- `graph_sort_parse_defaults_to_recent` (None, empty, garbage,
  "recent", "Recent", "RECENT")
- `graph_sort_parse_accepts_connected_case_insensitive`
- `default_center_id_recent_returns_newest_node` — ingest 3 nodes,
  assert newest is picked
- `default_center_id_connected_prefers_hub_over_newest` — wire a hub
  node with 3 spokes, then ingest a newer "lonely" node; assert the
  hub wins in Connected mode even though it's older
- `default_center_id_connected_falls_back_to_recent_when_no_edges`
  — fresh DB with no connections still returns newest, not 404
- `default_center_id_returns_not_found_on_empty_db` — both modes
  return 404 cleanly on empty storage

Build + test:
- cargo test -p vestige-mcp --lib handlers:: → 6/6 pass
- cargo test --workspace --lib → 830/830 pass, 0 failed
- cargo clippy -p vestige-core -p vestige-mcp --lib -- -D warnings →
  clean
- npm run check → 0 errors, 0 warnings
- npm test → 361/361 pass

Binary already installed at ~/.local/bin/vestige-mcp (copied from
cargo build --release -p vestige-mcp). New Claude Desktop / Code
sessions will pick it up automatically when they respawn their MCP
subprocess. The dashboard HTTP server on port 3927 needs a manual
relaunch from a terminal with the usual pattern:

    nohup bash -c 'tail -f /dev/null | \
        VESTIGE_DASHBOARD_ENABLED=true ~/.local/bin/vestige-mcp' \
        > /tmp/vestige-mcp.log 2>&1 & disown

* feat(v2.4): UI expansion — 8 new surfaces exposing the cognitive engine

Sam asked: "Build EVERY SINGLE MISSING UI PIECE." 10 parallel agents shipped
10 new viewports over the existing Rust backend, then 11 audit agents
line-by-line reviewed each one, extracted pure-logic helpers, fixed ~30
bugs, and shipped 549 new unit tests. Everything wired through the layout
with single-key shortcuts and a live theme toggle.

**Eight new routes**
- `/reasoning`  — Reasoning Theater: Cmd+K ask palette → animated 8-stage
  deep_reference pipeline + FSRS-trust-scored evidence cards +
  contradiction arcs rendered as live SVG between evidence nodes
- `/duplicates` — threshold-driven cluster detector with winner selection,
  Merge/Review/Dismiss actions, debounced slider
- `/dreams`     — Dream Cinema: trigger dream + scrubbable 5-stage replay
  (Replay → Cross-reference → Strengthen → Prune → Transfer) + insight
  cards with novelty glow
- `/schedule`   — FSRS Review Calendar: 6×7 grid with urgency color
  bands (overdue/today/week/future), retention sparkline, expand-day list
- `/importance` — 4-channel radar (Novelty/Arousal/Reward/Attention) with
  composite score + top-important list
- `/activation` — live spreading-activation view: search → SVG concentric
  rings with decay animation + live-mode event feed
- `/contradictions` — 2D cosmic constellation of conflicting memories,
  arcs colored by severity, tooltips with previews
- `/patterns`   — cross-project pattern transfer heatmap with category
  filters, top-transferred sidebar

**Three layout additions**
- `AmbientAwarenessStrip` — slim top band with retention vitals, at-risk
  count, active intentions, recent dream, activity sparkline, dreaming
  indicator, Sanhedrin-watch flash. Pure `$derived` over existing stores.
- `ThemeToggle` — dark/light/auto cycle with matchMedia listener,
  localStorage persistence, SSR-safe, reduced-motion-aware. Rendered in
  sidebar footer next to the connection dot.
- `MemoryAuditTrail` — per-memory Sources panel integrated as a
  Content/Audit tab into the existing /memories expansion.

**Pure-logic helper modules extracted (for testability + reuse)**
  reasoning-helpers, duplicates-helpers, dream-helpers, schedule-helpers,
  audit-trail-helpers, awareness-helpers, contradiction-helpers,
  activation-helpers, patterns-helpers, importance-helpers.

**Bugs fixed during audit (not exhaustive)**
- Trust-color inconsistency between EvidenceCard and the page confidence
  ring (0.75 boundary split emerald vs amber)
- `new Date('garbage').toLocaleDateString()` returned literal "Invalid Date"
  in 3 components — all now return em-dash or raw string
- NaN propagation in `Math.max(0, Math.min(1, NaN))` across clamps
- Off-by-one PRNG in audit-trail seeded mock (seed === UINT32_MAX yielded
  rand() === 1.0 → index out of bounds)
- Duplicates dismissals keyed by array index broke on re-fetch; now keyed
  by sorted cluster member IDs with stale-dismissal pruning
- Empty-cluster crash in DuplicateCluster.pickWinner
- Undefined tags crash in DuplicateCluster.safeTags
- Debounce timer leak in threshold slider (missing onDestroy cleanup)
- Schedule day-vs-hour granularity mismatch between calendar cell and
  sidebar list ("today" in one, "in 1d" in the other)
- Schedule 500-memory hard cap silently truncated; bumped to 2000 + banner
- Schedule DST boundary bug in daysBetween (wall-clock math vs
  startOfDay-normalized)
- Dream stage clamp now handles NaN/Infinity/floats
- Dream double-click debounce via `if (dreaming) return`
- Theme setTheme runtime validation; initTheme idempotence (listener +
  style-element dedup on repeat calls)
- ContradictionArcs node radius unclamped (trust < 0 or > 1 rendered
  invalid sizes); tooltip position clamp (could push off-canvas)
- ContradictionArcs $state closure capture (width/height weren't reactive
  in the derived layout block)
- Activation route was MISSING from the repo — audit agent created it
  with identity-based event filtering and proper RAF cleanup
- Layout: ThemeToggle was imported but never rendered — now in sidebar
  footer; sidebar overflow-y-auto added for the 16-entry nav

**Tests — 549 new, 910 total passing (0 failures)**
  ReasoningChain     42 | EvidenceCard       50
  DuplicateCluster   64 | DreamStageReplay   19
  DreamInsightCard   43 | FSRSCalendar       32
  MemoryAuditTrail   45 | AmbientAwareness   60
  theme (store)      31 | ContradictionArcs  43
  ActivationNetwork  54 | PatternTransfer    31
  ImportanceRadar    35 | + existing 361 tests still green

**Gates passed**
- `npm run check`:  0 errors, 0 warnings across 623 files
- `npm test`:       910/910 passing, 22 test files
- `npm run build`:  clean adapter-static output

**Layout wiring**
- Nav array expanded 8 → 16 entries (existing 8 + 8 new routes)
- Single-key shortcuts added: R/A/D/C/P/U/X/N (no conflicts with
  existing G/M/T/F/E/I/S/,)
- Cmd+K palette search works across all 16
- Mobile nav = top 5 (Graph, Reasoning, Memories, Timeline, Feed)
- AmbientAwarenessStrip mounted as first child of <main>
- ThemeToggle rendered in sidebar footer (was imported-but-unmounted)
- Theme initTheme() + teardown wired into onMount cleanup chain

Net branch delta: 47 files changed, +13,756 insertions, -6 deletions

* chore(release): v2.0.8 "Pulse"

Bundled release: Reasoning Theater wired to the 8-stage deep_reference
cognitive pipeline, Pulse InsightToast, Memory Birth Ritual (v2.3
Terrarium), 7 new dashboard surfaces (/duplicates, /dreams, /schedule,
/importance, /activation, /contradictions, /patterns), 3D graph
brightness system with auto distance-compensation + user slider, and
contradiction-detection + primary-selection hardening in the
cross_reference tool. Intel Mac (x86_64-apple-darwin) also flows through
to the release matrix from PR #43.

Added:
- POST /api/deep_reference — HTTP surface for the 8-stage pipeline
- DeepReferenceCompleted WebSocket event (primary + supporting +
  contradicting memory IDs for downstream graph animation)
- /reasoning route, full UI + Cmd+K Ask palette
- 7 new dashboard surfaces exposing the cognitive engine
- Graph brightness slider + localStorage persistence + distance-based
  emissive compensation so nodes don't disappear into fog at zoom-out

Fixed:
- Contradiction-detection false positives: adjacent-domain memories no
  longer flagged as conflicts (NEGATION_PAIRS wildcards removed,
  shared-words floor 2 → 4, topic-sim floor 0.15 → 0.55, STAGE 5
  overlap floor 0.15 → 0.4)
- Primary-memory selection: unified composite 0.5 × relevance + 0.2 ×
  trust + 0.3 × term_presence with hard topic-term filter, closing the
  class of bug where off-topic high-trust memories won queries about
  specific subjects
- Graph default-load fallback from sort=recent to sort=connected when
  the newest memory is isolated, both backend and client

Changed:
- Reasoning page information hierarchy: chain renders first as hero,
  confidence meter + Primary Source citation footer below
- Cargo feature split: embeddings code-only + ort-download | ort-dynamic
  backends; defaults preserve identical behavior for existing consumers
- CI release-build now gates PRs too so multi-platform regressions
  surface pre-merge
2026-04-23 02:21:11 -05:00
.github fix(#41): restore Intel Mac build via ort-dynamic + Homebrew ONNX Runtime (#43) 2026-04-23 02:03:45 -05:00
apps/dashboard v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
crates v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
docs v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
packages chore(release): v2.0.7 "Visible" 2026-04-19 20:37:11 -05:00
scripts feat: Vestige v1.9.1 AUTONOMIC — self-regulating memory with graph visualization 2026-02-21 02:02:06 -06:00
tests/e2e feat(v2.0.5): Intentional Amnesia — active forgetting via top-down inhibitory control 2026-04-14 17:30:30 -05:00
.agentaudit-report.json Add AgentAudit security report: safe (0 findings) 2026-02-13 10:55:37 +01:00
.gitignore fix: remove vestige-agent from workspace (not shipped), improve reasoning chain output 2026-04-09 17:06:24 -05:00
Cargo.lock v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
Cargo.toml v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
CHANGELOG.md v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
CLAUDE.md v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) 2026-04-23 02:21:11 -05:00
CLAUDE.md.template chore: add CLAUDE.md template for Vestige integration 2026-02-12 04:33:53 -06:00
CODE_OF_CONDUCT.md Initial commit: Vestige v1.0.0 - Cognitive memory MCP server 2026-01-25 01:31:03 -06:00
CONTRIBUTING.md docs: tool-count reconciliation (continued): 23 -> 24 in 3 stragglers 2026-04-19 20:28:11 -05:00
demo.sh fix: accurate science claims, security docs, remove hardcoded path 2026-01-25 20:29:37 -06:00
LICENSE chore: license AGPL-3.0, zero clippy warnings, CHANGELOG through v1.6.0 2026-02-19 03:00:39 -06:00
package.json fix: v2.0.1 release — fix broken installs, CI, security, and docs 2026-03-01 20:20:14 -06:00
pnpm-lock.yaml fix: resolve CI failures — clippy lint + lockfile sync 2026-03-03 14:20:37 -06:00
pnpm-workspace.yaml Initial commit: Vestige v1.0.0 - Cognitive memory MCP server 2026-01-25 01:31:03 -06:00
README.md fix(#41): restore Intel Mac build via ort-dynamic + Homebrew ONNX Runtime (#43) 2026-04-23 02:03:45 -05:00
SECURITY.md feat: v2.0.4 "Deep Reference" — cognitive reasoning engine + 10 bug fixes 2026-04-09 16:15:26 -05:00

Vestige

The cognitive engine that gives AI agents a brain.

GitHub stars Release Tests License MCP Compatible

Your Agent forgets everything between sessions. Vestige fixes that.

Built on 130 years of memory research — FSRS-6 spaced repetition, prediction error gating, synaptic tagging, spreading activation, memory dreaming — all running in a single Rust binary with a 3D neural visualization dashboard. 100% local. Zero cloud.

Quick Start | Dashboard | How It Works | Tools | Docs


What's New in v2.0.6 "Composer"

v2.0.6 is a polish release that makes the existing cognitive stack finally feel alive in the dashboard and stays out of your way on the prompt side.

  • Six live graph reactions, not oneMemorySuppressed, MemoryUnsuppressed, Rac1CascadeSwept, Connected, ConsolidationStarted, and ImportanceScored now light the 3D graph in real time. v2.0.5 shipped suppress but the graph was silent when you called it; consolidation and importance scoring have been silent since v2.0.0. No longer.
  • Intentions page actually works — fixes a long-standing bug where every intention rendered as "normal priority" (type/schema drift between backend and frontend) and context/time triggers surfaced as raw JSON.
  • Opt-in composition mandate — the new MCP instructions string stays minimal by default. Opt in to the full Composing / Never-composed / Recommendation composition protocol with VESTIGE_SYSTEM_PROMPT_MODE=full when you want it, and nothing is imposed on your sessions when you don't.

What's New in v2.0.5 "Intentional Amnesia"

The first shipped AI memory system with top-down inhibitory control over retrieval. Other systems implement passive decay — memories fade if you don't touch them. Vestige v2.0.5 also implements active suppression: the new suppress tool compounds a retrieval penalty on every call (up to 80%), a background Rac1 worker fades co-activated neighbors over 72 hours, and the whole thing is reversible within a 24-hour labile window. Never deletes. The memory is inhibited, not erased.

Ebbinghaus 1885 models what happens to memories you don't touch. Anderson 2025 models what happens when you actively want to stop thinking about one. Every other AI memory system implements the first. Vestige is the first to ship the second.

Based on Anderson et al. 2025 (Suppression-Induced Forgetting, Nat Rev Neurosci) and Cervantes-Sandoval et al. 2020 (Rac1 synaptic cascade). 24 tools · 29 cognitive modules · 1,292 tests.

Earlier releases (v2.0 "Cognitive Leap" → v2.0.4 "Deep Reference")
  • v2.0.4 — deep_reference Tool — 8-stage cognitive reasoning pipeline with FSRS-6 trust scoring, intent classification, spreading activation, contradiction analysis, and pre-built reasoning chains. Token budgets raised 10K → 100K. CORS tightened.
  • v2.0 — 3D Memory Dashboard — SvelteKit + Three.js neural visualization with real-time WebSocket events, bloom post-processing, force-directed graph layout.
  • v2.0 — WebSocket Event Bus — Every cognitive operation broadcasts events: memory creation, search, dreaming, consolidation, retention decay.
  • v2.0 — HyDE Query Expansion — Template-based Hypothetical Document Embeddings for dramatically improved search quality on conceptual queries.
  • v2.0 — Nomic v2 MoE (experimental) — fastembed 5.11 with optional Nomic Embed Text v2 MoE (475M params, 8 experts) + Metal GPU acceleration.
  • v2.0 — Command PaletteCmd+K navigation, keyboard shortcuts, responsive mobile layout, PWA installable.
  • v2.0 — FSRS Decay Visualization — SVG retention curves with predicted decay at 1d/7d/30d.

Quick Start

# 1. Install (macOS Apple Silicon)
curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-aarch64-apple-darwin.tar.gz | tar -xz
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/

# 2. Connect to Claude Code
claude mcp add vestige vestige-mcp -s user

# Or connect to Codex
codex mcp add vestige -- /usr/local/bin/vestige-mcp

# 3. Test it
# "Remember that I prefer TypeScript over JavaScript"
# ...new session...
# "What are my coding preferences?"
# → "You prefer TypeScript over JavaScript."
Other platforms & install methods

Linux (x86_64):

curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-unknown-linux-gnu.tar.gz | tar -xz
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/

macOS (Intel): Microsoft is discontinuing x86_64 macOS prebuilts after ONNX Runtime v1.23.0, so Vestige's Intel Mac build links dynamically against a Homebrew-installed ONNX Runtime via the ort-dynamic feature. Install with:

brew install onnxruntime
curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-apple-darwin.tar.gz | tar -xz
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/
echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc
source ~/.zshrc
claude mcp add vestige vestige-mcp -s user

Full Intel Mac guide (build-from-source + troubleshooting): docs/INSTALL-INTEL-MAC.md.

Windows: Prebuilt binaries ship but usearch 2.24.0 hit an MSVC compile break (usearch#746); we've pinned =2.23.0 until upstream fixes it. Source builds work with:

git clone https://github.com/samvallad33/vestige && cd vestige
cargo build --release -p vestige-mcp

npm:

npm install -g vestige-mcp-server

Build from source (requires Rust 1.91+):

git clone https://github.com/samvallad33/vestige && cd vestige
cargo build --release -p vestige-mcp
# Optional: enable Metal GPU acceleration on Apple Silicon
cargo build --release -p vestige-mcp --features metal

Works Everywhere

Vestige speaks MCP — the universal protocol for AI tools. One brain, every IDE.

IDE Setup
Claude Code claude mcp add vestige vestige-mcp -s user
Codex Integration guide
Claude Desktop 2-min setup
Xcode 26.3 Integration guide
Cursor Integration guide
VS Code (Copilot) Integration guide
JetBrains Integration guide
Windsurf Integration guide

🧠 3D Memory Dashboard

Vestige v2.0 ships with a real-time 3D visualization of your AI's memory. Every memory is a glowing node in 3D space. Watch connections form, memories pulse when accessed, and the entire graph come alive during dream consolidation.

Features:

  • Force-directed 3D graph with 1000+ nodes at 60fps
  • Bloom post-processing for cinematic neural network aesthetic
  • Real-time WebSocket events: memories pulse on access, burst on creation, fade on decay
  • Dream visualization: graph enters purple dream mode, replayed memories light up sequentially
  • FSRS retention curves: see predicted memory decay at 1d, 7d, 30d
  • Command palette (Cmd+K), keyboard shortcuts, responsive mobile layout
  • Installable as PWA for quick access

Tech: SvelteKit 2 + Svelte 5 + Three.js + Tailwind CSS 4 + WebSocket

The dashboard runs automatically at http://localhost:3927/dashboard when the MCP server starts.


Architecture

┌─────────────────────────────────────────────────────┐
│  SvelteKit Dashboard (apps/dashboard)                │
│  Three.js 3D Graph · WebGL + Bloom · Real-time WS   │
├─────────────────────────────────────────────────────┤
│  Axum HTTP + WebSocket Server (port 3927)            │
│  15 REST endpoints · WS event broadcast              │
├─────────────────────────────────────────────────────┤
│  MCP Server (stdio JSON-RPC)                         │
│  24 tools · 29 cognitive modules                     │
├─────────────────────────────────────────────────────┤
│  Cognitive Engine                                    │
│  ┌──────────┐ ┌──────────┐ ┌───────────────┐       │
│  │ FSRS-6   │ │ Spreading│ │ Prediction    │       │
│  │ Scheduler│ │ Activation│ │ Error Gating  │       │
│  └──────────┘ └──────────┘ └───────────────┘       │
│  ┌──────────┐ ┌──────────┐ ┌───────────────┐       │
│  │ Memory   │ │ Synaptic │ │ Hippocampal   │       │
│  │ Dreamer  │ │ Tagging  │ │ Index         │       │
│  └──────────┘ └──────────┘ └───────────────┘       │
├─────────────────────────────────────────────────────┤
│  Storage Layer                                       │
│  SQLite + FTS5 · USearch HNSW · Nomic Embed v1.5    │
│  Optional: Nomic v2 MoE · Qwen3 Reranker · Metal   │
└─────────────────────────────────────────────────────┘

Why Not Just Use RAG?

RAG is a dumb bucket. Vestige is an active organ.

RAG / Vector Store Vestige
Storage Store everything Prediction Error Gating — only stores what's surprising or new
Retrieval Nearest-neighbor 7-stage pipeline — HyDE expansion + reranking + spreading activation
Decay Nothing expires FSRS-6 — memories fade naturally, context stays lean
Forgetting (v2.0.5) Delete only suppress tool — compounding top-down inhibition, neighbor cascade, reversible 24h
Duplicates Manual dedup Self-healing — auto-merges "likes dark mode" + "prefers dark themes"
Importance All equal 4-channel scoring — novelty, arousal, reward, attention
Sleep No consolidation Memory dreaming — replays, connects, synthesizes insights
Health No visibility Retention dashboard — distributions, trends, recommendations
Visualization None 3D neural graph — real-time WebSocket-powered Three.js
Privacy Usually cloud 100% local — your data never leaves your machine

🔬 The Cognitive Science Stack

This isn't a key-value store with an embedding model bolted on. Vestige implements real neuroscience:

Prediction Error Gating — The hippocampal bouncer. When new information arrives, Vestige compares it against existing memories. Redundant? Merged. Contradictory? Superseded. Novel? Stored with high synaptic tag priority.

FSRS-6 Spaced Repetition — 21 parameters governing the mathematics of forgetting. Frequently-used memories stay strong. Unused memories naturally decay. Your context window stays clean.

HyDE Query Expansion (v2.0) — Template-based Hypothetical Document Embeddings. Expands queries into 3-5 semantic variants, embeds all variants, and searches with the centroid embedding for dramatically better recall on conceptual queries.

Synaptic Tagging — A memory that seemed trivial this morning can be retroactively tagged as critical tonight. Based on Frey & Morris, 1997.

Spreading Activation — Search for "auth bug" and find the related JWT library update from last week. Memories form a graph, not a flat list. Based on Collins & Loftus, 1975.

Dual-Strength Model — Every memory has storage strength (encoding quality) and retrieval strength (accessibility). A deeply stored memory can be temporarily hard to retrieve — just like real forgetting. Based on Bjork & Bjork, 1992.

Memory Dreaming — Like sleep consolidation. Replays recent memories to discover hidden connections, strengthen important patterns, and synthesize insights. Dream-discovered connections persist to a graph database. Based on the Active Dreaming Memory framework.

Waking SWR Tagging — Promoted memories get sharp-wave ripple tags for preferential replay during dream consolidation. 70/30 tagged-to-random ratio. Based on Buzsaki, 2015.

Autonomic Regulation — Self-regulating memory health. Auto-promotes frequently accessed memories. Auto-GCs low-retention memories. Consolidation triggers on 6h staleness or 2h active use.

Active Forgetting (v2.0.5) — Top-down inhibitory control via the suppress tool. Other memory systems implement passive decay — the Ebbinghaus 1885 "use it or lose it" curve, sometimes with trust-weighted strength factors. Vestige v2.0.5 also implements active top-down suppression: each suppress call compounds (Suppression-Induced Forgetting, Anderson 2025), a background Rac1 cascade worker fades co-activated neighbors across the connection graph (Cervantes-Sandoval & Davis 2020), and a 24-hour labile window allows reversal (Nader reconsolidation semantics on a pragmatic axis). The memory persists — it's inhibited, not erased. Explicitly distinct from Anderson 1994 retrieval-induced forgetting (bottom-up, passive competition during retrieval), which is a separate, older primitive that several other memory systems implement. Based on Anderson et al., 2025 and Cervantes-Sandoval et al., 2020. First shipped AI memory system with this primitive.

Full science documentation ->


🛠 24 MCP Tools

Context Packets

Tool What It Does
session_context One-call session init — replaces 5 calls with token-budgeted context, automation triggers, expandable IDs

Core Memory

Tool What It Does
search 7-stage cognitive search — HyDE expansion + keyword + semantic + reranking + temporal + competition + spreading activation
smart_ingest Intelligent storage with CREATE/UPDATE/SUPERSEDE via Prediction Error Gating. Batch mode for session-end saves
memory Get, delete, check state, promote (thumbs up), demote (thumbs down)
codebase Remember code patterns and architectural decisions per-project
intention Prospective memory — "remind me to X when Y happens"

Cognitive Engine

Tool What It Does
dream Memory consolidation — replays memories, discovers connections, synthesizes insights, persists graph
explore_connections Graph traversal — reasoning chains, associations, bridges between memories
predict Proactive retrieval — predicts what you'll need next based on context and activity

Autonomic

Tool What It Does
memory_health Retention dashboard — distribution, trends, recommendations
memory_graph Knowledge graph export — force-directed layout, up to 200 nodes

Scoring & Dedup

Tool What It Does
importance_score 4-channel neuroscience scoring (novelty, arousal, reward, attention)
find_duplicates Detect and merge redundant memories via cosine similarity

Maintenance

Tool What It Does
system_status Combined health + stats + cognitive state + recommendations
consolidate Run FSRS-6 decay cycle (also auto-runs every 6 hours)
memory_timeline Browse chronologically, grouped by day
memory_changelog Audit trail of state transitions
backup / export / gc Database backup, JSON export, garbage collection
restore Restore from JSON backup

Deep Reference (v2.0.4)

Tool What It Does
deep_reference Cognitive reasoning across memories. 8-stage pipeline: FSRS-6 trust scoring, intent classification, spreading activation, temporal supersession, contradiction analysis, relation assessment, dream insight integration, and algorithmic reasoning chain generation. Returns trust-scored evidence with a pre-built reasoning scaffold.
cross_reference Backward-compatible alias for deep_reference.

Active Forgetting (v2.0.5)

Tool What It Does
suppress Top-down active forgetting — neuroscience-grounded inhibitory control over retrieval. Distinct from memory.delete (destroys the row) and memory.demote (one-shot ranking hit). Each call compounds a retrieval-score penalty (Anderson 2025 SIF), and a background Rac1 cascade worker fades co-activated neighbors over 72h (Davis 2020). Reversible within a 24-hour labile window via reverse: true. The memory persists — it is inhibited, not erased.

Make Your AI Use Vestige Automatically

Add this to your CLAUDE.md:

## Memory

At the start of every session:
1. Search Vestige for user preferences and project context
2. Save bug fixes, decisions, and patterns without being asked
3. Create reminders when the user mentions deadlines
You Say AI Does
"Remember this" Saves immediately
"I prefer..." / "I always..." Saves as preference
"Remind me..." Creates a future trigger
"This is important" Saves + promotes

Full CLAUDE.md templates ->


Technical Details

Metric Value
Language Rust 2024 edition (MSRV 1.91)
Codebase 80,000+ lines, 1,292 tests (366 core + 425 mcp + 497 e2e + 4 doctests)
Binary size ~20MB
Embeddings Nomic Embed Text v1.5 (768d → 256d Matryoshka, 8192 context)
Vector search USearch HNSW (20x faster than FAISS)
Reranker Jina Reranker v1 Turbo (38M params, +15-20% precision)
Storage SQLite + FTS5 (optional SQLCipher encryption)
Dashboard SvelteKit 2 + Svelte 5 + Three.js + Tailwind CSS 4
Transport MCP stdio (JSON-RPC 2.0) + WebSocket
Cognitive modules 30 stateful (17 neuroscience, 11 advanced, 2 search)
First run Downloads embedding model (~130MB), then fully offline
Platforms macOS ARM + Intel + Linux x86_64 + Windows x86_64 (all prebuilt). Intel Mac needs brew install onnxruntime — see install guide.

Optional Features

# Metal GPU acceleration (Apple Silicon — faster embedding inference)
cargo build --release -p vestige-mcp --features metal

# Nomic Embed Text v2 MoE (475M params, 305M active, 8 experts)
cargo build --release -p vestige-mcp --features nomic-v2

# Qwen3 Reranker (Candle backend, high-precision cross-encoder)
cargo build --release -p vestige-mcp --features qwen3-reranker

# SQLCipher encryption
cargo build --release -p vestige-mcp --no-default-features --features encryption,embeddings,vector-search

CLI

vestige stats                    # Memory statistics
vestige stats --tagging          # Retention distribution
vestige stats --states           # Cognitive state breakdown
vestige health                   # System health check
vestige consolidate              # Run memory maintenance
vestige restore <file>           # Restore from backup
vestige dashboard                # Open 3D dashboard in browser

Documentation

Document Contents
FAQ 30+ common questions answered
Science The neuroscience behind every feature
Storage Modes Global, per-project, multi-instance
CLAUDE.md Setup Templates for proactive memory
Configuration CLI commands, environment variables
Integrations Codex, Xcode, Cursor, VS Code, JetBrains, Windsurf
Changelog Version history

Troubleshooting

"Command not found" after installation

Ensure vestige-mcp is in your PATH:

which vestige-mcp
# Or use the full path:
claude mcp add vestige /usr/local/bin/vestige-mcp -s user
Embedding model download fails

First run downloads ~130MB from Hugging Face. If behind a proxy:

export HTTPS_PROXY=your-proxy:port

Cache: macOS ~/Library/Caches/com.vestige.core/fastembed | Linux ~/.cache/vestige/fastembed

Dashboard not loading

The dashboard starts automatically on port 3927 when the MCP server runs. Check:

curl http://localhost:3927/api/health
# Should return {"status":"healthy",...}

More troubleshooting ->


Contributing

Issues and PRs welcome. See CONTRIBUTING.md.

License

AGPL-3.0 — free to use, modify, and self-host. If you offer Vestige as a network service, you must open-source your modifications.


Built by @samvallad33
80,000+ lines of Rust · 29 cognitive modules · 130 years of memory research · one 22MB binary