Introduce two trait boundaries that the rest of the stack now sits above,
landing Phase 1 of ADR 0001 (pluggable storage and network access).
Rebased onto v2.1.22 Sanhedrin from the original April work.
MemoryStore / LocalMemoryStore (crates/vestige-core/src/storage/memory_store.rs):
One trait, ~25 methods, covering CRUD, hybrid / FTS / vector search,
FSRS scheduling, graph edges, and the forthcoming domain surface.
trait_variant::make generates a Send-bound MemoryStore alias over the
base LocalMemoryStore so Arc<dyn MemoryStore> works under tokio/axum.
Storage errors map through a dedicated MemoryStoreError.
Embedder / LocalEmbedder (crates/vestige-core/src/embedder/):
Pluggable text-to-vector encoder. FastembedEmbedder wraps the existing
EmbeddingService; storage never calls fastembed directly anymore.
Embedder::signature() produces the ModelSignature consumed by the
store's embedding_model registry.
SqliteMemoryStore (crates/vestige-core/src/storage/sqlite.rs):
Storage renamed to SqliteMemoryStore; the old name lives on as a
pub type alias so Arc<Storage> consumers in vestige-mcp stay intact.
All existing inherent methods are untouched; the trait impl is
purely additive and dispatches into them. The db_path field added
by v2.1.1 portable-sync is preserved.
Migration V14 (crates/vestige-core/src/storage/migrations.rs):
Renumbered from V12 (the original April number) to V14 to slot in
cleanly after upstream's V12 (v2.1.1 sync_tombstones) and V13
(v2.1.2 purge tombstones).
- embedding_model registry table (CHECK id = 1, code enforces the
single-row invariant).
- knowledge_nodes.domains / domain_scores TEXT columns (JSON arrays
default '[]' / '{}'), domains catalogue table, supporting indexes.
Phase 4 populates these columns; Phase 1 just exposes the schema.
Consolidation and other cognitive pathways now accept a
&dyn LocalMemoryStore (sync) or Arc<dyn MemoryStore> (async) rather
than a concrete Storage.
Tests:
- trait-method unit tests colocated in sqlite.rs and migrations.rs
- embedder/fastembed.rs tests for name/dimension/hash stability
- new integration crate tests/phase_1 (added to workspace members):
trait_round_trip (8), embedding_model_registry (7),
domain_column_migration (5), cognitive_module_isolation (4),
send_bound_variant (2), embedder_trait (2).
Acceptance gate post-rebase:
- cargo build --workspace --all-targets: ok
- cargo clippy --workspace --all-targets -- -D warnings: clean
- cargo test -p vestige-core --lib: 428 pass
- cargo test -p vestige-phase-1-tests: 28 pass
- cargo test -p vestige-mcp --lib: 380 pass (Storage alias preserves
every existing call site)
Co-existence with v2.1.1 portable-sync: this trait extraction is
additive. Portable-sync's tombstone migrations (V12, V13) remain
on the concrete SqliteMemoryStore; Phase 2 (Postgres) will decide
which of those surfaces graduate into the trait.
Rebased on v2.1.25 merge/supersede and bumped the post-release metadata to v2.1.26 so this branch does not roll versions backward.
Adds local vestige.toml defaults, output profiles, and MCP response precedence for search, timeline, codebase context, and session context.
Verified:
- cargo metadata --format-version 1 --locked --no-deps
- cargo test -p vestige-core config --no-fail-fast
- cargo test -p vestige-mcp config --no-fail-fast
Tolerate SQLite-native timestamps from external writers while preserving RFC3339 as the canonical write format.
Verified locally on the merge result:
- cargo test -p vestige-core test_parse_timestamp_accepts_rfc3339_and_sqlite_native --no-fail-fast
CI/Test Suite on the updated PR branch are green.
* feat(mcp/system_status): add optional schema_introspection flag
Adds an optional `schema_introspection: bool` parameter to the
`system_status` MCP tool. When set to true, the response gains a
`schema` block carrying:
- `schemaVersion` (u32) — highest applied migration, mirrors
`Storage::current_schema_version` (now exposed via a typed public
method).
- `schemaVersionAppliedAt` (RFC3339, optional) — timestamp the
current schema_version row was applied.
- `tables` ([{name, rows, columns}]) — per-table row count + column
list, walked over the canonical PORTABLE_USER_DATA_TABLES set so
the surface stays stable across migrations rather than enumerating
arbitrary sqlite_master rows.
- `embeddingNullCount` (i64) — count of knowledge_nodes with NO row
in node_embeddings. Distinct from MemoryStats.nodes_with_embeddings
(which keys off the `has_embedding` flag column), so audit scripts
can detect drift between the flag and the join-based truth.
- `activeEmbeddingModel` (string, optional) + `activeEmbeddingDimensions`
(u32, optional) — mirrors the existing MemoryStats active-model
fields, included here so audits get schema_version + active model
in a single round-trip.
Motivation: external consumers (audit scripts, migration guards,
downstream binary upgrade scripts) currently must read SQLite
directly to learn the schema shape, which couples them to internals
Vestige owns and breaks on every migration. This PR closes that gap
with a first-class MCP surface.
Implementation:
- New `pub fn schema_introspection() -> Result<SchemaIntrospection>`
inherent method on `Storage` (sqlite.rs). Inherent, not on a
trait — schema-walk is SQLite-specific by nature, so this stays
out of any future MemoryStore trait extraction.
- New typed structs `SchemaIntrospection` + `TableIntrospection` in
memory/mod.rs (canonical home alongside MemoryStats), re-exported
from the crate root.
- MCP layer (maintenance.rs) parses `SystemStatusArgs`, conditionally
extends the existing response object with a `schema` key — additive,
default off, response shape unchanged when omitted.
Coupling assessment vs PR #61 (storage-trait-phase1):
This PR adds ONE new public inherent method on `Storage` plus uses
three already-existing private helpers (`current_schema_version`,
`table_exists`, `table_row_count`, `table_columns`). It does NOT
touch the existing inherent method signatures, does NOT add anything
to the prospective `MemoryStore` trait surface, and does NOT modify
any of the ~25 methods #61 lifts into the trait. PR #61 is purely
additive on the trait surface (per its description, `pub type
Storage = SqliteMemoryStore;` preserves all existing call sites);
this PR is additive on the inherent surface. Two purely-additive
changes to disjoint surfaces should rebase cleanly.
Tests:
- system_status_schema_has_schema_introspection_flag (schema
introspection: property present, type=boolean, default=false,
not required)
- system_status_without_schema_flag_omits_schema_block
(backwards-compat: unset/false → no `schema` key)
- system_status_with_schema_flag_emits_schema_block (positive case:
schema block present, schemaVersion >= 13, tables non-empty,
knowledge_nodes row count + columns sane, convenience fields
present)
- system_status_camelcase_alias (#[serde(rename_all="camelCase")] +
alias works for both snake and camel input)
- storage_schema_introspection_method (Storage-layer method tested
directly, independent of MCP)
Closes the second of two gaps surfaced in the knowledge-mgmt-sota-uplift
initiative. Companion to PR #68 (search.tag_prefix). The two PRs are
deliberately decoupled — this one carries the storage-layer surface
extension; the other is MCP-layer-only.
* fix(memory): derive Default on SchemaIntrospection to satisfy clippy
The manual `impl Default for SchemaIntrospection` tripped
`clippy::derivable_impls` under the workspace's `-D warnings` CI gate.
All fields are types with `Default` impls (`u32`, `Option<T>`, `Vec<T>`,
`i64`), so deriving is equivalent and clippy-clean. Matches the existing
style of `ConsolidationResult` further down in the same file.
CI / Release Build (aarch64-apple-darwin) (push) Blocked by required conditions
CI / Release Build (x86_64-unknown-linux-gnu) (push) Blocked by required conditions
CI / Release Build (x86_64-apple-darwin) (push) Blocked by required conditions
Test Suite / Unit Tests (push) Waiting to run
Test Suite / MCP E2E Tests (push) Waiting to run
Test Suite / User Journey Tests (push) Blocked by required conditions
Test Suite / Dashboard Build (push) Waiting to run
Test Suite / Code Coverage (push) Waiting to run
Nine tool modules in crates/vestige-mcp/src/tools/ had zero callers after
the v2.0.x unification work shipped *_unified + maintenance::* replacements.
They'd been #[allow(dead_code)]-papered over and forgotten. Verified each
module independently: grep for tools::<name>::, string dispatch in server.rs,
cross-crate usage — all nine returned zero external callers.
Removed modules (all superseded):
checkpoint (364 LOC) — no callers anywhere
codebase (298) — superseded by codebase_unified
consolidate (36) — superseded by maintenance::execute_consolidate
ingest (456) — superseded by smart_ingest
intentions (1,093) — superseded by intention_unified
knowledge (106) — no callers anywhere
recall (403) — superseded by search_unified
search (184) — superseded by search_unified
stats (132) — superseded by maintenance::execute_system_status
Also removed:
- EmotionCategory::base_arousal (10 LOC, zero callers)
Kept (still string-dispatched from server.rs):
- context, feedback, memory_states, review, tagging
Doc fixes (ghost env vars that were documented but zero Rust source reads):
- docs/CONFIGURATION.md — dropped VESTIGE_DATA_DIR, VESTIGE_LOG_LEVEL rows
(neither is read anywhere; --data-dir CLI flag + RUST_LOG are the real
mechanisms). Added the full real env-var table.
- packages/vestige-mcp-npm/README.md — same two ghost rows dropped
- docs/VESTIGE_STATE_AND_PLAN.md:399 — dropped VESTIGE_DATA_DIR row
- docs/VESTIGE_STATE_AND_PLAN.md:709 — typo VESTIGE_API_KEY
-> VESTIGE_AUTH_TOKEN (matches shipping convention), "open if unset"
-> "auto-generated if unset" to match actual behavior
Verified post-cleanup:
- cargo check --workspace clean
- cargo clippy --workspace -D warnings clean
- cargo test --workspace 1,223 passing / 0 failed
- cargo build --release -p vestige-mcp clean
Net: -3,091 LOC (14 files), zero behavior change, zero regressions.
sanitize_fts5_query wraps queries in quotes, producing FTS5 phrase search
where the words must be adjacent. So "quantum physics" against a doc
containing "quantum entanglement superposition physics" returned no FTS
hit; semantic search hid the issue whenever embeddings were enabled.
Add sanitize_fts5_terms that splits into space-separated terms (FTS5
implicit AND, any order, any position), and use it in:
- keyword_search_with_scores (hybrid-search FTS leg) so multi-word
queries return docs containing all words regardless of adjacency
- a new SqliteMemoryStore::search_terms inherent method for callers
that want individual-term matching without the full hybrid pipeline
sanitize_fts5_query stays in place; KeywordSearcher still uses it
(phrase semantics preserved where they were wanted).
memory_timeline ran node_type and tags as Rust-side `retain` after
`query_time_range`, which applied `LIMIT` in SQL before the retain
saw anything. Against a corpus where one tag or type dominates, a
sparse match could be crowded out of the limit window — the tool
reported "no matches" when matches existed.
Fix: thread `node_type: Option<&str>` and `tags: Option<&[String]>`
through `query_time_range` and apply both as `WHERE` predicates so
`LIMIT` kicks in after filtering. Tag matching uses `tags LIKE '%"tag"%'` —
the quoted pattern pins to exact tags and rejects substring false
positives (e.g. `alpha` no longer matches `alphabet`).
Regression tests in `tools/timeline.rs`:
- test_timeline_node_type_filter_sparse: 10 `fact` + 2 `concept`,
`limit=5`, query `concept` — asserts 2 rows; fails on pre-fix code.
- test_timeline_tag_filter_sparse: 10 rows tagged `common` + 2 tagged
`rare`, `limit=5`, query `rare` — asserts 2 rows; same shape for tags.
- test_timeline_tag_filter_exact_match: one `alpha` row + one
`alphabet` row, query `alpha` — asserts exactly 1 row.
Dashboard caller updated to pass `None, None` for the new filter
params. 19/19 timeline tests pass; 1295/1295 workspace tests pass;
clippy clean on vestige-core and vestige-mcp.
Ported from the Unforgettable/Anamnesis fork.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI runs on stable Rust which advanced from 1.93 to 1.95, introducing
two newly-enforced lints under -D warnings:
- clippy::unnecessary_sort_by (12 sites) — rewrite sort_by closures
that only call .cmp on Copy keys as sort_by_key, using std::cmp::Reverse
for the descending ones.
- clippy::collapsible_match (1 site) — merge the MemoryState::Dormant
inner if into a match guard. The equivalent rewrite for the Ping/Pong
arm in websocket.rs is blocked by a move of non-Copy Bytes across the
match-guard boundary, so that one site gets an explicit #[allow].
Files touched:
- crates/vestige-core/src/advanced/{chains,compression,cross_project,reconsolidation}.rs
- crates/vestige-core/src/codebase/{git,relationships}.rs
- crates/vestige-core/src/neuroscience/{importance_signals,memory_states,predictive_retrieval}.rs
- crates/vestige-mcp/src/tools/{changelog,cross_reference}.rs
- crates/vestige-mcp/src/dashboard/websocket.rs
Verified: cargo clippy --workspace -- -D warnings green on rustc 1.95.0;
cargo test --workspace unchanged (1292 tests green).
The pre-merge audit flagged that 4 of the 5 branch commits shipped
with zero assertions exercising the new code paths — existing tests
would have passed if the fixes were reverted to their broken state.
Close that gap with 7 new tests, each touching one specific
behavior:
migrations.rs (2 tests, crates/vestige-core)
- test_apply_migrations_advances_to_v11_and_drops_dead_tables:
end-to-end runs the whole V1..V11 chain on an in-memory DB and
asserts schema_version=11, knowledge_edges absent,
compressed_memories absent.
- test_v11_is_idempotent_on_replay: rewinds schema_version to 10
after a successful apply and re-runs apply_migrations to prove
`DROP TABLE IF EXISTS` tolerates the already-dropped state.
Guards against a future refactor accidentally using `DROP TABLE`
without the guard.
predict.rs (1 test)
- test_predict_degraded_false_on_happy_path: asserts the new
`predict_degraded` JSON field is present and `false` on a fresh
cognitive engine.
changelog.rs (2 tests)
- test_changelog_malformed_start_returns_error: asserts a bad
`start` value produces a helpful `Invalid start ... ISO-8601`
error instead of panicking or silently dropping the filter.
- test_changelog_filter_field_echoes_start: asserts the response
`filter.start` field echoes the applied bound so callers can
confirm their window was honored.
intention_unified.rs (3 tests)
- test_check_includes_snoozed_when_flag_set: creates an intention,
snoozes it, calls check with include_snoozed=true, asserts it
appears in either triggered or pending.
- test_check_excludes_snoozed_by_default: same setup, default
flag, asserts the snoozed intention does NOT appear — locks in
the pre-v2.0.7 behavior for every non-opt-in caller.
- test_check_item_exposes_status_field: asserts every item in the
check response carries the new `status` field.
All tests pass. vestige-core moves 366 -> 368, vestige-mcp moves
419 -> 425. Zero regressions under default or qwen3-embed features.
Clippy still clean on both crates.
Both tables were added speculatively in V4 and never received a single
INSERT or SELECT in the codebase. `knowledge_edges` has an elaborate
bi-temporal schema (valid_from, valid_until, confidence) and was marked
DEPRECATED in the same V4 migration that created it — the real edge
table is `memory_connections` (V3). `compressed_memories` was a tiered-
compression feature (compression_ratio, semantic_fidelity, model_used)
but `advanced/compression.rs` operates entirely in-memory and never
touches it.
Both tables are verified single-file references (only migrations.rs).
A grep across crates/ shows zero row reads or writes. Safe to drop
without behaviour change; frees schema space for future migrations.
First AI memory system to model forgetting as a neuroscience-grounded
PROCESS rather than passive decay. Adds the `suppress` MCP tool (#24),
Rac1 cascade worker, migration V10, and dashboard forgetting indicators.
Based on:
- Anderson, Hanslmayr & Quaegebeur (2025), Nat Rev Neurosci — right
lateral PFC as the domain-general inhibitory controller; SIF
compounds with each stopping attempt.
- Cervantes-Sandoval et al. (2020), Front Cell Neurosci PMC7477079 —
Rac1 GTPase as the active synaptic destabilization mechanism.
What's new:
* `suppress` MCP tool — each call compounds `suppression_count` and
subtracts a `0.15 × count` penalty (saturating at 80%) from
retrieval scores during hybrid search. Distinct from delete
(removes) and demote (one-shot).
* Rac1 cascade worker — background sweep piggybacks the 6h
consolidation loop, walks `memory_connections` edges from
recently-suppressed seeds, applies attenuated FSRS decay to
co-activated neighbors. You don't just forget Jake — you fade
the café, the roommate, the birthday.
* 24h labile window — reversible via `suppress({id, reverse: true})`
within 24 hours. Matches Nader reconsolidation semantics.
* Migration V10 — additive-only (`suppression_count`, `suppressed_at`
+ partial indices). All v2.0.x DBs upgrade seamlessly on first launch.
* Dashboard: `ForgettingIndicator.svelte` pulses when suppressions
are active. 3D graph nodes dim to 20% opacity when suppressed.
New WebSocket events: `MemorySuppressed`, `MemoryUnsuppressed`,
`Rac1CascadeSwept`. Heartbeat carries `suppressed_count`.
* Search pipeline: SIF penalty inserted into the accessibility stage
so it stacks on top of passive FSRS decay.
* Tool count bumped 23 → 24. Cognitive modules 29 → 30.
Memories persist — they are INHIBITED, not erased. `memory.get(id)`
returns full content through any number of suppressions. The 24h
labile window is a grace period for regret.
Also fixes issue #31 (dashboard graph view buggy) as a companion UI
bug discovered during the v2.0.5 audit cycle:
* Root cause: node glow `SpriteMaterial` had no `map`, so
`THREE.Sprite` rendered as a solid-coloured 1×1 plane. Additive
blending + `UnrealBloomPass(0.8, 0.4, 0.85)` amplified the square
edges into hard-edged glowing cubes.
* Fix: shared 128×128 radial-gradient `CanvasTexture` singleton used
as the sprite map. Retuned bloom to `(0.55, 0.6, 0.2)`. Halved fog
density (0.008 → 0.0035). Edges bumped from dark navy `0x4a4a7a`
to brand violet `0x8b5cf6` with higher opacity. Added explicit
`scene.background` and a 2000-point starfield for depth.
* 21 regression tests added in `ui-fixes.test.ts` locking every
invariant in (shared texture singleton, depthWrite:false, scale
×6, bloom magic numbers via source regex, starfield presence).
Tests: 1,284 Rust (+47) + 171 Vitest (+21) = 1,455 total, 0 failed
Clippy: clean across all targets, zero warnings
Release binary: 22.6MB, `cargo build --release -p vestige-mcp` green
Versions: workspace aligned at 2.0.5 across all 6 crates/packages
Closes#31
CI failed on macOS + Ubuntu with clippy::collapsible_if on the
else-if branch of the exclude_types filter. Collapse the inner
`if` into the `let Some && ...` guard. Semantics preserved — the
includes branch is left as-is to keep include/exclude mutually
exclusive behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Type filtering (include_types/exclude_types) was applied post-fetch after
the database LIMIT, which could return zero results when all top-N
results were of the filtered type. This pushes type filters into the SQL
WHERE clause in keyword_search_with_scores() so they apply before the
limit. Semantic results still get post-fetch filtering as a safety net
since the vector index cannot filter by type.
Also adds hybrid_search_filtered() as the new primary method, with the
original hybrid_search() delegating to it with no filters for backward
compatibility. The MCP search tool now exposes include_types and
exclude_types parameters.
Includes 5 new test cases covering include, exclude, precedence,
empty results, and backward compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed vestige-agent and vestige-agent-py from workspace members
(ARC-AGI-3 code, not part of Vestige release — caused CI failure)
- Improved deep_reference reasoning chain: fuller output with arrows on
supersession reasoning, longer primary finding preview, fallback message
when no relations found, boosted relation detection for search results
with high combined_score
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When memories are created, promoted, deleted, or dreamed via MCP tools,
the 3D graph now shows spectacular live animations:
- Rainbow particle burst + elastic scale-up on MemoryCreated
- Ripple wave cascading to nearby nodes
- Green pulse + node growth on MemoryPromoted
- Implosion + dissolution on MemoryDeleted
- Edge growth animation on ConnectionDiscovered
- Purple cascade on DreamStarted/DreamProgress/DreamCompleted
- FIFO eviction at 50 live nodes to guard performance
Also: graph center defaults to most-connected node, legacy HTML
redirects to SvelteKit dashboard, CSS height chain fix in layout.
Testing: 150 unit tests (vitest), 11 e2e tests (Playwright with
MCP Streamable HTTP client), 22 proof screenshots.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ort-sys v2.0.0-rc.11 has no prebuilt ONNX Runtime binaries for
x86_64-apple-darwin, and vestige-mcp requires embeddings to compile.
- Remove x86_64-apple-darwin from CI release matrix (discontinued 2020)
- Fix vestige-mcp Cargo.toml: add default-features=false to vestige-core dep
- Extract sanitize_fts5_query to always-available fts.rs module
- Gate embeddings-only imports in storage/sqlite.rs behind #[cfg]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dashboard v2.1 "Nuclear" upgrade:
- Dark glassmorphism UI system (4-tier glass utilities, ambient orbs, nav glow)
- Graph3D decomposed from 806-line monolith into 10 focused modules
- Custom GLSL shaders (nebula FBM background, chromatic aberration, film grain, vignette)
- Enhanced dream mode with smooth 2s lerped transitions and aurora cycling
- Cognitive pipeline visualizer (7-stage search cascade animation)
- Temporal playback slider (scrub through memory evolution over time)
- Bioluminescent color palette for node types and events
Fix flaky CI test on macOS:
- vector::tests::test_add_and_search used near-identical test vectors (additive phase shift)
- Changed to multiplicative frequency so each seed produces a distinct vector
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Triggers 2 (force after 6h stale) and 3 (mini-consolidation after 2h)
fired immediately on fresh schedulers even when user was active, because
they didn't check activity state. Added MIN_BRIEF_IDLE_MINS (5 min)
guard so both triggers require a brief idle period before firing.
Fixes test_consolidation_idle_trigger in CI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3 new MCP tools (16 → 19 total):
- importance_score: 4-channel neuroscience importance scoring (novelty/arousal/reward/attention)
- session_checkpoint: batch smart_ingest up to 20 items with PE Gating
- find_duplicates: cosine similarity clustering with union-find for dedup
CLI: vestige ingest command for memory ingestion via command line
Core: made get_node_embedding public, added get_all_embeddings for dedup scanning
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add web dashboard (axum) on port 3927 with memory browser, search, and
system stats. New MCP tools: memory_timeline, memory_changelog,
health_check, consolidate, stats, backup, export, gc. Search now supports
detail_level (brief/summary/full) to control token usage. Add backup_to()
and get_recent_state_transitions() to storage layer. Bump to v1.2.0.
P0 fixes:
- Add `vestige backup <path>` — full DB copy with WAL checkpoint flush
- Add `vestige export --format json|jsonl [--tags] [--since] <path>` —
paginated memory export with tag/date filtering
- Add `vestige gc --min-retention 0.1 [--max-age-days] [--dry-run] [--yes]`
— bulk cleanup of stale memories with safety prompts
- Fix apply_decay() scaling: batched pagination (500 rows/batch) with
explicit transactions instead of loading all nodes into memory
- Fix hidden MCP resources: memory://insights and memory://consolidation-log
now listed in resources/list (were implemented but undiscoverable)
P1 fixes:
- Add auto-consolidation on server startup: FSRS-6 decay runs in background
after 2s delay, only if last consolidation was >6 hours ago
- Add encryption at rest via SQLCipher feature flag: use --features encryption
with VESTIGE_ENCRYPTION_KEY env var (bundled-sqlite and encryption are
mutually exclusive)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, fastembed created .fastembed_cache in the current working
directory, polluting project folders with symlinks.
Now uses platform-appropriate cache directories:
- macOS: ~/Library/Caches/com.vestige.core/fastembed
- Linux: ~/.cache/vestige/fastembed
- Windows: %LOCALAPPDATA%\vestige\cache\fastembed
Can still be overridden with FASTEMBED_CACHE_PATH env var.
Fixes user feedback about .fastembed_cache appearing in random folders.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add #![allow(dead_code)] to deprecated tool modules (kept for
backwards compatibility but not exposed in MCP tool list)
- Mark unused functions with #[allow(dead_code)] annotations
- Fix unused variable warnings (prefix with _)
- Apply clippy auto-fixes for redundant closures and derives
- Fix test to account for protocol version negotiation
- Reorganize tools/mod.rs to clarify active vs deprecated tools
Security review: LOW RISK - no critical vulnerabilities found
Dead code review: deprecated tools properly annotated
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix silent errors in stdio.rs: clients now receive fallback error
responses instead of hanging when JSON serialization fails
- Fix UTF-8 panics in keyword.rs: use char-aware slicing instead of
byte offsets for query sanitization and term highlighting
- Fix UTF-8 panics in prospective_memory.rs: replace hard-coded byte
offsets with char-aware slicing for natural language parsing
- Fix UTF-8 panics in git.rs: convert byte positions to char positions
before slicing commit messages
- Fix feature flag bug in vestige-mcp: add proper [features] section
to forward embeddings and vector-search features from vestige-core,
enabling the #[cfg(feature = "embeddings")] initialization code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When embeddings fail to initialize in the MCP server context (e.g., due
to working directory issues), the error was silently swallowed and
smart_ingest would fall back to regular ingest without explanation.
Changes:
- Add init_embeddings() method to Storage for explicit initialization
- Initialize embeddings at MCP server startup with error logging
- Add check_ready() method to EmbeddingService for error access
- Log warning when is_ready() returns false
Now users will see clear error messages like:
"Failed to initialize embedding service: ..."
"Hint: Check FASTEMBED_CACHE_PATH or ensure ~/.fastembed_cache exists"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace BGE-base-en-v1.5 with nomic-embed-text-v1.5
- 8192 token context window (vs 512 for BGE)
- Matryoshka representation learning support
- Fully open source with training data released
- Same 768 dimensions, no schema changes required
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
FSRS-6 spaced repetition, spreading activation, synaptic tagging,
hippocampal indexing, and 130 years of memory research.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>