mirror of
https://github.com/samvallad33/vestige.git
synced 2026-07-12 22:42:10 +02:00
Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d95347b88 | ||
|
|
cb7ee2dcb5 | ||
|
|
4f457ec2db |
720 changed files with 9878 additions and 83478 deletions
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
|
|
@ -17,15 +17,6 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Pin macOS to macos-14 (Sonoma): the rolling `macos-latest` image
|
||||
# The "ld: library 'clang_rt.osx' not found" failure is NOT a flaky
|
||||
# image. It is the linker resolving a clang compiler-rt search path
|
||||
# (Xcode .../clang/<N>/lib/darwin) that no longer exists on the runner,
|
||||
# because a STALE `target/` was restored from the cache after the
|
||||
# runner image's default Xcode moved. The real fix is the cache change
|
||||
# below (we no longer cache `target/`, and the key is bumped to v2 to
|
||||
# discard the poisoned caches), so the runner choice is no longer
|
||||
# load-bearing. macos-latest is fine again with a clean target dir.
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -35,20 +26,17 @@ jobs:
|
|||
with:
|
||||
components: clippy
|
||||
|
||||
- name: Cache cargo (registry only)
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
# Deliberately NOT caching `target/`: a `target/` built against a
|
||||
# different Xcode carries a stale clang compiler-rt search path that
|
||||
# breaks the linker ("clang_rt.osx not found"). Cache only the
|
||||
# download-heavy registry/git dirs; recompiling is cheap and correct.
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
key: ${{ runner.os }}-cargo-v2-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: ${{ runner.os }}-cargo-v2-
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: ${{ runner.os }}-cargo-
|
||||
|
||||
- name: Check
|
||||
run: cargo check --workspace
|
||||
|
|
@ -73,13 +61,13 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-14
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
cargo_flags: ""
|
||||
# Intel Mac builds against a system ONNX Runtime via ort-dynamic
|
||||
# (ort-sys has no x86_64-apple-darwin prebuilts). Compile-only here;
|
||||
# runtime linking is a user concern documented in INSTALL-INTEL-MAC.md.
|
||||
- os: macos-14
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
cargo_flags: "--no-default-features --features ort-dynamic,vector-search"
|
||||
- os: ubuntu-latest
|
||||
|
|
|
|||
25
.github/workflows/guard-no-private-cloud.yml
vendored
25
.github/workflows/guard-no-private-cloud.yml
vendored
|
|
@ -1,25 +0,0 @@
|
|||
name: Guard — No Private Cloud Code
|
||||
|
||||
# Fails if private Vestige Cloud *service* code (billing, sync-key/namespace
|
||||
# mapping, Lemon Squeezy webhooks, transactional email) ever lands in this
|
||||
# public repo. The public cloud *client* is allowed and does not trip this.
|
||||
on:
|
||||
push:
|
||||
branches: [main, feat/cloud-sync-mvp]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
guard:
|
||||
name: No private cloud service code
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Scan for private cloud service markers
|
||||
run: ./scripts/check-no-private-cloud.sh
|
||||
67
.github/workflows/pages.yml
vendored
67
.github/workflows/pages.yml
vendored
|
|
@ -1,67 +0,0 @@
|
|||
name: Deploy GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, feat/cloud-sync-mvp]
|
||||
paths:
|
||||
- 'apps/dashboard/**'
|
||||
- '.github/workflows/pages.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment; let an in-progress run finish.
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
env:
|
||||
# GitHub Pages serves this project repo from the /vestige/ subpath.
|
||||
# The dashboard must be built with a matching base so every _app/ asset
|
||||
# resolves instead of 404ing.
|
||||
VESTIGE_BASE_PATH: /vestige
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build dashboard
|
||||
run: pnpm --filter @vestige/dashboard build
|
||||
|
||||
- name: Assemble site root
|
||||
run: |
|
||||
# The Pages project site is already served from /vestige/, and the
|
||||
# dashboard is built with base path /vestige (VESTIGE_BASE_PATH), so
|
||||
# its files go directly at the artifact root — the base path already
|
||||
# accounts for the subpath. No extra subdirectory or redirect needed.
|
||||
rm -rf _site
|
||||
mkdir -p _site
|
||||
cp -r apps/dashboard/build/* _site/
|
||||
|
||||
- uses: actions/configure-pages@v5
|
||||
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: _site
|
||||
|
||||
- id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
103
.github/workflows/release.yml
vendored
103
.github/workflows/release.yml
vendored
|
|
@ -31,14 +31,7 @@ jobs:
|
|||
- target: x86_64-pc-windows-msvc
|
||||
os: windows-latest
|
||||
archive: zip
|
||||
# vector-search (usearch HNSW index) is REQUIRED. Without it the
|
||||
# storage layer's #[cfg(feature = "vector-search")] paths compile
|
||||
# out, so embeddings are never persisted or queried: the binary
|
||||
# reports "Embedding Service: Not Ready", 0% coverage, consolidate
|
||||
# generates 0 embeddings, and no model download is ever attempted.
|
||||
# usearch builds cleanly on MSVC because vestige-core pins it with
|
||||
# features=["fp16lib"] (see crates/vestige-core/Cargo.toml).
|
||||
cargo_flags: "--no-default-features --features embeddings,ort-download,vector-search"
|
||||
cargo_flags: ""
|
||||
needs_onnxruntime: false
|
||||
# Intel Mac uses the ort-dynamic feature to runtime-link against a
|
||||
# system libonnxruntime (Homebrew), sidestepping the missing
|
||||
|
|
@ -57,93 +50,14 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event_name == 'workflow_dispatch' && github.sha || github.event.inputs.tag || github.ref }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Validate release version
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }}
|
||||
run: |
|
||||
node <<'NODE'
|
||||
const { execFileSync } = require('node:child_process');
|
||||
const tag = process.env.RELEASE_TAG || '';
|
||||
const expected = tag.replace(/^refs\/tags\//, '').replace(/^v/, '');
|
||||
if (!expected) {
|
||||
throw new Error('Release tag is empty');
|
||||
}
|
||||
|
||||
const packageFiles = [
|
||||
'package.json',
|
||||
'apps/dashboard/package.json',
|
||||
'packages/vestige-init/package.json',
|
||||
'packages/vestige-mcp-npm/package.json'
|
||||
];
|
||||
for (const file of packageFiles) {
|
||||
const actual = require(`./${file}`).version;
|
||||
if (actual !== expected) {
|
||||
throw new Error(`${file} version ${actual} does not match ${tag}`);
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = JSON.parse(execFileSync('cargo', [
|
||||
'metadata',
|
||||
'--format-version',
|
||||
'1',
|
||||
'--locked',
|
||||
'--no-deps'
|
||||
], { encoding: 'utf8' }));
|
||||
for (const name of ['vestige-core', 'vestige-mcp']) {
|
||||
const pkg = metadata.packages.find((candidate) => candidate.name === name);
|
||||
if (!pkg) throw new Error(`Missing Cargo package ${name}`);
|
||||
if (pkg.version !== expected) {
|
||||
throw new Error(`${name} version ${pkg.version} does not match ${tag}`);
|
||||
}
|
||||
}
|
||||
NODE
|
||||
|
||||
- name: Build embedded dashboard
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }}
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm --filter @vestige/dashboard check
|
||||
pnpm --filter @vestige/dashboard test
|
||||
pnpm --filter @vestige/dashboard build
|
||||
node <<'NODE'
|
||||
const fs = require('node:fs');
|
||||
const tag = process.env.RELEASE_TAG || '';
|
||||
const expected = tag.replace(/^refs\/tags\//, '').replace(/^v/, '');
|
||||
const versionFile = 'apps/dashboard/build/_app/version.json';
|
||||
const version = JSON.parse(fs.readFileSync(versionFile, 'utf8')).version;
|
||||
if (version !== expected) {
|
||||
throw new Error(`${versionFile} version ${version} does not match ${tag}`);
|
||||
}
|
||||
for (const file of ['apps/dashboard/build/index.html', versionFile]) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(`Dashboard build did not produce ${file}`);
|
||||
}
|
||||
}
|
||||
NODE
|
||||
|
||||
- name: Build
|
||||
run: cargo build --locked --package vestige-mcp --release --target ${{ matrix.target }} ${{ matrix.cargo_flags }}
|
||||
run: cargo build --package vestige-mcp --release --target ${{ matrix.target }} ${{ matrix.cargo_flags }}
|
||||
|
||||
- name: Package (Unix)
|
||||
if: matrix.os != 'windows-latest'
|
||||
|
|
@ -163,21 +77,10 @@ jobs:
|
|||
cd target/${{ matrix.target }}/release
|
||||
Compress-Archive -Path vestige-mcp.exe,vestige.exe,vestige-restore.exe -DestinationPath ../../../vestige-mcp-${{ matrix.target }}.zip
|
||||
|
||||
- name: Generate checksum
|
||||
shell: bash
|
||||
run: |
|
||||
if command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} > vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256
|
||||
else
|
||||
sha256sum vestige-mcp-${{ matrix.target }}.${{ matrix.archive }} > vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256
|
||||
fi
|
||||
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.tag || github.ref_name }}
|
||||
files: |
|
||||
vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}
|
||||
vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}.sha256
|
||||
files: vestige-mcp-${{ matrix.target }}.${{ matrix.archive }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
|
|
@ -12,19 +12,6 @@ env:
|
|||
VESTIGE_TEST_MOCK_EMBEDDINGS: "1"
|
||||
|
||||
jobs:
|
||||
hook-tests:
|
||||
name: Hook Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- run: python3 -m unittest discover -s tests/hooks -p 'test_*.py'
|
||||
- run: python3 -m py_compile hooks/sanhedrin-local.py tests/hooks/test_sanhedrin_claim_mode.py
|
||||
- run: bash -n hooks/sanhedrin.sh scripts/install-sandwich.sh scripts/check-sandwich-prereqs.sh
|
||||
|
||||
unit-tests:
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -139,6 +139,3 @@ apps/dashboard/node_modules/
|
|||
# =============================================================================
|
||||
fastembed-rs/
|
||||
.mcp.json
|
||||
|
||||
.claude/
|
||||
.codebase-memory/
|
||||
|
|
|
|||
489
CHANGELOG.md
489
CHANGELOG.md
|
|
@ -5,469 +5,17 @@ All notable changes to Vestige will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed — Auto-consolidation merge: opt-out lever + protected pins honored (#142)
|
||||
|
||||
The background consolidation cycle's auto-dedup pass silently concat-merges
|
||||
near-duplicate memories (cosine ≥ 0.85): it keeps the strongest node, folds the
|
||||
weaker ones in as `[MERGED]` blocks, and **hard-deletes** the originals — with no
|
||||
reflog and no way to turn it off. Two fixes. First, it is now disableable: set
|
||||
`VESTIGE_AUTO_CONSOLIDATE_MERGE=0` (or `false`/`off`/`no`) to suppress it. It
|
||||
remains **on by default** (behavior unchanged), and the `dedup` MCP tool stays
|
||||
available for on-demand, previewable, reversible merges regardless. Second,
|
||||
**protected (pinned) memories are now excluded from this pass** — previously
|
||||
`dedup protect` did nothing here, so a pinned memory could be absorbed or deleted
|
||||
unattended, contradicting the interactive contract that a protected node may only
|
||||
survive a merge, never be absorbed. A protected node is now never an anchor, never
|
||||
a cluster member, and thus never merged into or deleted, whether the lever is on
|
||||
or off.
|
||||
|
||||
## [2.2.1] - 2026-07-02 — "Windows embeddings + backfill safety"
|
||||
|
||||
A focused patch release. Two fixes plus a first-run guide.
|
||||
|
||||
### Fixed — Windows embeddings never initialized (#101)
|
||||
|
||||
The `x86_64-pc-windows-msvc` v2.2.0 binary was built without the `vector-search`
|
||||
feature, so the storage layer's `#[cfg(feature = "vector-search")]` paths compiled
|
||||
out. On Windows this meant new memories got no embedding, semantic search returned
|
||||
nothing, `vestige health` reported "Embedding Service: Not Ready" (0% coverage),
|
||||
and no model download was ever attempted — while v2.1.23 worked on the same machine.
|
||||
The release build now includes `vector-search` on Windows (it compiles cleanly on
|
||||
MSVC because `usearch` is pinned with `features = ["fp16lib"]`). npm and direct
|
||||
downloads are fixed by the same rebuilt release asset. Thanks @Vrakoss for the
|
||||
precise report.
|
||||
|
||||
### Fixed — Retroactive Salience Backfill: bounded promote + opt-out lever (#103)
|
||||
|
||||
The consolidation-pass backfill promoted root-cause memories with an **uncapped**
|
||||
`stability * 1.5` FSRS multiply, and a code comment wrongly claimed it was capped.
|
||||
On a chronically-recurring failure this could inflate a cause's stability without
|
||||
bound, distorting its review schedule. Backfill promotion is now bounded to
|
||||
`MIN(stability * 1.5, stability + 365.0)` (the additive +365-day ceiling the
|
||||
backfill module already computed but never applied), on both the auto-fire and the
|
||||
manual `backfill` tool paths. Auto-fire remains **on by default** (it shipped and
|
||||
was documented in v2.2.0) but is now disableable: set `VESTIGE_BACKFILL_AUTOFIRE=0`
|
||||
(or `false`/`off`/`no`) to turn it off; the manual `backfill` tool + CLI remain
|
||||
available regardless. Thanks @randomnimbus for the report and the initial patch.
|
||||
|
||||
### Added — First-run guide (#83)
|
||||
|
||||
A single `docs/GETTING-STARTED.md` that consolidates install, "what gets saved",
|
||||
how to inspect your memory, and project scoping into one 30-minute first-run path,
|
||||
linked from the README.
|
||||
|
||||
### Credits
|
||||
|
||||
This release was driven by the community:
|
||||
|
||||
- **@Vrakoss** reported the Windows embeddings regression (#101) with a clean,
|
||||
precise repro that pinned the failure immediately.
|
||||
- **@randomnimbus** (Peter Lauzon) reported the backfill safety issue (#103) and
|
||||
contributed the fix — the bounded `promote_memory_backfill` and the
|
||||
`VESTIGE_BACKFILL_AUTOFIRE` lever shipped as they proposed them
|
||||
(co-authored in `f7530af`).
|
||||
|
||||
Thank you both.
|
||||
|
||||
## [2.2.0] - 2026-06-29 — "Retroactive Salience + Tool Consolidation"
|
||||
|
||||
Three independent value streams land together as a coherent release.
|
||||
|
||||
### Added — Retroactive Salience Backfill ("Memory with hindsight")
|
||||
|
||||
A faithful port of Cai 2024 (*Nature*). When a **failure** (bug/crash/regression)
|
||||
is recorded, Vestige reaches **backward in time** and promotes the quiet earlier
|
||||
memory that *caused* it — the root cause a vector search structurally cannot
|
||||
surface, because it is not *similar* to the failure, only *causally upstream*
|
||||
(it shares an entity: the same file, env var, or service). Backward-only by
|
||||
construction. Auto-fires inside the consolidation pass; also exposed as the
|
||||
`backfill` MCP tool and the `vestige backfill` CLI command (`--manual`,
|
||||
`--contrast`, `--no-promote` dry-run).
|
||||
|
||||
### Changed — MCP Tool Consolidation (34 → 13 advertised tools)
|
||||
|
||||
The MCP surface is consolidated from 34 tools to **13**: `recall` (folds
|
||||
search + deep_reference + contradictions), `maintain` (consolidate/dream/gc/
|
||||
importance_score/backup/export/restore), `dedup` (8 merge tools → 1), `graph`
|
||||
(explore/predict/memory_graph/composed_graph), `memory_status` (system_status/
|
||||
memory_health/timeline/changelog), plus `memory`, `codebase`, `intention`,
|
||||
`smart_ingest`, `source_sync`, `session_start`, `suppress`, and the flagship
|
||||
`backfill`. Old tool names remain dispatchable as hidden back-compat aliases.
|
||||
|
||||
### Improved — `deep_reference` retrieval engine
|
||||
|
||||
- **F32 embeddings** (was I8 quantization) — lifts the 0.4–0.6 paraphrase cosine
|
||||
band so close-but-reworded queries actually retrieve.
|
||||
- **Reciprocal Rank Fusion** replaces linear score combination in hybrid search.
|
||||
- **Claim-vs-memory contradiction** — `recall`/`cross_reference` now test *your
|
||||
claim* against stored memory, surfacing `claim_contradicts_memory` instead of
|
||||
the old "confident silence."
|
||||
- **Never-composed semantic-band gate** — admits no-shared-word memory pairs in
|
||||
the 0.45–0.85 cosine band for `vestige compose`.
|
||||
- New `vestige recall <query>` and `vestige compose` CLI commands expose the
|
||||
engine outside the MCP path.
|
||||
|
||||
### Fixed — security & correctness (multi-model audit swarm)
|
||||
|
||||
SSRF/token-exfil hardening, panic/DoS/overflow fixes, deadlock and
|
||||
lock-contention fixes, dedup and decay correctness. `usearch` keeps
|
||||
`features = ["fp16lib"]` to avoid the Windows MSVC C1021 build break (#71/#94).
|
||||
|
||||
## [2.1.27] - 2026-06-19 — "External-Source Connectors"
|
||||
|
||||
Roadmap [#57](https://github.com/samvallad33/vestige/issues/57), **Phases 1–4
|
||||
(complete)**: Vestige can now act as a durable, local, semantically-searchable
|
||||
retrieval layer over an external system of record — GitHub Issues and Redmine —
|
||||
without replacing it. The external system stays canonical; Vestige **indexes,
|
||||
connects, retrieves, and cites back** to the source record.
|
||||
|
||||
Unlike a live ticket-system MCP proxy (which holds no state and is rate-limited
|
||||
per query), Vestige keeps a durable embedded index: searchable **offline**,
|
||||
**semantically**, joinable with the rest of your memory, temporally versioned,
|
||||
and re-syncable **idempotently** with no duplication. To our knowledge no other
|
||||
local-first memory layer combines native connectors, external-URL provenance,
|
||||
content-hash idempotent sync, and tombstoning of vanished records.
|
||||
|
||||
### Added
|
||||
|
||||
- **`source_sync` MCP tool** — index an external system into Vestige.
|
||||
- GitHub: `{"source": "github", "repo": "owner/name"}` indexes every issue +
|
||||
its comments. Auth via `GITHUB_TOKEN` (public repos work tokenless at a
|
||||
lower rate limit).
|
||||
- Redmine: `{"source": "redmine", "project": "<id>"}` indexes a project's
|
||||
issues + journals (comments and status/assignment history). Host from
|
||||
`REDMINE_URL`, auth from `REDMINE_API_KEY`.
|
||||
- Re-running updates changed issues in place (no duplicates); `reconcile:
|
||||
true` tombstones issues no longer visible upstream.
|
||||
- **Source-aware investigation filters on `search`** (Phase 4) — filter results
|
||||
by `source_system`, `source_project`, `source_id`, `source_type`,
|
||||
`source_author`, a `source_updated_after`/`source_updated_before` date range,
|
||||
and `source_status` (`valid` / `tombstoned` / `any`). Status, tracker, and
|
||||
priority remain filterable via the existing `tag_prefix` (the connectors emit
|
||||
`status:`/`tracker:`/`priority:`/`label:` tags). Applied as post-filters;
|
||||
non-connector memories are excluded from a source-scoped query.
|
||||
- **Source envelope** on every memory — structured, machine-readable provenance
|
||||
(`source_system`, `source_id`, `source_url`, `source_updated_at`,
|
||||
`content_hash`, `synced_at`, `source_project`, `source_type`, `source_author`)
|
||||
distinct from the legacy free-form `source` label. Search results gain a
|
||||
`sourceRecord` object (with the canonical `url`) **only** for
|
||||
connector-ingested memories, so an agent can cite and follow the source.
|
||||
- **Idempotent sync primitives** (`vestige-core`): `upsert_by_source` (keyed on
|
||||
`(source_system, source_id)`, content-hash change detection), per-connector
|
||||
cursor checkpoints (`connector_cursors`), and `reconcile_source_tombstones`
|
||||
(invalidate-don't-delete via the bitemporal `valid_until`, so a vanished
|
||||
record is retained for audit but drops out of current retrieval).
|
||||
- **Connector contract** (`vestige_core::connectors`) — a small source-agnostic
|
||||
`Connector` trait + `run_sync` driver (cursor overlap window, incremental
|
||||
paging, optional deletion reconcile) with two reference connectors behind the
|
||||
optional `connectors` cargo feature (on by default in the MCP server, off in
|
||||
the core library's default features so non-connector consumers link no HTTP
|
||||
client):
|
||||
- **GitHub Issues** — `state=all`, `since` cursor, Link-header pagination,
|
||||
drops PRs, host-pinned next-url.
|
||||
- **Redmine** — `status_id=*` (open + closed), hex-encoded `updated_on>=`
|
||||
cursor, `offset` pagination, per-issue detail fetch for journals (the list
|
||||
endpoint omits them), `X-Redmine-API-Key` header auth.
|
||||
|
||||
### Database
|
||||
|
||||
- **Migration V17** — nine nullable source-envelope columns on `knowledge_nodes`
|
||||
(additive; every existing memory is untouched), a partial UNIQUE index on
|
||||
`(source_system, source_id)` enforcing one memory per external record while
|
||||
costing nothing for envelope-less legacy rows, and the `connector_cursors`
|
||||
checkpoint table. Idempotent on replay, following the established
|
||||
`add_column_if_missing` pattern.
|
||||
|
||||
### Notes
|
||||
|
||||
- Local-first and optional: with no `source_sync` call, behavior is unchanged.
|
||||
The default core-library build does not link an HTTP client.
|
||||
|
||||
## [2.1.26] - 2026-06-15 — "Configurable Output"
|
||||
|
||||
Roadmap **Phase 2: Configurable Output**. Users can now control the default
|
||||
shape and size of high-traffic MCP responses with an optional, local-first
|
||||
config file — without recompiling and without a cloud service. The default
|
||||
behavior is unchanged: a fresh install with no `vestige.toml` behaves exactly
|
||||
as before.
|
||||
|
||||
### Added
|
||||
|
||||
- **`vestige.toml` config file**, loaded from the active Vestige data directory
|
||||
(`<data_dir>/vestige.toml`, alongside `vestige.db`). A missing or malformed
|
||||
file falls back to built-in defaults, so existing installs are unaffected.
|
||||
- **`[defaults]` table** with three keys: `detail_level`
|
||||
(`brief` | `summary` | `full`), `limit` (default result count for
|
||||
high-traffic tools), and `profile`.
|
||||
- **Output profiles** — `lean`, `default`, `audit`, `research` — each presetting
|
||||
a coherent bundle of detail level, result limit, and whether scores and
|
||||
timestamps are included:
|
||||
- `lean`: `brief` detail, limit 5, scores and timestamps dropped (smallest
|
||||
context cost).
|
||||
- `default`: historical behavior — `summary` detail, tool's own default
|
||||
limit, scores and timestamps present. **Unchanged.**
|
||||
- `audit`: `full` detail with every field, score, and timestamp.
|
||||
- `research`: `full` detail with a larger default limit (25).
|
||||
- **Three-layer precedence**, applied per call: an explicit MCP parameter wins
|
||||
over the config file, which wins over the built-in default.
|
||||
- **`profile` field** echoed in `search`, `memory_timeline`, `codebase`
|
||||
(`get_context`), and `session_context` responses so the active profile is
|
||||
observable.
|
||||
|
||||
### Changed
|
||||
|
||||
- `search`, `memory_timeline`, `codebase` (`get_context`), and
|
||||
`session_context` now resolve their default detail level and result limit
|
||||
through the config file when no explicit parameter is supplied. With no
|
||||
`vestige.toml` present, their output is byte-for-byte identical to v2.1.25.
|
||||
|
||||
### Documentation
|
||||
|
||||
- `docs/CONFIGURATION.md` gains a **Output Configuration (`vestige.toml`)**
|
||||
section documenting the file location, `[defaults]` keys, profile presets,
|
||||
and precedence rules.
|
||||
|
||||
## [2.1.25] - 2026-06-12 — "Merge / Supersede Controls"
|
||||
|
||||
v2.1.25 ships Phase 3: diff-previewed, confidence-gated, reversible,
|
||||
self-explaining combine/dedupe/supersede on a never-delete (bitemporal) store.
|
||||
The default is always preview/review — these tools never silently mutate memory.
|
||||
The differentiator is the reversible operation log: every merge/supersede/undo is
|
||||
an auditable, reversible event with provenance ("why did these combine?") — a git
|
||||
reflog for your agent's memory.
|
||||
|
||||
### Added
|
||||
|
||||
- **Seven new MCP tools** for merge/supersede control:
|
||||
- `merge_candidates` — surface likely duplicate/overlapping clusters with
|
||||
confidence scores and the signals behind each (Fellegi-Sunter
|
||||
match/possible/non-match). Read-only.
|
||||
- `plan_merge` — produce a previewable merge PLAN (a diff of combined
|
||||
content/tags/provenance) without applying it.
|
||||
- `plan_supersede` — preview superseding A with B (bitemporal invalidation,
|
||||
audit-preserving) without applying.
|
||||
- `apply_plan` — execute a previously-generated plan id; recorded as a
|
||||
reversible operation.
|
||||
- `merge_undo` — reverse a prior merge/supersede operation, or list the
|
||||
reversible operation log (the "memory reflog").
|
||||
- `protect` — pin a memory so it can never be auto-merged, superseded, or
|
||||
garbage-collected.
|
||||
- `merge_policy` — get/set the per-project Fellegi-Sunter two thresholds
|
||||
(`match_threshold`, `possible_threshold`) and `auto_apply`.
|
||||
- **Bitemporal "invalidate, don't delete" supersede** (Graphiti-style): a
|
||||
superseded memory is kept and stays queryable for audit. It is stamped with
|
||||
`valid_until = now` and a new `superseded_by` lineage pointer, instead of being
|
||||
deleted or merely demoted.
|
||||
- **Reversible operation log** (`merge_operations` table) — every applied
|
||||
merge/supersede records an undo payload and provenance signals so any operation
|
||||
can be reversed, including restoring survivor content/tags and clearing the
|
||||
bitemporal invalidation.
|
||||
- **Fellegi-Sunter two-threshold scoring** for dedup/merge candidates, combining
|
||||
embedding cosine similarity with tag and content-token overlap. Borderline
|
||||
"possible" matches are surfaced for review instead of force-merged.
|
||||
- **Memory protection / pinning** — `protected` column on `knowledge_nodes`;
|
||||
protected memories are excluded from auto-merge/supersede/GC paths.
|
||||
- **Migration V14** adding the `merge_plans` and `merge_operations` tables, the
|
||||
`protected` and `superseded_by` columns on `knowledge_nodes`, and their
|
||||
indexes. Idempotent on replay.
|
||||
- **Docs**: `docs/MERGE_SUPERSEDE.md` describing the design, the bitemporal
|
||||
model, the two-threshold policy, the reversible operation log, and the tool
|
||||
surface.
|
||||
|
||||
### Notes
|
||||
|
||||
- All merge/supersede operations are **opt-in and preview-first**. `apply_plan`
|
||||
requires `confirm=true` for `possible`/`non_match` plans, and only applies
|
||||
`match` plans without confirmation when `merge_policy.auto_apply` is enabled
|
||||
(default off). This deliberately avoids the silent-merge / auto-delete /
|
||||
audit-trail-loss anti-patterns reported against other memory systems.
|
||||
- The merge policy persists per-project and is also overridable via
|
||||
`VESTIGE_MERGE_MATCH_THRESHOLD`, `VESTIGE_MERGE_POSSIBLE_THRESHOLD`, and
|
||||
`VESTIGE_MERGE_AUTO_APPLY` environment variables.
|
||||
|
||||
## [2.1.23] - 2026-05-27 — "Receipt Lock Hardening"
|
||||
|
||||
v2.1.23 hardens the Sanhedrin launch path so Receipt Lock is portable,
|
||||
observable, and precise enough for broader use.
|
||||
|
||||
### Added
|
||||
|
||||
- **Model-agnostic Sanhedrin backend presets** for custom OpenAI-compatible
|
||||
servers, small laptops, Ollama, MLX, vLLM, llama.cpp, hosted APIs, and
|
||||
Anthropic via LiteLLM. Sanhedrin no longer guesses a large default verifier.
|
||||
- **Fail-open telemetry** in `fail-open.jsonl`, plus a dashboard telemetry API
|
||||
and 7-day ambient dashboard counters for vetoes, appeals, and fail-open runs.
|
||||
- **Receipt schema documentation** covering receipt artifacts, appeals, command
|
||||
ledgers, fail-open logs, compatibility rules, and staged-evidence trust
|
||||
boundaries.
|
||||
- **Opt-in CUDA feature flags** for Qwen3 embedding builds on NVIDIA hardware.
|
||||
|
||||
### Changed
|
||||
|
||||
- Receipt Lock strips code fences, inline code, blockquotes, quoted regions, and
|
||||
scoped epistemic hedges before matching verification claims.
|
||||
- Structured transcript tool-use receipts are the default evidence path; loose
|
||||
JSON command scanning now requires `VESTIGE_SANHEDRIN_ALLOW_LOOSE_LEDGER=1`.
|
||||
- Claim-mode sampling now prioritizes higher-severity claims instead of taking
|
||||
the first eight source-order claims.
|
||||
- Hosted Sanhedrin credentials now require `VESTIGE_SANHEDRIN_API_KEY` and are
|
||||
only sent to the configured Sanhedrin endpoint, never to Vestige retrieval.
|
||||
- `smart_ingest` batch mode now defaults to `batchMergePolicy: "force_create"`
|
||||
so caller-separated items stay separate unless callers opt into smart merging.
|
||||
- CUDA-enabled Qwen3 builds now try `Device::new_cuda(0)` before falling back to
|
||||
Metal or CPU.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Standalone dashboard mode now hydrates the cognitive engine for Dream and
|
||||
Deep Reference instead of returning 503s.
|
||||
- `--data-dir` now rejects existing non-directory paths with a clear error.
|
||||
- `vestige-restore` now handles `--help` and `--version` instead of treating
|
||||
them as backup file paths.
|
||||
- Smart ingest merge/update responses now include `previousContent`,
|
||||
`mergedFrom`, and `mergePreview` so callers can inspect mutated memories.
|
||||
- Daily Sanhedrin telemetry now preserves NOTE and CAUTION buckets instead of
|
||||
folding both into PASS.
|
||||
|
||||
## [2.1.22] - 2026-05-25 — "Sanhedrin Receipts"
|
||||
|
||||
v2.1.22 makes the optional Sanhedrin hook quieter and more accountable by
|
||||
turning draft judgment into local, appealable receipts instead of opaque vetoes.
|
||||
|
||||
### Added
|
||||
|
||||
- **Receipt Lock** blocks unsupported verification claims such as "tests passed"
|
||||
unless the current transcript contains a matching successful test, build,
|
||||
lint, or typecheck command receipt.
|
||||
- **Veto receipts** are written to `~/.vestige/sanhedrin/latest.json` and
|
||||
`latest.html` with Claim -> Verdict -> Precedent -> Fix -> Appeal fields.
|
||||
- **Dashboard Verdict Bar** surfaces the latest PASS, NOTE, CAUTION, VETO, or
|
||||
APPEALED state and lets users appeal stale, wrong, or too-strict vetoes.
|
||||
- **Appeal training** records feedback in `appeals.jsonl` and suppresses future
|
||||
vetoes for the same claim fingerprint.
|
||||
|
||||
### Changed
|
||||
|
||||
- Sanhedrin claim-mode output now feeds a per-claim receipt ledger while keeping
|
||||
the existing one-line Stop-hook contract for Claude Code.
|
||||
|
||||
## [2.1.21] - 2026-05-24 — "Agent-Neutral Hardening"
|
||||
|
||||
v2.1.21 is a release-hardening pass for normal MCP usage across agents. It keeps
|
||||
Claude Code Cognitive Sandwich companion files optional while making the MCP
|
||||
server, package installer, release workflow, and portable sync path safer.
|
||||
|
||||
### Added
|
||||
|
||||
- **Agent-neutral memory protocol** — new `docs/AGENT-MEMORY-PROTOCOL.md` gives
|
||||
any MCP-compatible client the same practical memory loop: initialize context,
|
||||
search/deep-reference when needed, save durable facts with `smart_ingest`, and
|
||||
promote/demote/purge with `memory`.
|
||||
- **HTTP transport opt-in** — `vestige-mcp` now requires `--http`,
|
||||
`--http-port`, or `VESTIGE_HTTP_ENABLED=1` before starting MCP-over-HTTP.
|
||||
- **Release checksums** — release assets now publish `.sha256` files beside each
|
||||
archive.
|
||||
|
||||
### Changed
|
||||
|
||||
- **`vestige update` is binary-only by default** — Claude Code Cognitive
|
||||
Sandwich companion files refresh only with `vestige update --sandwich-companion`
|
||||
or `vestige sandwich install`.
|
||||
- **MCP tool results include structured content** while keeping text content for
|
||||
clients that only consume the classic MCP response shape.
|
||||
- **NPM install messaging is agent-neutral** and unsupported release targets
|
||||
fail fast instead of trying to download assets that do not exist.
|
||||
- **Portable merge uses UPSERT instead of `INSERT OR REPLACE`** for keyed tables,
|
||||
preserving related rows instead of causing delete-and-insert side effects.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Destructive delete confirmation** — `memory(action="delete")` now requires
|
||||
`confirm=true`, matching `purge`; the deprecated `delete_knowledge` shim no
|
||||
longer bypasses confirmation.
|
||||
- **Portable purge tombstone sync** — merge imports now carry
|
||||
`deletion_tombstones` and apply purges without retaining deleted memory text.
|
||||
Hard purge tombstones win over newer local edits during portable sync, while
|
||||
tombstone merges keep the newest deletion timestamp.
|
||||
- **Vector index reload staleness** — loading persisted embeddings rebuilds the
|
||||
in-memory index from an empty index before adding current embeddings.
|
||||
- **HTTP transport hardening** — origin, Accept, session, and protocol-version
|
||||
validation now reject incompatible or cross-origin browser requests earlier.
|
||||
- **Init config safety** — `@vestige/init` backs up existing config files, writes
|
||||
atomically, accepts JSONC-style comments/trailing commas, and no longer writes
|
||||
Xcode trust-accepted flags.
|
||||
- **Release tag checkout** — manual release builds now checkout the requested tag
|
||||
or ref before packaging.
|
||||
|
||||
### Verified
|
||||
|
||||
- `cargo test -p vestige-mcp --lib --no-fail-fast`
|
||||
- `cargo test -p vestige-mcp --bin vestige-mcp --no-fail-fast`
|
||||
- `cargo test -p vestige-core portable_merge_import --no-fail-fast`
|
||||
- `cargo test -p vestige-mcp --bin vestige --no-fail-fast`
|
||||
- `cargo test -p vestige-e2e-tests --test mcp_protocol --no-fail-fast`
|
||||
- `cargo check --workspace`
|
||||
- `cargo metadata --format-version 1 --locked --no-deps`
|
||||
- `pnpm --filter @vestige/dashboard check`
|
||||
- `pnpm --filter @vestige/dashboard test`
|
||||
- `pnpm --filter @vestige/dashboard build`
|
||||
- `node --check packages/vestige-init/bin/init.js`
|
||||
- `node --check packages/vestige-mcp-npm/scripts/postinstall.js`
|
||||
- `node --check packages/vestige-mcp-npm/bin/vestige-restore.js`
|
||||
|
||||
## [2.1.2] - 2026-05-01 — "Honest Memory"
|
||||
|
||||
v2.1.2 focuses on operational trust: exact search stays exact, purge really removes content, contradictions are directly inspectable, and the update flow no longer depends on copied curl commands.
|
||||
|
||||
### Added
|
||||
|
||||
- **Concrete search mode** — `search` now auto-detects literal queries such as quoted strings, env vars, UUIDs, paths, and code identifiers. Those queries take a keyword/literal path that skips HyDE, semantic fusion, FSRS reweighting, retrieval competition, and spreading activation so exact matches land first.
|
||||
- **Irreversible purge** — `memory(action="purge", confirm=true)` permanently removes memory content and embeddings, scrubs `insights.source_memories`, detaches temporal-summary children, prunes graph edges, and writes only a non-content `deletion_tombstones` row for sync/audit.
|
||||
- **First-class contradictions tool** — new `contradictions` MCP tool scans a topic or recent memories for trust-weighted disagreements using the same local contradiction logic as `deep_reference`.
|
||||
- **Simple update flow** — `vestige update` refreshes the installed binary and companion Sandwich files without requiring users to paste a curl installer.
|
||||
- **Pro waitlist preview** — `/dashboard/waitlist` adds a local-only marketing surface for Solo Pro and Team Pro early-access signups. `VITE_WAITLIST_ENDPOINT` and `VITE_SUPPORT_BOT_ENDPOINT` are opt-in dashboard env vars, so no signup data is captured unless endpoints are configured.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Dream connection persistence cap** — dense single-domain dreams now persist every connection discovered in that run instead of losing everything beyond the old 1,000-entry live buffer. The live dreamer buffer now keeps up to 200,000 high-scoring recent connections, and the MCP `dream` tool exposes `min_similarity` for corpus-specific tuning.
|
||||
- **Embedding-model upgrade repair** — `vestige consolidate` now re-embeds every missing or active-model-mismatched memory in one pass, so v1/v2 mixed stores are no longer left partially unreachable after only the first 100 legacy embeddings are regenerated.
|
||||
|
||||
## [2.1.1] - 2026-05-01 — "Portable Sync"
|
||||
|
||||
v2.1.1 focuses on user-controlled portability: exact storage archives, merge-safe file sync, pluggable sync backends, and explicit hook opt-ins.
|
||||
|
||||
### Added
|
||||
|
||||
- **Exact portable archives** — `vestige portable-export` / `vestige portable-import` preserve raw Vestige storage rows: memory IDs, FSRS state, graph edges, suppression state, audit rows, sessions, intentions, and embedding blobs.
|
||||
- **Merge-safe imports** — `vestige portable-import --merge` can merge into non-empty databases. It applies `sync_tombstones`, keeps newer local memory rows on timestamp conflicts, preserves stable IDs, and rebuilds FTS after import.
|
||||
- **File-backed two-way sync** — `vestige sync <archive>` performs pull-merge-push through a shared portable archive. This works today with Dropbox, iCloud Drive, Syncthing, Git, network shares, and shared folders.
|
||||
- **Pluggable portable-sync backend trait** — core now exposes `PortableSyncBackend`, `FilePortableSyncBackend`, and `PortableSyncReport`, so non-file backends can reuse the same merge semantics without reimplementing conflict handling.
|
||||
- **Portable restore merge mode** — the MCP `restore` tool accepts `merge: true` for portable archives and returns inserted/updated/deleted/skipped/conflict counts.
|
||||
- **Qwen3 embedding opt-in** — build-time and runtime support for Qwen3 embeddings, with model-aware retrieval safeguards so mixed embedding models are not compared in the same vector path.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Sanhedrin, preflight, and all Vestige Claude Code hooks are optional again.** The Cognitive Sandwich installer now activates no hooks by default and leaves every preflight hook, every Stop hook, the MLX launchd service, and the 19 GB Qwen model path behind explicit `--enable-preflight`, `--enable-sanhedrin`, or `--with-launchd` flags.
|
||||
- **x86-friendly Sanhedrin path.** The verifier bridge now accepts any OpenAI-compatible chat endpoint via `VESTIGE_SANHEDRIN_ENDPOINT` and `VESTIGE_SANHEDRIN_MODEL`, so Linux and Intel Mac users can opt in without MLX or Apple Silicon.
|
||||
|
||||
### Verified
|
||||
|
||||
- `cargo test -p vestige-core portable --no-fail-fast`
|
||||
- `cargo test -p vestige-mcp portable --no-fail-fast`
|
||||
- `cargo test --workspace --no-fail-fast`
|
||||
- Installer shell/Python/JSON validation and default/preflight/Sanhedrin migration dry-runs.
|
||||
|
||||
## [2.1.0] - 2026-04-27 — "Cognitive Sandwich Goes Local"
|
||||
|
||||
v2.1.0 ships the Cognitive Sandwich hook harness for Claude Code, with a hotfix that makes every hook layer opt-in. The default installer stages files, removes old Vestige hook wiring, starts no MLX service, downloads no model, and makes no automatic model calls. Users can opt into preflight context, Sanhedrin verification, or the Apple Silicon MLX backend separately.
|
||||
The Sanhedrin Executioner — Vestige's veto layer for Claude Code responses — can run against a local MLX model (`mlx-community/Qwen3.6-35B-A3B-4bit`) when explicitly enabled. Combined with four pre-cognitive UserPromptSubmit hooks (synthesis-preflight, cwd-state-injector, vestige-pulse-daemon, preflight-swarm), Vestige now ships a complete "Cognitive Sandwich" — Vestige memories injected before the model thinks, optional Sanhedrin veto after the model speaks.
|
||||
|
||||
> 2026-05-01 hotfix: Sanhedrin, preflight, and all Vestige Claude Code hooks are optional by default. The default installer activates no hooks, makes no automatic model calls, removes old Vestige hook wiring from previous v2.1.0 installs, no longer starts MLX, and removes the old v2.1.0 MLX launchd job on reinstall. Users who want preflight can opt in with `--enable-preflight`; users who want Sanhedrin can opt in with `--enable-sanhedrin`; Apple Silicon local MLX autostart is a separate `--with-launchd` flag, and x86 users can point `--sanhedrin-endpoint` at any OpenAI-compatible `/v1/chat/completions` endpoint.
|
||||
|
||||
### Added
|
||||
|
||||
- **`hooks/`** — first-class harness-side companion to the Vestige MCP server. 9 production hooks designed for `~/.claude/hooks/`:
|
||||
- `sanhedrin.sh` — Stop hook that invokes the local Qwen Executioner via the Python bridge.
|
||||
- `sanhedrin-local.py` — local backend that POSTs to `mlx_lm.server` (`localhost:8080`) with Vestige evidence injected via the dashboard `/api/deep_reference` HTTP endpoint. TRUST_FLOOR=0.55 evidence filter + topical-relevance gate + inference-verb ban + 8 worked few-shots covering true positives AND false-positive guards.
|
||||
- `sanhedrin.sh` — optional Stop hook that invokes the Sanhedrin Executioner via the Python bridge only when `VESTIGE_SANHEDRIN_ENABLED=1`.
|
||||
- `sanhedrin-local.py` — OpenAI-compatible backend that POSTs to the configured Sanhedrin endpoint with Vestige evidence injected via the dashboard `/api/deep_reference` HTTP endpoint. TRUST_FLOOR=0.55 evidence filter + topical-relevance gate + inference-verb ban + 8 worked few-shots covering true positives AND false-positive guards.
|
||||
- `synthesis-preflight.sh` — UserPromptSubmit hook that POSTs the user prompt to `/api/deep_reference` and injects the trust-scored reasoning chain into context.
|
||||
- `cwd-state-injector.sh` — captures git status, branch, modified files, open PRs/issues.
|
||||
- `vestige-pulse-daemon.sh` — surfaces fresh Vestige dream insights from the past 20 min.
|
||||
|
|
@ -475,18 +23,21 @@ v2.1.0 ships the Cognitive Sandwich hook harness for Claude Code, with a hotfix
|
|||
- `synthesis-stop-validator.sh` — Stop hook regex against forbidden hedging patterns.
|
||||
- `veto-detector.sh` — fast 50ms regex pre-screen against `veto`-tagged Vestige memories.
|
||||
- `synthesis-gate.sh` — legacy v1 trigger (kept for backward compat).
|
||||
- `settings.fragment.json` — empty default JSON snippet; the installer only wires hooks from the opt-in preflight/Sanhedrin fragments.
|
||||
- `settings.fragment.json` — empty default fragment used to remove old Vestige hook wiring without enabling new hooks.
|
||||
- `settings.preflight.fragment.json` — opt-in UserPromptSubmit hooks used only with `--enable-preflight`.
|
||||
- `settings.sanhedrin.fragment.json` — opt-in JSON snippet used only with `--enable-sanhedrin`.
|
||||
- **Dashboard `/api/changelog` endpoint** — bounded REST event feed for recent `DreamCompleted` and `ConnectionDiscovered` events, used by the Pulse hook to inject fresh synthesis into Claude Code context.
|
||||
- **`agents/`** — `executioner.md` (legacy/fallback Haiku 4.5 path), `lateral-thinker.md`, `synthesis-composer.md`.
|
||||
- **`launchd/com.vestige.mlx-server.plist.template`** — auto-start `mlx_lm.server` with the Qwen3.6-35B-A3B-4bit model on login. Templated with `__HOME__` and `__MODEL__` placeholders.
|
||||
- **`scripts/install-sandwich.sh`** — one-command installer that stages hooks and agents, removes old Vestige hook wiring by default, and only wires optional layers with `--enable-preflight`, `--enable-sanhedrin`, or `--with-launchd`. Backs up `settings.json` to `.bak.pre-sandwich`. Supports `--force`, `--include-memory-loader`, and `--src=PATH`.
|
||||
- **`scripts/check-sandwich-prereqs.sh`** — default verifier confirms no Vestige Claude Code hooks are wired. Optional `--preflight` and `--sanhedrin` modes check the corresponding enabled layer.
|
||||
- **`launchd/com.vestige.mlx-server.plist.template`** — optional Apple Silicon helper that auto-starts `mlx_lm.server` with the Qwen3.6-35B-A3B-4bit model on login. Templated with `__HOME__` and `__MODEL__` placeholders.
|
||||
- **`scripts/install-sandwich.sh`** — one-command installer that stages hooks, agents, jq-merges the settings fragment, and backs up `settings.json` to `.bak.pre-sandwich`. Supports `--force`, `--enable-sanhedrin`, `--with-launchd`, `--sanhedrin-endpoint`, `--sanhedrin-model`, `--include-memory-loader`, `--src=PATH`.
|
||||
- **`scripts/check-sandwich-prereqs.sh`** — verifier that default installs have no Vestige hooks wired, with `--preflight` and `--sanhedrin` checks for optional layers.
|
||||
- **`docs/COGNITIVE_SANDWICH.md`** — architecture diagram, install guide, performance notes (82 tok/s on M3 Max), uninstall, configuration env vars.
|
||||
- **PR #48** — `VESTIGE_DATA_DIR` env-var support + tilde expansion + secure unix perms (thanks @Jelloeater) — directly addresses the ghost env-vars exposed by v2.0.9 cleanup.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Sanhedrin Executioner backend can run locally or remotely when explicitly enabled.** The bridge targets an OpenAI-compatible chat endpoint, with local `mlx_lm.server` + Qwen3.6-35B-A3B-4bit available behind `--with-launchd` on Apple Silicon. Anthropic API key no longer required for the post-cognitive layer. The `executioner.md` agent definition is retained as manual/fallback only when invoked explicitly via `Task(subagent_type='executioner')`.
|
||||
- **Sanhedrin, preflight, and all Vestige Claude Code hooks are optional by default.** Default installs run on x86 and low-memory machines without wiring any Vestige hook, calling Claude, downloading the 19 GB MLX model, or starting MLX. Reinstalling the default v2.1.0 hotfix removes the old Vestige hook wiring and the old mandatory `com.vestige.mlx-server` launchd job if they exist.
|
||||
- **Sanhedrin Executioner backend swapped from Anthropic Haiku 4.5 → OpenAI-compatible endpoint, with local `mlx_lm.server` + Qwen3.6-35B-A3B-4bit as the Apple Silicon opt-in path.** Anthropic API key no longer required for the post-cognitive layer. The `executioner.md` agent definition is retained as manual/fallback only when invoked explicitly via `Task(subagent_type='executioner')`.
|
||||
- **All hooks sanitized for public release** — replaced hardcoded personal absolute paths with `$HOME` / `$VESTIGE_*` env vars; removed personal regex tokens.
|
||||
- **NPM binary installer now follows package version** — `vestige-mcp-server@2.1.0` downloads release assets from `v2.1.0` instead of a stale hardcoded binary tag, while local workspace installs skip the release-asset download before the tag exists.
|
||||
|
||||
|
|
@ -494,23 +45,29 @@ v2.1.0 ships the Cognitive Sandwich hook harness for Claude Code, with a hotfix
|
|||
|
||||
- `cargo test --workspace --release --no-fail-fast`: **1,229 passing, 0 failed** (366 vestige-core + 358 vestige-mcp lib + 4 vestige-mcp bin + 497 e2e + 4 doctests).
|
||||
- Sanhedrin bridge smoke checks: Python bytecode compilation passes, fail-open bridge invocation returns `yes`, and public hook settings validate as JSON.
|
||||
- v2.1.0 hotfix installer matrix: default, preflight-only, Sanhedrin-only, full sandwich, legacy-all-hooks migration, and unrelated custom hooks preservation.
|
||||
- 8-day Sandwich dogfood: **84% pass rate, 16% legitimate vetoes** caught real hallucinations.
|
||||
- 2026-05-01 hotfix checks: `cargo test --workspace --no-fail-fast`, `cargo build --release --workspace`, shell/Python/JSON validation, and default/preflight/Sanhedrin installer dry-runs all pass.
|
||||
|
||||
### Closes
|
||||
|
||||
- #36 (Agent Hooks for Low-Effort Automatic Memory Capture) — Cognitive Sandwich is the answer.
|
||||
|
||||
### Prerequisites for optional local MLX Sanhedrin
|
||||
### Prerequisites for the Cognitive Sandwich
|
||||
|
||||
- macOS Apple Silicon (M1+) — required only for `--with-launchd` MLX autostart
|
||||
- Python 3.10+
|
||||
- `jq`
|
||||
- `vestige-mcp`
|
||||
- Claude Code
|
||||
|
||||
Optional local MLX Sanhedrin backend:
|
||||
|
||||
- macOS Apple Silicon (M1+) — required for the launchd MLX helper only
|
||||
- ~22 GB free RAM (Qwen3.6-35B-A3B-4bit at runtime)
|
||||
- First-run model download: ~19 GB from Hugging Face (cached locally thereafter)
|
||||
|
||||
### Migration
|
||||
|
||||
None required for existing Vestige users. The Cognitive Sandwich is opt-in via `scripts/install-sandwich.sh`; running the default installer removes old Vestige hook wiring and leaves preflight, Sanhedrin, launchd, and the 19 GB model path disabled. The MCP server, schema, and tool surface are bit-identical to v2.0.9.
|
||||
None required for existing Vestige users. The default installer now removes old v2.1.0 Claude Code hook wiring. The Cognitive Sandwich hook layers are opt-in via `--enable-preflight`, `--enable-sanhedrin`, or `--enable-sandwich`. The MCP server, schema, and tool surface are bit-identical to v2.0.9.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
411
CLAUDE.md
411
CLAUDE.md
|
|
@ -1,89 +1,362 @@
|
|||
# 🚀 MANDATE #0 — MAXIMUM AMBITION. NO HEDGING. (read this first, every time)
|
||||
# 🚫 READ FIRST EVERY PROMPT — NO HEDGING
|
||||
|
||||
This is the standing default for ALL work on Vestige, before anything else below.
|
||||
Sam's April 20 2026 correction: *"you NEVER LISTEN TO YOUR RULES, WHY ARE YOU ALWAYS BREAKING THE HEDGING/PESSIMISTIC RULE."*
|
||||
|
||||
- **Assume maximum ambition.** Build the most exhaustive, jaw-dropping, correct
|
||||
version — not the safe "good enough" one. The ceiling is "nobody else has
|
||||
this," not "this works." Default to the winning move, not the cautious one.
|
||||
- **Scour before you settle.** When unsure or stuck, research the real frontier
|
||||
(web, source, the actual running app) before acting. Never accept the first
|
||||
adequate answer when a deeper one exists. Verify, don't assume.
|
||||
- **No hedging.** Lead with the best path and a clear recommendation. Forbidden:
|
||||
"this is probably too risky," "temper expectations," "good enough," "maybe try
|
||||
the easier one." Risks get their own honest section — never used to shrink the
|
||||
target.
|
||||
- **Show proof.** Verify changes in the real running app and share the evidence
|
||||
(screenshots, test output, gate results) — don't claim done without it.
|
||||
- **Protect what's flawless, detonate what isn't.** Treat finished, loved work as
|
||||
load-bearing (don't break it); push everything else past where any other dev
|
||||
would stop.
|
||||
When Sam commits to an execution path (content cadence, shipping velocity, outreach, launch), COMPUTE THE FORECAST AS IF THAT COMMITMENT IS MET. Do not discount by execution probability. Sam has earned the benefit of the doubt across 139 commits and 1,292 passing tests in 3 months.
|
||||
|
||||
Origin: Sam, Jun 22 2026 — the overnight session that turned the dashboard +
|
||||
Memory Cinema from "alive" into a category-of-one particle journey. The depth
|
||||
only happened because the bar was set to maximum. Make that the default, not the
|
||||
exception.
|
||||
**Forbidden in any response**: "has to be true", "has to convert", "realistic forecast" used to shrink, "contingent on" Sam's own execution, "not guaranteed", "may or may not", "aspiration not forecast", "temper your expectations", floors framed as reality vs. ceilings framed as fantasy.
|
||||
|
||||
**Required format for forecasts**: `Target X. Floor Y. Ceiling Z. Math: [line items]. Risks: [separate section]. Let's go.`
|
||||
|
||||
Full rule: `/Users/entity002/CLAUDE.md` (top banner) + `/Users/entity002/.claude/projects/-Users-entity002/memory/feedback_always_positive_energy.md`. Stop-hook enforcement: `/Users/entity002/.claude/hooks/synthesis-stop-validator.sh`.
|
||||
|
||||
---
|
||||
|
||||
# Vestige Agent Guidance
|
||||
# Vestige v2.0.4 — Cognitive Memory & Reasoning System
|
||||
|
||||
This file is intentionally safe for the public repository. It gives coding
|
||||
agents project-specific context without relying on private local files,
|
||||
personal operating notes, or mandatory background hooks.
|
||||
Vestige is your long-term memory AND reasoning engine. 29 stateful cognitive modules implement real neuroscience: FSRS-6 spaced repetition, synaptic tagging, prediction error gating, hippocampal indexing, spreading activation, reconsolidation, and dual-strength memory theory. **Use it automatically. Use it aggressively.**
|
||||
|
||||
## Project Shape
|
||||
**NEW: `deep_reference` — call this for ALL factual questions.** It doesn't just retrieve — it REASONS across memories with FSRS-6 trust scoring, intent classification, contradiction analysis, and generates a pre-built reasoning chain. Read the `reasoning` field FIRST.
|
||||
|
||||
Vestige is a local-first MCP memory server written in Rust, with a SvelteKit
|
||||
dashboard embedded into the release binary. The core product promise is:
|
||||
---
|
||||
|
||||
- user-owned memory stored locally by default
|
||||
- MCP-native integration with coding agents
|
||||
- retrieval and memory lifecycle behavior informed by cognitive science
|
||||
- explicit tools for search, review, suppression, purge, graph exploration,
|
||||
contradiction inspection, and maintenance
|
||||
## Session Start Protocol
|
||||
|
||||
## Working Rules
|
||||
Every conversation, before responding to the user:
|
||||
|
||||
- Prefer source evidence over memory. Use `rg`, tests, and nearby code before
|
||||
making claims about behavior.
|
||||
- Keep release changes scoped. Do not rewrite unrelated modules during a
|
||||
version/tag cleanup unless the release gate requires it.
|
||||
- Preserve local-first behavior. Heavy models, Sanhedrin-style verifier hooks,
|
||||
and preflight automation must remain optional.
|
||||
- Treat deletion semantics carefully. `purge` must remove content and
|
||||
embeddings, while retaining only content-free audit tombstones.
|
||||
- Treat exact lookup semantics carefully. Env vars, paths, UUIDs, quoted
|
||||
strings, and code identifiers should not be distorted by semantic expansion.
|
||||
|
||||
## Common Checks
|
||||
|
||||
Run the narrowest check that covers the change, then run the release gates
|
||||
before tagging:
|
||||
|
||||
```sh
|
||||
cargo test --workspace --no-fail-fast
|
||||
cargo clippy --workspace -- -D warnings
|
||||
pnpm --filter @vestige/dashboard check
|
||||
pnpm --filter @vestige/dashboard build
|
||||
```
|
||||
session_context({
|
||||
queries: ["user preferences", "[current project] context"],
|
||||
context: { codebase: "[project]", topics: ["[current topics]"] },
|
||||
token_budget: 2000
|
||||
})
|
||||
```
|
||||
|
||||
For documentation-only changes, at minimum run:
|
||||
Then check `automationTriggers` from response:
|
||||
- `needsDream` → call `dream` (consolidates memories, discovers hidden connections)
|
||||
- `needsBackup` → call `backup`
|
||||
- `needsGc` → call `gc(dry_run: true)` then review
|
||||
- totalMemories > 700 → call `find_duplicates`
|
||||
|
||||
```sh
|
||||
git diff --check
|
||||
Say "Remembering..." then retrieve context before answering.
|
||||
|
||||
> **Fallback:** If `session_context` unavailable: `search` × 2 → `intention` check → `system_status` → `predict`.
|
||||
|
||||
---
|
||||
|
||||
## Complete Tool Reference (23 Tools)
|
||||
|
||||
### session_context — One-Call Initialization
|
||||
```
|
||||
session_context({
|
||||
queries: ["user preferences", "project context"], // search queries
|
||||
context: { codebase: "project-name", topics: ["svelte", "rust"], file: "src/main.rs" },
|
||||
token_budget: 2000, // 100-100000, controls response size
|
||||
include_status: true, // system health
|
||||
include_intentions: true, // triggered reminders
|
||||
include_predictions: true // proactive memory predictions
|
||||
})
|
||||
```
|
||||
Returns: markdown context + `automationTriggers` + `expandable` IDs for on-demand retrieval.
|
||||
|
||||
### smart_ingest — Save Anything
|
||||
**Single mode** — auto-decides CREATE/UPDATE/SUPERSEDE via Prediction Error Gating:
|
||||
```
|
||||
smart_ingest({
|
||||
content: "What to remember",
|
||||
tags: ["tag1", "tag2"],
|
||||
node_type: "fact", // fact|concept|event|person|place|note|pattern|decision
|
||||
source: "optional reference",
|
||||
forceCreate: false // bypass dedup when needed
|
||||
})
|
||||
```
|
||||
**Batch mode** — save up to 20 items in one call (session end, pre-compaction):
|
||||
```
|
||||
smart_ingest({
|
||||
items: [
|
||||
{ content: "Item 1", tags: ["session-end"], node_type: "fact" },
|
||||
{ content: "Item 2", tags: ["bug-fix"], node_type: "fact" }
|
||||
]
|
||||
})
|
||||
```
|
||||
Each item runs the full cognitive pipeline: importance scoring → intent detection → synaptic tagging → hippocampal indexing → PE gating → cross-project recording.
|
||||
|
||||
### search — 7-Stage Cognitive Search
|
||||
```
|
||||
search({
|
||||
query: "search query",
|
||||
limit: 10, // 1-100
|
||||
min_retention: 0.0, // filter by retention strength
|
||||
min_similarity: 0.5, // minimum cosine similarity
|
||||
detail_level: "summary", // brief|summary|full
|
||||
context_topics: ["rust", "debugging"], // boost topic-matching memories
|
||||
token_budget: 3000, // 100-100000, truncate to fit
|
||||
retrieval_mode: "balanced" // precise|balanced|exhaustive (v2.1)
|
||||
})
|
||||
```
|
||||
Retrieval modes: `precise` (fast, no activation/competition), `balanced` (default 7-stage pipeline), `exhaustive` (5x overfetch, deep graph traversal, no competition suppression).
|
||||
|
||||
Pipeline: Overfetch → Rerank (cross-encoder) → Temporal boost → Accessibility filter (FSRS-6) → Context match (Tulving 1973) → Competition (Anderson 1994) → Spreading activation. **Every search strengthens the memories it finds (Testing Effect).**
|
||||
|
||||
### memory — Read, Edit, Delete, Promote, Demote
|
||||
```
|
||||
memory({ action: "get", id: "uuid" }) // full node with all FSRS state
|
||||
memory({ action: "edit", id: "uuid", content: "updated text" }) // preserves FSRS state, regenerates embedding
|
||||
memory({ action: "delete", id: "uuid" })
|
||||
memory({ action: "promote", id: "uuid", reason: "was helpful" }) // +0.20 retrieval, +0.10 retention, 1.5x stability
|
||||
memory({ action: "demote", id: "uuid", reason: "was wrong" }) // -0.30 retrieval, -0.15 retention, 0.5x stability
|
||||
memory({ action: "state", id: "uuid" }) // Active/Dormant/Silent/Unavailable + accessibility score
|
||||
memory({ action: "get_batch", ids: ["uuid1", "uuid2", "uuid3"] }) // retrieve up to 20 full memories at once (v2.1)
|
||||
```
|
||||
Promote/demote does NOT delete — it adjusts ranking. Demoted memories rank lower; alternatives surface instead.
|
||||
`get_batch` is designed for batch retrieval of expandable overflow IDs from search/session_context.
|
||||
|
||||
### codebase — Code Patterns & Architectural Decisions
|
||||
```
|
||||
codebase({ action: "remember_pattern", name: "Pattern Name",
|
||||
description: "How it works and when to use it",
|
||||
files: ["src/file.rs"], codebase: "project-name" })
|
||||
|
||||
codebase({ action: "remember_decision", decision: "What was decided",
|
||||
rationale: "Why", alternatives: ["Option A", "Option B"],
|
||||
files: ["src/file.rs"], codebase: "project-name" })
|
||||
|
||||
codebase({ action: "get_context", codebase: "project-name", limit: 10 })
|
||||
// Returns: patterns, decisions, cross-project insights
|
||||
```
|
||||
|
||||
## Documentation
|
||||
### intention — Prospective Memory (Reminders)
|
||||
```
|
||||
intention({ action: "set", description: "What to do",
|
||||
trigger: { type: "context", topic: "authentication" }, // fires when discussing auth
|
||||
priority: "high" })
|
||||
|
||||
- User setup: `README.md`
|
||||
- Claude-specific templates: `docs/CLAUDE-SETUP.md`
|
||||
- Storage and sync behavior: `docs/STORAGE.md`
|
||||
- Cognitive Sandwich and optional verifier hooks: `docs/COGNITIVE_SANDWICH.md`
|
||||
- Release history: `CHANGELOG.md`
|
||||
intention({ action: "set", description: "Deploy by Friday",
|
||||
trigger: { type: "time", at: "2026-03-07T17:00:00Z" },
|
||||
deadline: "2026-03-07T17:00:00Z" })
|
||||
|
||||
## Public-Repo Hygiene
|
||||
intention({ action: "set", description: "Check test coverage",
|
||||
trigger: { type: "context", codebase: "vestige", file_pattern: "*.test.*" } })
|
||||
|
||||
Do not commit private absolute paths, local agent memory paths, unpublished
|
||||
planning files, real credentials, personal operating notes, or private repo
|
||||
locations. Example environment variables in docs must be empty placeholders or
|
||||
obviously fake examples.
|
||||
intention({ action: "check", context: { codebase: "vestige", topics: ["testing"] } })
|
||||
intention({ action: "update", id: "uuid", status: "complete" })
|
||||
intention({ action: "list", filter_status: "active" })
|
||||
```
|
||||
|
||||
### dream — Memory Consolidation
|
||||
```
|
||||
dream({ memory_count: 50 })
|
||||
```
|
||||
5-stage cycle: Replay → Cross-reference → Strengthen → Prune → Transfer. Uses Waking SWR tagging (70% tagged + 30% random for diversity). Discovers hidden connections, generates insights, persists new edges to the activation network.
|
||||
|
||||
### explore_connections — Graph Traversal
|
||||
```
|
||||
explore_connections({ action: "associations", from: "uuid", limit: 10 })
|
||||
// Spreading activation from a memory — find related memories via graph traversal
|
||||
|
||||
explore_connections({ action: "chain", from: "uuid-A", to: "uuid-B" })
|
||||
// Build reasoning path between two memories (A*-like pathfinding)
|
||||
|
||||
explore_connections({ action: "bridges", from: "uuid-A", to: "uuid-B" })
|
||||
// Find connecting memories that bridge two concepts
|
||||
```
|
||||
|
||||
### predict — Proactive Retrieval
|
||||
```
|
||||
predict({ context: { codebase: "vestige", current_file: "src/main.rs",
|
||||
current_topics: ["error handling", "rust"] } })
|
||||
```
|
||||
Returns: predictions with confidence, suggestions, speculative retrievals, top interests. Uses SpeculativeRetriever's learned patterns from access history.
|
||||
|
||||
### importance_score — Should I Save This?
|
||||
```
|
||||
importance_score({ content: "Content to evaluate",
|
||||
context_topics: ["debugging"], project: "vestige" })
|
||||
```
|
||||
4-channel model: novelty (0.25), arousal (0.30), reward (0.25), attention (0.20). Composite > 0.6 = save it.
|
||||
|
||||
### find_duplicates — Dedup Memory
|
||||
```
|
||||
find_duplicates({ similarity_threshold: 0.80, limit: 20, tags: ["bug-fix"] })
|
||||
```
|
||||
Cosine similarity clustering. Returns merge/review suggestions.
|
||||
|
||||
### memory_timeline — Chronological Browse
|
||||
```
|
||||
memory_timeline({ start: "2026-02-01", end: "2026-03-01",
|
||||
node_type: "decision", tags: ["vestige"], limit: 50, detail_level: "summary" })
|
||||
```
|
||||
|
||||
### memory_changelog — Audit Trail
|
||||
```
|
||||
memory_changelog({ memory_id: "uuid", limit: 20 }) // per-memory history
|
||||
memory_changelog({ start: "2026-03-01", limit: 20 }) // system-wide
|
||||
```
|
||||
|
||||
### memory_health — Retention Dashboard
|
||||
```
|
||||
memory_health()
|
||||
```
|
||||
Returns: avg retention, distribution buckets (0-20%, 20-40%, etc.), trend (improving/declining/stable), recommendation.
|
||||
|
||||
### memory_graph — Visualization Export
|
||||
```
|
||||
memory_graph({ query: "search term", depth: 2, max_nodes: 50 })
|
||||
memory_graph({ center_id: "uuid", depth: 3, max_nodes: 100 })
|
||||
```
|
||||
Returns nodes with force-directed positions + edges with weights.
|
||||
|
||||
### deep_reference — Cognitive Reasoning Engine (v2.0.4) ★ USE THIS FOR ALL FACTUAL QUESTIONS
|
||||
```
|
||||
deep_reference({ query: "What port does the dev server use?" })
|
||||
deep_reference({ query: "Should I use prefix caching with vLLM?", depth: 30 })
|
||||
```
|
||||
**THE killer tool.** 8-stage cognitive reasoning pipeline:
|
||||
1. Broad retrieval + cross-encoder reranking
|
||||
2. Spreading activation expansion (finds connected memories search misses)
|
||||
3. FSRS-6 trust scoring (retention × stability × reps ÷ lapses)
|
||||
4. Intent classification (FactCheck / Timeline / RootCause / Comparison / Synthesis)
|
||||
5. Temporal supersession (newer high-trust replaces older)
|
||||
6. Trust-weighted contradiction analysis (only flags conflicts between strong memories)
|
||||
7. Relation assessment (Supports / Contradicts / Supersedes / Irrelevant per pair)
|
||||
8. **Template reasoning chain** — pre-built natural language reasoning the AI validates
|
||||
|
||||
Parameters: `query` (required), `depth` (5-50, default 20).
|
||||
|
||||
Returns: `intent`, `reasoning` (THE KEY FIELD — read this first), `recommended` (highest-trust answer), `evidence` (trust-sorted), `contradictions`, `superseded`, `evolution`, `related_insights`, `confidence`.
|
||||
|
||||
`cross_reference` is a backward-compatible alias that calls `deep_reference`.
|
||||
|
||||
### Maintenance Tools
|
||||
```
|
||||
system_status() // health + stats + warnings + recommendations
|
||||
consolidate() // FSRS-6 decay cycle + embedding generation
|
||||
backup() // SQLite backup → ~/.vestige/backups/
|
||||
export({ format: "json", tags: ["bug-fix"], since: "2026-01-01" })
|
||||
gc({ min_retention: 0.1, dry_run: true }) // garbage collect (dry_run first!)
|
||||
restore({ path: "/path/to/backup.json" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mandatory Save Gates
|
||||
|
||||
**You MUST NOT proceed past a save gate without executing the save.**
|
||||
|
||||
| Gate | Trigger | Action |
|
||||
|------|---------|--------|
|
||||
| **BUG_FIX** | After any error is resolved | `smart_ingest({ content: "BUG FIX: [error]\nRoot cause: [why]\nSolution: [fix]\nFiles: [paths]", tags: ["bug-fix", "project"], node_type: "fact" })` |
|
||||
| **DECISION** | After any architectural/design choice | `codebase({ action: "remember_decision", decision, rationale, alternatives, files, codebase })` |
|
||||
| **CODE_CHANGE** | After >20 lines or new pattern | `codebase({ action: "remember_pattern", name, description, files, codebase })` |
|
||||
| **SESSION_END** | Before stopping or compaction | `smart_ingest({ items: [{ content: "SESSION: [summary]", tags: ["session-end"] }] })` |
|
||||
|
||||
---
|
||||
|
||||
## Trigger Words — Auto-Save
|
||||
|
||||
| User Says | Action |
|
||||
|-----------|--------|
|
||||
| "Remember this" / "Don't forget" | `smart_ingest` immediately |
|
||||
| "I always..." / "I never..." / "I prefer..." | Save as preference |
|
||||
| "This is important" | `smart_ingest` + `memory(action="promote")` |
|
||||
| "Remind me..." / "Next time..." | `intention({ action: "set" })` |
|
||||
|
||||
---
|
||||
|
||||
## Cognitive Architecture
|
||||
|
||||
### Search Pipeline (7 stages)
|
||||
1. **Overfetch** — 3x results from hybrid search (0.3 BM25 + 0.7 semantic, nomic-embed-text-v1.5 768D)
|
||||
2. **Rerank** — Cross-encoder rescoring (Jina Reranker v1 Turbo, 38M params)
|
||||
3. **Temporal** — Recency + validity window boosting (85% relevance + 15% temporal)
|
||||
4. **Accessibility** — FSRS-6 retention filter (Active ≥0.7, Dormant ≥0.4, Silent ≥0.1)
|
||||
5. **Context** — Tulving 1973 encoding specificity (topic overlap → +30% boost)
|
||||
6. **Competition** — Anderson 1994 retrieval-induced forgetting (winners strengthen, competitors weaken)
|
||||
7. **Activation** — Spreading activation side effects + predictive model + reconsolidation marking
|
||||
|
||||
### Ingest Pipeline
|
||||
**Pre:** 4-channel importance scoring (novelty/arousal/reward/attention) + intent detection → auto-tag
|
||||
**Store:** Prediction Error Gating: similarity >0.92 → UPDATE, 0.75-0.92 → UPDATE/SUPERSEDE, <0.75 → CREATE
|
||||
**Post:** Synaptic tagging (Frey & Morris 1997, 9h backward + 2h forward) + hippocampal indexing + cross-project recording
|
||||
|
||||
### FSRS-6 (State-of-the-Art Spaced Repetition)
|
||||
- Retrievability: `R = (1 + factor × t / S)^(-w20)` — 21 trained parameters
|
||||
- Dual-strength model (Bjork & Bjork 1992): storage strength (grows) + retrieval strength (decays)
|
||||
- Accessibility = retention×0.5 + retrieval×0.3 + storage×0.2
|
||||
- 20-30% more efficient than SM-2 (Anki)
|
||||
|
||||
### 29 Cognitive Modules (stateful, persist across calls)
|
||||
|
||||
**Neuroscience (16):**
|
||||
ActivationNetwork (Collins & Loftus 1975), SynapticTaggingSystem (Frey & Morris 1997), HippocampalIndex (Teyler & Rudy 2007), ContextMatcher (Tulving 1973), AccessibilityCalculator, CompetitionManager (Anderson 1994), StateUpdateService, ImportanceSignals, NoveltySignal, ArousalSignal, RewardSignal, AttentionSignal, EmotionalMemory (Brown & Kulik 1977), PredictiveMemory, ProspectiveMemory, IntentionParser
|
||||
|
||||
**Advanced (11):**
|
||||
ImportanceTracker, ReconsolidationManager (Nader — 5min labile window), IntentDetector (9 intent types), ActivityTracker, MemoryDreamer (5-stage consolidation), MemoryChainBuilder (A*-like), MemoryCompressor (30-day min age), CrossProjectLearner (6 pattern types), AdaptiveEmbedder, SpeculativeRetriever (6 trigger types), ConsolidationScheduler
|
||||
|
||||
**Search (2):** Reranker, TemporalSearcher
|
||||
|
||||
### Memory States
|
||||
- **Active** (retention ≥ 0.7) — easily retrievable
|
||||
- **Dormant** (≥ 0.4) — retrievable with effort
|
||||
- **Silent** (≥ 0.1) — difficult, needs cues
|
||||
- **Unavailable** (< 0.1) — needs reinforcement
|
||||
|
||||
### Connection Types
|
||||
semantic, temporal, causal, spatial, part_of, user_defined — each with strength (0-1), activation_count, timestamps
|
||||
|
||||
---
|
||||
|
||||
## Advanced Techniques
|
||||
|
||||
### Cross-Project Intelligence
|
||||
The CrossProjectLearner tracks patterns across ALL projects (ErrorHandling, AsyncConcurrency, Testing, Architecture, Performance, Security). When you learn a pattern in one project that works, it becomes available in all projects. Use `codebase({ action: "get_context" })` without a codebase filter to get universal patterns.
|
||||
|
||||
### Reconsolidation Window
|
||||
After any memory is accessed (via search, get, or promote), it enters a 5-minute "labile" state where modifications are enhanced. This is the optimal time to edit memories with new context. The system handles this automatically.
|
||||
|
||||
### Synaptic Tagging (Retroactive Importance)
|
||||
Memories encoded in the last 9 hours can be retroactively promoted when something important happens. If you fix a critical bug, not only does the fix get saved — related memories from the past 9 hours also get importance boosts. The SynapticTaggingSystem handles this automatically.
|
||||
|
||||
### Dream Insights
|
||||
Dreams don't just consolidate — they generate new insights by cross-referencing recent memories with older knowledge. The insights can reveal: contradictions between memories, previously unseen patterns, connections across different projects. Always check dream results for `insights_generated`.
|
||||
|
||||
### Token Budget Strategy
|
||||
Use `token_budget` on search and session_context to control response size. For quick lookups: 500. For deep context: 3000-5000. Results that don't fit go to `expandable` — retrieve them with `memory({ action: "get", id: "..." })`.
|
||||
|
||||
### Detail Levels
|
||||
- `brief` — id/type/tags/score only (1-2 tokens per result, good for scanning)
|
||||
- `summary` — 8 fields including content preview (default, balanced)
|
||||
- `full` — all FSRS state, timestamps, embedding info (for debugging/analysis)
|
||||
|
||||
---
|
||||
|
||||
## Memory Hygiene
|
||||
|
||||
**Promote** when user confirms helpful, solution worked, info was accurate.
|
||||
**Demote** when user corrects mistake, info was wrong, led to bad outcome.
|
||||
**Never save:** secrets, API keys, passwords, temporary debugging state, trivial info.
|
||||
|
||||
---
|
||||
|
||||
## The One Rule
|
||||
|
||||
**When in doubt, save. The cost of a duplicate is near zero (Prediction Error Gating handles dedup). The cost of lost knowledge is permanent.**
|
||||
|
||||
Memory is retrieval. Searching strengthens memory. Search liberally, save aggressively.
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
- **Crate:** `vestige-mcp` v2.0.4, Rust 2024 edition, MSRV 1.91
|
||||
- **Tests:** 758 (406 mcp + 352 core), zero warnings
|
||||
- **Build:** `cargo build --release -p vestige-mcp` (features: `embeddings` + `vector-search`)
|
||||
- **Build (no embeddings):** `cargo build --release -p vestige-mcp --no-default-features`
|
||||
- **Bench:** `cargo bench -p vestige-core`
|
||||
- **Architecture:** `McpServer` → `Arc<Storage>` + `Arc<Mutex<CognitiveEngine>>`
|
||||
- **Storage:** SQLite WAL mode, `Mutex<Connection>` reader/writer split, FTS5 full-text search
|
||||
- **Embeddings:** nomic-embed-text-v1.5 (768D, 8K context) via fastembed (local ONNX, no API)
|
||||
- **Vector index:** USearch HNSW (20x faster than FAISS)
|
||||
- **Binaries:** `vestige-mcp` (MCP server), `vestige` (CLI), `vestige-restore`
|
||||
- **Dashboard:** SvelteKit 2 + Svelte 5 + Three.js + Tailwind 4, embedded at `/dashboard`
|
||||
- **Env vars:** `VESTIGE_DASHBOARD_PORT` (default 3927), `VESTIGE_HTTP_PORT` (default 3928), `VESTIGE_HTTP_BIND` (default 127.0.0.1), `VESTIGE_AUTH_TOKEN` (auto-generated), `VESTIGE_CONSOLIDATION_INTERVAL_HOURS` (default 6), `RUST_LOG`
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ Tags: ["decision", "topic-name"]
|
|||
| "Don't forget" | `smart_ingest` with tags: ["important"] |
|
||||
| "I always..." / "I never..." | Save as preference |
|
||||
| "I prefer..." / "I like..." | Save as preference |
|
||||
| "This is important" | `smart_ingest` + `memory(action="promote")` |
|
||||
| "This is important" | `smart_ingest` + `promote_memory` |
|
||||
| "Remind me..." | Create `intention` with trigger |
|
||||
| "Next time we..." | Create `intention` with context trigger |
|
||||
| "When I'm working on X..." | Create `intention` with codebase trigger |
|
||||
|
|
@ -115,7 +115,7 @@ Act on feedback immediately — don't ask permission to promote/demote.
|
|||
|
||||
### Proactive Health Checks
|
||||
If you notice degraded recall or a user mentions memory issues:
|
||||
1. Run `system_status` — check overall system status
|
||||
1. Run `health_check` — check overall system status
|
||||
2. If `averageRetention < 0.5` → suggest running `consolidate`
|
||||
3. If `dueForReview > 50` → mention that some memories need review
|
||||
|
||||
|
|
|
|||
453
Cargo.lock
generated
453
Cargo.lock
generated
|
|
@ -8,16 +8,6 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
|
|
@ -153,24 +143,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures 0.2.17",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
|
|
@ -339,29 +311,6 @@ dependencies = [
|
|||
"core2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"cpufeatures 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
|
@ -443,10 +392,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6bd9895436c1ba5dc1037a19935d084b838db066ff4e15ef7dded020b7c12a4a"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"candle-kernels",
|
||||
"candle-metal-kernels",
|
||||
"candle-ug",
|
||||
"cudarc 0.19.7",
|
||||
"float8",
|
||||
"gemm 0.19.0",
|
||||
"half",
|
||||
|
|
@ -466,15 +413,6 @@ dependencies = [
|
|||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "candle-kernels"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "742e2ac226b777134436e9e692f44e77c278b8a7abb1554dc10e44dc911b349f"
|
||||
dependencies = [
|
||||
"cudaforge",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "candle-metal-kernels"
|
||||
version = "0.10.2"
|
||||
|
|
@ -515,7 +453,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ca0fc3167cbc99c8ec1be618cb620aa21dca95038f118c3579a79370e3dc5f77"
|
||||
dependencies = [
|
||||
"ug",
|
||||
"ug-cuda",
|
||||
"ug-metal",
|
||||
]
|
||||
|
||||
|
|
@ -552,36 +489,6 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"chacha20",
|
||||
"cipher",
|
||||
"poly1305",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.44"
|
||||
|
|
@ -623,17 +530,6 @@ dependencies = [
|
|||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.0"
|
||||
|
|
@ -734,12 +630,6 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
|
@ -795,15 +685,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
|
|
@ -887,50 +768,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cudaforge"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f7a0d45b139b5beeeb1c34188717e12241c44a0120afb498815ce7f5373c691"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fs2",
|
||||
"glob",
|
||||
"num_cpus",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror 2.0.18",
|
||||
"walkdir",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cudarc"
|
||||
version = "0.17.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf99ab37ee7072d64d906aa2dada9a3422f1d975cdf8c8055a573bc84897ed8"
|
||||
dependencies = [
|
||||
"half",
|
||||
"libloading 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cudarc"
|
||||
version = "0.19.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cea5f10a99e025c1b44ae2354c2d8326b25ddbd0baf76bde8e55cfd4018a2cc"
|
||||
dependencies = [
|
||||
"float8",
|
||||
"half",
|
||||
"libloading 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.194"
|
||||
|
|
@ -1092,7 +932,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1195,12 +1034,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_home"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
|
|
@ -1421,16 +1254,6 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
|
|
@ -1447,7 +1270,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1756,10 +1578,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1769,11 +1589,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi 5.3.0",
|
||||
"wasip2",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1814,12 +1632,6 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.13"
|
||||
|
|
@ -2011,7 +1823,6 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"webpki-roots 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2298,15 +2109,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interpolate_name"
|
||||
version = "0.2.4"
|
||||
|
|
@ -2406,10 +2208,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.91"
|
||||
version = "0.3.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
|
||||
checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
|
@ -2608,12 +2412,6 @@ dependencies = [
|
|||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||
|
||||
[[package]]
|
||||
name = "lzma-rust2"
|
||||
version = "0.15.7"
|
||||
|
|
@ -3090,12 +2888,6 @@ version = "11.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.3.3"
|
||||
|
|
@ -3221,17 +3013,6 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
|
|
@ -3318,17 +3099,6 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||
dependencies = [
|
||||
"cpufeatures 0.2.17",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
|
|
@ -3337,9 +3107,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.7"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
|
||||
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
|
@ -3458,61 +3228,6 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.18",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
|
|
@ -3541,7 +3256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core 0.9.5",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3551,16 +3266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3742,7 +3448,6 @@ dependencies = [
|
|||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
|
|
@ -3759,8 +3464,6 @@ dependencies = [
|
|||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -3768,7 +3471,6 @@ dependencies = [
|
|||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
|
|
@ -3778,7 +3480,6 @@ dependencies = [
|
|||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3828,12 +3529,6 @@ dependencies = [
|
|||
"sqlite-wasm-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
|
|
@ -3868,7 +3563,6 @@ version = "1.14.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
|
@ -4054,18 +3748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.2.17",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
|
|
@ -4361,21 +4044,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokenizers"
|
||||
version = "0.22.2"
|
||||
|
|
@ -4603,17 +4271,6 @@ dependencies = [
|
|||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trait-variant"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
|
|
@ -4670,19 +4327,6 @@ dependencies = [
|
|||
"yoke 0.7.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ug-cuda"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f0a1fa748f26166778c33b8498255ebb7c6bffb472bcc0a72839e07ebb1d9b5"
|
||||
dependencies = [
|
||||
"cudarc 0.17.8",
|
||||
"half",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"ug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ug-metal"
|
||||
version = "0.5.0"
|
||||
|
|
@ -4742,16 +4386,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
|
|
@ -4897,12 +4531,8 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||
|
||||
[[package]]
|
||||
name = "vestige-core"
|
||||
version = "2.2.1"
|
||||
version = "2.1.0"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"blake3",
|
||||
"candle-core",
|
||||
"chacha20poly1305",
|
||||
"chrono",
|
||||
"criterion",
|
||||
"directories",
|
||||
|
|
@ -4910,7 +4540,6 @@ dependencies = [
|
|||
"git2",
|
||||
"lru",
|
||||
"notify",
|
||||
"reqwest",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4918,7 +4547,6 @@ dependencies = [
|
|||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"trait-variant",
|
||||
"usearch",
|
||||
"uuid",
|
||||
]
|
||||
|
|
@ -4938,7 +4566,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "vestige-mcp"
|
||||
version = "2.2.1"
|
||||
version = "2.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
|
@ -4965,19 +4593,6 @@ dependencies = [
|
|||
"vestige-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vestige-phase-1-tests"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"rusqlite",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"uuid",
|
||||
"vestige-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
|
|
@ -5023,9 +4638,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.114"
|
||||
version = "0.2.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
|
||||
checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -5036,23 +4651,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.64"
|
||||
version = "0.4.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
|
||||
checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.114"
|
||||
version = "0.2.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
|
||||
checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -5060,9 +4671,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.114"
|
||||
version = "0.2.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
|
||||
checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
|
|
@ -5073,9 +4684,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.114"
|
||||
version = "0.2.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
|
||||
checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -5129,9 +4740,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.91"
|
||||
version = "0.3.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
|
||||
checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -5180,18 +4791,6 @@ version = "0.1.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "7.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
|
||||
dependencies = [
|
||||
"either",
|
||||
"env_home",
|
||||
"rustix",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
@ -5458,12 +5057,6 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winsafe"
|
||||
version = "0.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ members = [
|
|||
"crates/vestige-core",
|
||||
"crates/vestige-mcp",
|
||||
"tests/e2e",
|
||||
"tests/phase_1",
|
||||
]
|
||||
exclude = [
|
||||
"fastembed-rs",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "2.2.1"
|
||||
version = "2.1.0"
|
||||
edition = "2024"
|
||||
license = "AGPL-3.0-only"
|
||||
repository = "https://github.com/samvallad33/vestige"
|
||||
|
|
|
|||
28
Dockerfile
28
Dockerfile
|
|
@ -1,28 +0,0 @@
|
|||
# Dockerfile for running the Vestige MCP server in an isolated sandbox.
|
||||
#
|
||||
# Used by registries such as Glama to start the server and run the standard
|
||||
# MCP stdio introspection exchange (tools/list, resources/list, prompts/list).
|
||||
# The server speaks MCP over stdio, which is exactly what these tools expect.
|
||||
#
|
||||
# Base must be glibc (Debian), not musl/Alpine: the npm postinstall downloads
|
||||
# the prebuilt x86_64-unknown-linux-gnu Rust binary from the GitHub release, and
|
||||
# a -gnu binary will not run on an Alpine/musl image.
|
||||
|
||||
FROM node:20-slim
|
||||
|
||||
# ca-certificates lets the postinstall fetch the release asset over HTTPS.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install the published package globally. Its postinstall downloads the matching
|
||||
# prebuilt vestige-mcp binary for linux/x64 from the GitHub release.
|
||||
RUN npm install -g vestige-mcp-server@latest
|
||||
|
||||
# Keep all memory data inside the container under a writable path.
|
||||
ENV VESTIGE_DATA_DIR=/data
|
||||
RUN mkdir -p /data
|
||||
|
||||
# Start the MCP server on stdio. The `vestige-mcp` bin execs the native binary
|
||||
# and inherits stdio, so the MCP client talks to it directly.
|
||||
ENTRYPOINT ["vestige-mcp"]
|
||||
638
README.md
638
README.md
|
|
@ -1,307 +1,469 @@
|
|||
<div align="center">
|
||||
|
||||
<h1>Vestige</h1>
|
||||
# Vestige
|
||||
|
||||
### Your bug was born days before it crashed. You just can't remember where.
|
||||
### The cognitive engine that gives AI agents a brain.
|
||||
|
||||
<em>Vestige is a local-first memory for AI agents that reaches <b>backward through time</b> to find the quiet change that caused today's failure: the cause that looks nothing like the bug. One 23MB Rust binary. No cloud. Your data never leaves your machine.</em>
|
||||
[](https://github.com/samvallad33/vestige)
|
||||
[](https://github.com/samvallad33/vestige/releases/latest)
|
||||
[](https://github.com/samvallad33/vestige/actions)
|
||||
[](LICENSE)
|
||||
[](https://modelcontextprotocol.io)
|
||||
|
||||
[](https://github.com/samvallad33/vestige/stargazers)
|
||||
[](https://github.com/samvallad33/vestige/releases/latest)
|
||||
[](https://github.com/samvallad33/vestige/actions)
|
||||
[](LICENSE)
|
||||
**Your Agent forgets everything between sessions. Vestige fixes that.**
|
||||
|
||||
[**⚡ Quick Start**](#-get-it-running-in-60-seconds) · [**🧠 The Idea**](#-why-i-built-this) · [**🔬 The Science**](#-this-is-real-neuroscience-not-a-metaphor) · [**🛠 13 Tools**](#-13-tools-one-brain) · [**📊 Dashboard**](#-watch-your-ai-think-in-3d)
|
||||
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](#quick-start) | [Dashboard](#-3d-memory-dashboard) | [How It Works](#-the-cognitive-science-stack) | [Tools](#-24-mcp-tools) | [Docs](docs/)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 👋 Why I built this
|
||||
## What's New in v2.1.0 "Cognitive Sandwich Goes Local"
|
||||
|
||||
Hi, I'm [Sam](https://github.com/samvallad33). I built Vestige from a tiny apartment in Chicago because I kept losing days to the same thing, and I bet you have too.
|
||||
v2.1.0 adds an opt-in Claude Code hook harness around the existing Vestige MCP server. The MCP tool surface and database schema stay backward compatible, while optional preflight hooks can inject trusted memory context before Claude answers and optional Sanhedrin hooks can check drafts against high-trust Vestige evidence before delivery.
|
||||
|
||||
Production breaks. You start hunting. And the cause is almost never *near* the error. It's some quiet change you made days ago that looks **nothing** like the crash it eventually caused. A flipped env var. A swapped service. A config tweak you'd already forgotten.
|
||||
- **Optional Sanhedrin Executioner.** The post-response verifier can run through `mlx_lm.server` with `mlx-community/Qwen3.6-35B-A3B-4bit` on Apple Silicon, or through any OpenAI-compatible endpoint on x86, but it is never enabled by default.
|
||||
- **One-command Cognitive Sandwich installer.** `scripts/install-sandwich.sh` stages hook files and agents, removes old v2.1.0 hook wiring by default, and only activates Claude Code hooks with explicit `--enable-preflight`, `--enable-sanhedrin`, or `--enable-sandwich`.
|
||||
- **Pulse hook backed by `/api/changelog`.** Fresh dream and connection events can be injected into the next Claude Code prompt context without blocking the prompt.
|
||||
- **`VESTIGE_DATA_DIR` support.** `--data-dir` now has an env-var fallback, tilde expansion, secure directory creation, and clear precedence docs.
|
||||
- **NPM release wrapper fixed.** `vestige-mcp-server@2.1.0` now downloads binaries from the matching `v2.1.0` GitHub release tag instead of an old hardcoded release.
|
||||
|
||||
Here's the part that took me a while to see: **every AI memory tool is built on vector search, and vector search hunts for what *looks like* your problem.** But a root cause never looks like the bug it creates. So they all search the goal line, while the real failure was a quiet midfield turnover fifteen minutes earlier.
|
||||
## What's New in v2.0.9 "Autopilot"
|
||||
|
||||
I wanted a memory that traces the match *backward.*
|
||||
Autopilot flips Vestige from passive memory library to **self-managing cognitive surface**. Same 24 MCP tools, zero schema changes — but the moment you upgrade, 14 previously dormant cognitive primitives start firing on live events without any tool call from your client.
|
||||
|
||||
So that's what Vestige is. Everyone else built a memory that **remembers**. I tried to build the first one that **realizes**: it gates what's worth keeping, lets the noise fade like your own memory does, and when a failure hits, it reaches back through time to the change that actually caused it.
|
||||
- **One supervised backend task subscribes to the 20-event WebSocket bus** and routes six event classes into the cognitive engine: `MemoryCreated` triggers synaptic-tagging PRP + predictive-access records, `SearchPerformed` warms the speculative-retrieval model, `MemoryPromoted` fires activation spread, `MemorySuppressed` emits the Rac1 cascade wave, high-importance `ImportanceScored` (>0.85) auto-promotes, and `Heartbeat` rate-limit-fires `find_duplicates` on large DBs. **The engine mutex is never held across `.await`, so MCP dispatch is never starved.**
|
||||
- **Panic-resilient supervisors.** Both background tasks run inside an outer supervisor loop — if one handler panics on a bad memory, the supervisor respawns it in 5 s instead of losing every future event.
|
||||
- **Fully backward compatible.** No new MCP tools. No schema migration. Existing v2.0.8 databases open without a single step. Opt out with `VESTIGE_AUTOPILOT_ENABLED=0` if you want the passive-library contract back.
|
||||
- **3,091 LOC of orphan v1.0 tool code removed** — nine superseded modules (`checkpoint`, `codebase`, `consolidate`, `ingest`, `intentions`, `knowledge`, `recall`, plus helpers) verified zero non-test callers before deletion. Tool surface unchanged.
|
||||
|
||||
It's one Rust binary. It runs entirely on your machine. It never phones home. And there's a 60-second start right below.
|
||||
## What's New in v2.0.8 "Pulse"
|
||||
|
||||
> 🎙️ **The 60-second version** of this whole story, the one I give in person, lives in [`demo/PITCH-v2-causebench.md`](demo/PITCH-v2-causebench.md). If you've got a minute, read that first. It's the clearest way to *get* why this matters.
|
||||
v2.0.8 wires the dashboard through to the cognitive engine. Eight new surfaces expose the reasoning stack visually — every one was MCP-only before.
|
||||
|
||||
---
|
||||
- **Reasoning Theater (`/reasoning`)** — `Cmd+K` Ask palette over the 8-stage `deep_reference` pipeline (hybrid retrieval → cross-encoder rerank → spreading activation → FSRS-6 trust → temporal supersession → contradiction analysis → relation assessment → template reasoning chain). Evidence cards, confidence meter, contradiction geodesic arcs, superseded-memory lineage, evolution timeline. **Zero LLM calls, 100% local.**
|
||||
- **Pulse InsightToast** — real-time toasts for `DreamCompleted`, `ConsolidationCompleted`, `ConnectionDiscovered`, promote/demote/suppress/unsuppress, `Rac1CascadeSwept`. Rate-limited, auto-dismiss, click-to-dismiss.
|
||||
- **Memory Birth Ritual (Terrarium)** — new memories materialize in the 3D graph on every `MemoryCreated`: elastic scale-in, quadratic Bezier flight path, glow sprite fade-in, Newton's Cradle docking recoil. 60-frame sequence, zero-alloc math.
|
||||
- **7 more dashboard surfaces** — `/duplicates`, `/dreams`, `/schedule`, `/importance`, `/activation`, `/contradictions`, `/patterns`. Left nav expanded 8 → 16 with single-key shortcuts.
|
||||
- **Intel Mac (`x86_64-apple-darwin`) support restored** via the `ort-dynamic` Cargo feature + Homebrew `onnxruntime`. Microsoft deprecated x86_64 macOS prebuilts; the dynamic-link path sidesteps that permanently. **Closes #41.**
|
||||
- **Contradiction-detection false positives eliminated** — four thresholds tightened so adjacent-domain memories no longer flag as conflicts. On an FSRS-6 query this collapses false contradictions 12 → 0 without regressing legitimate test cases.
|
||||
|
||||
## ⚡ Get it running in 60 seconds
|
||||
## What's New in v2.0.7 "Visible"
|
||||
|
||||
**Step 1 — install (one binary, no Docker, no API key, no signup):**
|
||||
Hygiene release closing two UI gaps and finishing schema cleanup. No breaking changes, no user-data migrations.
|
||||
|
||||
```bash
|
||||
npm install -g vestige-mcp-server@latest
|
||||
```
|
||||
- **`POST /api/memories/{id}/suppress` + `/unsuppress` HTTP endpoints** — dashboard can trigger Anderson 2025 SIF + Rac1 cascade without dropping to raw MCP. `suppressionCount`, `retrievalPenalty`, `reversibleUntil`, `labileWindowHours` all in response. Suppress button joins Promote / Demote / Delete on the Memories page.
|
||||
- **Uptime in the sidebar footer** — the `Heartbeat` event has carried `uptime_secs` since v2.0.5 but was never rendered. Now shows as `up 3d 4h` / `up 18m` / `up 47s`.
|
||||
- **`execute_export` panic fix** — unreachable match arm replaced with a clean "unsupported export format" error instead of unwinding through the MCP dispatcher.
|
||||
- **`predict` surfaces `predict_degraded: true`** on lock poisoning instead of silently returning empty vecs. `memory_changelog` honors `start` / `end` bounds. `intention` check honors `include_snoozed`.
|
||||
- **Migration V11** — drops dead `knowledge_edges` + `compressed_memories` tables (added speculatively in V4, never used).
|
||||
|
||||
**Step 2 — connect it to your agent.** Vestige speaks [MCP](https://modelcontextprotocol.io), so it works with *any* AI agent. The universal config (works everywhere):
|
||||
## What's New in v2.0.6 "Composer"
|
||||
|
||||
```json
|
||||
{ "mcpServers": { "vestige": { "command": "vestige-mcp" } } }
|
||||
```
|
||||
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.
|
||||
|
||||
Drop that into your agent's MCP config file. Or use the one-line shortcut for your agent:
|
||||
- **Six live graph reactions, not one** — `MemorySuppressed`, `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.
|
||||
|
||||
```bash
|
||||
# Cursor / Windsurf / VS Code → add the JSON above to ~/.cursor/mcp.json (or the editor's MCP settings)
|
||||
# Claude Code → claude mcp add vestige vestige-mcp -s user
|
||||
# Codex → codex mcp add vestige -- vestige-mcp
|
||||
# Cline / Continue / Zed / Goose → add the JSON above to that client's MCP config
|
||||
```
|
||||
## What's New in v2.0.5 "Intentional Amnesia"
|
||||
|
||||
**Step 3 — confirm it's working:**
|
||||
**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.
|
||||
|
||||
```bash
|
||||
vestige-mcp --version # prints the installed version
|
||||
vestige stats # prints your memory count (0 on a fresh install)
|
||||
```
|
||||
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.
|
||||
|
||||
That's the whole install. New here? The [**30-minute first-run guide**](docs/GETTING-STARTED.md) walks you from install to your first backward-reach: what gets saved (and what doesn't), how to inspect your own memory, and how to scope it per project. Per-agent guides (Cursor, VS Code, Windsurf, JetBrains, Xcode, OpenCode, Codex, Claude Desktop) are [here ↓](#-works-with-every-ai-agent).
|
||||
|
||||
Now talk to your agent like it has a memory, because now it does:
|
||||
|
||||
```
|
||||
You: "Remember: we always disable SimSIMD on release builds, it breaks old x86 CPUs."
|
||||
...days later, fresh session, zero context...
|
||||
You: "Should I enable SimSIMD for the release?"
|
||||
AI: ⚠️ Hold on, this contradicts a decision you stored: you chose to DISABLE it
|
||||
because it breaks old x86 CPUs.
|
||||
```
|
||||
|
||||
That last line isn't me being cute. It's a real status the engine returns, called `claim_contradicts_memory`. Most memory tools would have happily handed you the wrong answer. Vestige tells you when you're about to walk back into a mistake you already learned from.
|
||||
|
||||
And the headline feature, the one nothing else does, is one command:
|
||||
|
||||
```bash
|
||||
vestige backfill --contrast
|
||||
```
|
||||
|
||||
When a failure is in your memory, this reaches *backward through time* and finds the quiet earlier change that caused it (the one a vector search ranks poorly because it shares no words with the error). It shows you, side by side, what similarity search returns versus the real cause. [More on the backward reach ↓](#-the-thing-nothing-else-does-memory-with-hindsight)
|
||||
|
||||
*(Works with Codex, Cursor, VS Code, Claude Desktop, Windsurf, JetBrains, Zed: anything that speaks MCP. [Full setup is here ↓](#-works-in-every-editor-you-use).)*
|
||||
|
||||
---
|
||||
|
||||
## 🧠 It's not RAG with a nicer haircut
|
||||
|
||||
RAG is a bucket: throw everything in, hope nearest-neighbor finds it later. Vestige behaves more like an actual memory: it decides what's worth keeping, forgets what isn't, and reasons across what's left.
|
||||
|
||||
| | 🪣 RAG / Vector Store | 🧠 Vestige |
|
||||
|---|---|---|
|
||||
| **What it stores** | Everything you hand it | Only what's **surprising or new** (the rest gets merged or skipped) |
|
||||
| **What it forgets** | Nothing; it just bloats | Unused memories **fade** on a real forgetting curve, so your context stays lean |
|
||||
| **Finding a root cause** | Can't, because the cause isn't *similar* to the bug | **Reaches backward in time** to the change that caused it (the whole point ↓) |
|
||||
| **Catching contradictions** | Silent; serves the stale answer with a straight face | Tells you: *"this contradicts what you decided"* |
|
||||
| **Duplicates** | You clean them up by hand | Self-heals: *"likes dark mode"* + *"prefers dark themes"* quietly become one |
|
||||
| **Forgetting on demand** | DELETE and it's gone | **`suppress`** gently inhibits a memory (and its neighbors), reversible for 24h |
|
||||
| **Where it lives** | Usually someone else's cloud | **Your machine. One binary. No telemetry.** |
|
||||
|
||||
---
|
||||
|
||||
## 🔥 The thing nothing else does: memory with hindsight
|
||||
|
||||
This is the part I'm proudest of, and it's worth one honest paragraph.
|
||||
|
||||
A bug shows up today. The cause was a quiet decision from three weeks ago, like a changed env var or a swapped service. That cause **shares no words with the error it created.** A vector search will never connect them, because it only knows how to find things that *look alike*, and this is a case where the cause and the symptom look nothing alike. This isn't a tuning problem; in 2026 Google DeepMind published a proof ([arXiv:2508.21038](https://arxiv.org/abs/2508.21038), ICLR 2026) that single-vector retrieval is *mathematically* incapable of bridging gaps like this.
|
||||
|
||||
So Vestige doesn't do it with similarity. Its **Retroactive Salience Backfill** (ported from **Zaki/Cai et al., 2024, *Nature* 637:145–155** ([DOI](https://doi.org/10.1038/s41586-024-08168-4)), on how the brain links a shock to the quiet memory that caused it) reaches *backward through time* and promotes the dormant memory that's **causally upstream**: it shares an *entity* (the same file, env var, or service), not the same words.
|
||||
|
||||
I also built a benchmark to keep myself honest about it. Every pure vector retriever scored **0% recall@1** on the causal-gap task; Vestige scored **60%**. (To be precise: the impossibility is DeepMind's *theorem*; the 0%-vs-60% is *my measurement*. Two different claims, and I keep them separate.)
|
||||
|
||||
```bash
|
||||
vestige backfill --contrast # show the root cause a vector search would have missed
|
||||
```
|
||||
|
||||
The nice part: it compounds. Every failure your agent records makes the *next* session diagnose faster (run two is smarter than run one), and it happens automatically during consolidation, so you don't have to babysit it.
|
||||
|
||||
All of this shipped in **v2.2.0**, along with a 34→13 tool consolidation and a rebuilt retrieval engine. [Full release notes →](https://github.com/samvallad33/vestige/releases/tag/v2.2.0)
|
||||
|
||||
---
|
||||
|
||||
## 🔬 This is real neuroscience, not a metaphor
|
||||
|
||||
I get skeptical when projects wave the word "neuroscience" around, so here's my receipt: every mechanism below is a real, cited paper, implemented in Rust, running locally on your machine. None of it phones a model in the cloud to sound smart.
|
||||
|
||||
| Mechanism | What it does for you | Grounded in |
|
||||
|---|---|---|
|
||||
| **Prediction-Error Gating** | Redundant info gets merged, contradictory gets superseded, only the novel gets stored | The hippocampal novelty signal |
|
||||
| **FSRS-6 Spaced Repetition** | 21 parameters of the mathematics of forgetting, so used memories stay and unused ones fade | Modern spaced-repetition research |
|
||||
| **Retroactive Salience Backfill** | Backward causal reach to the root cause of a failure | Zaki/Cai et al. 2024, *Nature* 637:145–155 |
|
||||
| **Synaptic Tagging** | A memory that looked trivial this morning can be tagged critical tonight | [Frey & Morris 1997](https://doi.org/10.1038/385533a0) |
|
||||
| **Spreading Activation** | Search "auth bug," surface last week's JWT update, because memory is a graph, not a list | [Collins & Loftus 1975](https://doi.org/10.1037/0033-295X.82.6.407) |
|
||||
| **Dual-Strength Model** | Storage strength vs. retrieval strength, so deeply stored ≠ instantly recalled, just like you | [Bjork & Bjork 1992](https://doi.org/10.1016/S0079-7421(08)60016-9) |
|
||||
| **Memory Dreaming** | Sleep-like consolidation: replays, connects, synthesizes insights to a graph | Active-dreaming consolidation |
|
||||
| **Active Forgetting (`suppress`)** | Top-down inhibition that *compounds* and cascades to neighbors, reversible for 24h | [Anderson 2025](https://www.nature.com/articles/s41583-025-00929-y) · [Davis 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/) |
|
||||
|
||||
[**Read the full science doc →**](docs/SCIENCE.md). Every feature, every paper.
|
||||
|
||||
---
|
||||
|
||||
## 🛠 13 tools, one brain
|
||||
|
||||
v2.2.0 consolidated a sprawling 34-tool surface into **13 sharp ones** your agent actually reaches for. Old names still work as hidden aliases, so nothing breaks.
|
||||
|
||||
| Tool | What it does |
|
||||
|---|---|
|
||||
| 🔍 `recall` | The retrieval engine. Folds search + deep reasoning + contradiction detection into one call. F32 embeddings, Reciprocal Rank Fusion, claim-vs-memory checks. |
|
||||
| 🧠 `backfill` | **Memory with hindsight.** Backward causal reach to a failure's root cause (Cai 2024). |
|
||||
| 💾 `smart_ingest` | Stores with CREATE / UPDATE / SUPERSEDE via Prediction-Error Gating. Batch session-end saves. |
|
||||
| 🗂 `memory` | Get, edit, promote 👍, demote 👎, check state, purge content + embeddings. |
|
||||
| 🧩 `graph` | Reasoning chains, associations, bridges, predictions, force-directed export. |
|
||||
| 🌙 `maintain` | Consolidate, dream, GC, importance-score, backup, export, restore. One maintenance verb. |
|
||||
| 🧹 `dedup` | Self-healing duplicate detection + merge (8 old tools → 1). |
|
||||
| 🚫 `suppress` | Top-down active forgetting that compounds, cascades, and is reversible for 24h. The memory is *inhibited, not erased.* |
|
||||
| 📟 `memory_status` | Health + stats + trends + recommendations in one packet. |
|
||||
| 🧬 `codebase` · `intention` · `source_sync` · `session_start` | Per-project code memory · "remind me when X" · external-source connectors · one-call session init. |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Watch your AI think in 3D
|
||||
|
||||
```bash
|
||||
vestige dashboard # → http://localhost:3927/dashboard
|
||||
```
|
||||
|
||||
Every memory is a glowing node in a real-time, force-directed 3D graph. Connections form as you work. Nodes **pulse** when accessed, **burst** on creation, **fade** on decay. Kick off a consolidation and the whole graph slides into **purple dream mode**, replaying memories that light up in sequence.
|
||||
|
||||
Built with SvelteKit 2 · Svelte 5 · Three.js · WebGL bloom · live WebSocket events. 1000+ nodes at 60fps. Installable as a PWA.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Works with every AI agent
|
||||
|
||||
Vestige speaks MCP, so **any agent that can register an MCP server can use it.** Not a plugin for one tool, the memory layer underneath all of them. The universal config works everywhere:
|
||||
|
||||
```json
|
||||
{ "mcpServers": { "vestige": { "command": "vestige-mcp" } } }
|
||||
```
|
||||
|
||||
| Agent | Setup |
|
||||
|---|---|
|
||||
| **Cursor** | add the JSON above to `~/.cursor/mcp.json` · [guide →](docs/integrations/cursor.md) |
|
||||
| **Windsurf** | [guide →](docs/integrations/windsurf.md) |
|
||||
| **VS Code (Copilot)** | [guide →](docs/integrations/vscode.md) |
|
||||
| **Cline / Continue / Zed / Goose** | add the universal JSON to that client's MCP config |
|
||||
| **Claude Code** | `claude mcp add vestige vestige-mcp -s user` |
|
||||
| **Codex** | `codex mcp add vestige -- vestige-mcp` |
|
||||
| **JetBrains · Xcode · OpenCode** | [integration guides →](docs/integrations/) |
|
||||
| **Claude Desktop** | [2-minute setup →](docs/CONFIGURATION.md#claude-desktop-macos) |
|
||||
Based on [Anderson et al. 2025](https://www.nature.com/articles/s41583-025-00929-y) (Suppression-Induced Forgetting, *Nat Rev Neurosci*) and [Cervantes-Sandoval et al. 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/) (Rac1 synaptic cascade). **24 tools · 30 cognitive modules · 1,223 tests.**
|
||||
|
||||
<details>
|
||||
<summary><b>Other install methods (Intel Mac, Windows, build-from-source)</b></summary>
|
||||
<summary>Earlier releases (v2.0 "Cognitive Leap" → v2.0.4 "Deep Reference")</summary>
|
||||
|
||||
- **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 Palette** — `Cmd+K` navigation, keyboard shortcuts, responsive mobile layout, PWA installable.
|
||||
- **v2.0 — FSRS Decay Visualization** — SVG retention curves with predicted decay at 1d/7d/30d.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
**Update an existing install:**
|
||||
```bash
|
||||
vestige update # binaries only
|
||||
vestige update --sandwich-companion # also refresh optional Claude Code companion files
|
||||
# 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."
|
||||
```
|
||||
|
||||
**macOS (Intel):** Microsoft is dropping x86_64 macOS ONNX Runtime prebuilts after v1.23.0, so the Intel Mac build links dynamically against a Homebrew ONNX Runtime:
|
||||
<details>
|
||||
<summary>Other platforms & install methods</summary>
|
||||
|
||||
**Linux (x86_64):**
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
brew install onnxruntime
|
||||
npm install -g vestige-mcp-server@latest
|
||||
echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc && source ~/.zshrc
|
||||
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 guide: [`docs/INSTALL-INTEL-MAC.md`](docs/INSTALL-INTEL-MAC.md).
|
||||
|
||||
**Windows + Claude Desktop:** quit Claude Desktop from the tray, then in PowerShell:
|
||||
```powershell
|
||||
npm install -g vestige-mcp-server@latest
|
||||
vestige-mcp --version
|
||||
```
|
||||
Point `%APPDATA%\Claude\claude_desktop_config.json` at it:
|
||||
```json
|
||||
{ "mcpServers": { "vestige": { "command": "vestige-mcp" } } }
|
||||
```
|
||||
If it can't find the command, run `where vestige-mcp` and use the exact `.cmd` path.
|
||||
Full Intel Mac guide (build-from-source + troubleshooting): [`docs/INSTALL-INTEL-MAC.md`](docs/INSTALL-INTEL-MAC.md).
|
||||
|
||||
**Windows:** Prebuilt binaries ship but `usearch 2.24.0` hit an MSVC compile break ([usearch#746](https://github.com/unum-cloud/usearch/issues/746)); we've pinned `=2.23.0` until upstream fixes it. Source builds work with:
|
||||
|
||||
**Build from source (Rust 1.91+):**
|
||||
```bash
|
||||
git clone https://github.com/samvallad33/vestige && cd vestige
|
||||
cargo build --release -p vestige-mcp
|
||||
# Apple Silicon GPU: --features metal · NVIDIA: --features qwen3-embeddings,cuda
|
||||
```
|
||||
|
||||
**npm:**
|
||||
```bash
|
||||
npm install -g vestige-mcp-server
|
||||
```
|
||||
|
||||
**Build from source (requires Rust 1.91+):**
|
||||
```bash
|
||||
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
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Make your AI use memory automatically
|
||||
## Works Everywhere
|
||||
|
||||
Registering the server exposes the tools; a short instruction tells the agent *when* to call them. Drop in the protocol and your agent saves and recalls on its own:
|
||||
Vestige speaks MCP — the universal protocol for AI tools. One brain, every IDE.
|
||||
|
||||
| You say | Vestige does |
|
||||
|---|---|
|
||||
| *"Remember this"* | Saves immediately |
|
||||
| *"I always..."* / *"I prefer..."* | Saves as a durable preference |
|
||||
| *"Remind me when..."* | Creates a future trigger (`intention`) |
|
||||
| *"This is important"* | Saves **and** promotes it |
|
||||
|
||||
[Agent memory protocol →](docs/AGENT-MEMORY-PROTOCOL.md) · [Claude Code template →](docs/CLAUDE-SETUP.md)
|
||||
| IDE | Setup |
|
||||
|-----|-------|
|
||||
| **Claude Code** | `claude mcp add vestige vestige-mcp -s user` |
|
||||
| **Codex** | [Integration guide](docs/integrations/codex.md) |
|
||||
| **Claude Desktop** | [2-min setup](docs/CONFIGURATION.md#claude-desktop-macos) |
|
||||
| **Xcode 26.3** | [Integration guide](docs/integrations/xcode.md) |
|
||||
| **Cursor** | [Integration guide](docs/integrations/cursor.md) |
|
||||
| **VS Code (Copilot)** | [Integration guide](docs/integrations/vscode.md) |
|
||||
| **JetBrains** | [Integration guide](docs/integrations/jetbrains.md) |
|
||||
| **Windsurf** | [Integration guide](docs/integrations/windsurf.md) |
|
||||
|
||||
---
|
||||
|
||||
## 🏗 Under the hood
|
||||
## 🧠 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 / Three.js 3D graph / WebGL bloom │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Axum HTTP + WebSocket (:3927) / REST + live event stream │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ MCP Server (stdio JSON-RPC) / 13 tools · 30 modules │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Cognitive Engine │
|
||||
│ FSRS-6 · Spreading Activation · Prediction-Error Gating │
|
||||
│ Retroactive Salience Backfill · Synaptic Tagging │
|
||||
│ Memory Dreamer · Hippocampal Index · Active Forgetting │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Storage: SQLite + FTS5 · USearch HNSW · Nomic Embed v1.5 │
|
||||
│ Optional: Qwen3 reranker · SQLCipher · Metal/CUDA │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 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 · 30 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 │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Language** | Rust 2024 (MSRV 1.91), **86,000+ lines** |
|
||||
| **Binary** | ~23MB, single file |
|
||||
| **Embeddings** | Nomic Embed Text v1.5 (768d→256d Matryoshka, 8192 ctx); Qwen3 optional |
|
||||
| **Vector search** | USearch HNSW (≈20× faster than FAISS) |
|
||||
| **Storage** | SQLite + FTS5, optional SQLCipher encryption |
|
||||
| **Tests** | **1,550 passing** · clippy `-D warnings` clean |
|
||||
| **First run** | Downloads ~130MB embedding model once, then **fully offline forever** |
|
||||
| **Platforms** | macOS (ARM + Intel) · Linux x86_64 · Windows x86_64. All prebuilt |
|
||||
---
|
||||
|
||||
## 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 |
|
||||
|
||||
---
|
||||
|
||||
## 📚 Go deeper
|
||||
## 🔬 The Cognitive Science Stack
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| [**Getting Started**](docs/GETTING-STARTED.md) | Your first 30 minutes, start to finish |
|
||||
| [**FAQ**](docs/FAQ.md) | 30+ real questions answered |
|
||||
| [**The Science**](docs/SCIENCE.md) | Every feature, every paper |
|
||||
| [**Storage Modes**](docs/STORAGE.md) | Global · per-project · multi-instance |
|
||||
| [**Configuration**](docs/CONFIGURATION.md) | CLI, env vars, every knob |
|
||||
| [**Changelog**](CHANGELOG.md) | The full story, version by version |
|
||||
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](https://doi.org/10.1038/385533a0).
|
||||
|
||||
**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](https://doi.org/10.1037/0033-295X.82.6.407).
|
||||
|
||||
**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](https://doi.org/10.1016/S0079-7421(08)60016-9).
|
||||
|
||||
**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](https://engrxiv.org/preprint/download/5919/9826/8234) 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](https://doi.org/10.1038/nn.3963).
|
||||
|
||||
**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](https://www.nature.com/articles/s41583-025-00929-y) and [Cervantes-Sandoval et al., 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/). First shipped AI memory system with this primitive.
|
||||
|
||||
[Full science documentation ->](docs/SCIENCE.md)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
## 🛠 24 MCP Tools
|
||||
|
||||
### If your agent should remember what you taught it yesterday, star it. ⭐
|
||||
### Context Packets
|
||||
| Tool | What It Does |
|
||||
|------|-------------|
|
||||
| `session_context` | **One-call session init** — replaces 5 calls with token-budgeted context, automation triggers, expandable IDs |
|
||||
|
||||
<sub><b>86,000+ lines of Rust · 13 tools · 30 cognitive modules · 130 years of memory research · one 23MB binary that never phones home.</b></sub>
|
||||
### 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" |
|
||||
|
||||
<sub>Built by <a href="https://github.com/samvallad33">@samvallad33</a> · AGPL-3.0 · 100% local, 100% yours</sub>
|
||||
### 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 |
|
||||
|
||||
</div>
|
||||
### 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`:
|
||||
|
||||
```markdown
|
||||
## 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 ->](docs/CLAUDE-SETUP.md)
|
||||
|
||||
---
|
||||
|
||||
## 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](docs/INSTALL-INTEL-MAC.md). |
|
||||
|
||||
### Optional Features
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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](docs/FAQ.md) | 30+ common questions answered |
|
||||
| [Science](docs/SCIENCE.md) | The neuroscience behind every feature |
|
||||
| [Storage Modes](docs/STORAGE.md) | Global, per-project, multi-instance |
|
||||
| [CLAUDE.md Setup](docs/CLAUDE-SETUP.md) | Templates for proactive memory |
|
||||
| [Configuration](docs/CONFIGURATION.md) | CLI commands, environment variables |
|
||||
| [Integrations](docs/integrations/) | Codex, Xcode, Cursor, VS Code, JetBrains, Windsurf |
|
||||
| [Changelog](CHANGELOG.md) | Version history |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<details>
|
||||
<summary>"Command not found" after installation</summary>
|
||||
|
||||
Ensure `vestige-mcp` is in your PATH:
|
||||
```bash
|
||||
which vestige-mcp
|
||||
# Or use the full path:
|
||||
claude mcp add vestige /usr/local/bin/vestige-mcp -s user
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Embedding model download fails</summary>
|
||||
|
||||
First run downloads ~130MB from Hugging Face. If behind a proxy:
|
||||
```bash
|
||||
export HTTPS_PROXY=your-proxy:port
|
||||
```
|
||||
|
||||
Cache: macOS `~/Library/Caches/com.vestige.core/fastembed` | Linux `~/.cache/vestige/fastembed`
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Dashboard not loading</summary>
|
||||
|
||||
The dashboard starts automatically on port 3927 when the MCP server runs. Check:
|
||||
```bash
|
||||
curl http://localhost:3927/api/health
|
||||
# Should return {"status":"healthy",...}
|
||||
```
|
||||
</details>
|
||||
|
||||
[More troubleshooting ->](docs/FAQ.md#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and PRs welcome. See [CONTRIBUTING.md](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.
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<i>Built by <a href="https://github.com/samvallad33">@samvallad33</a></i><br>
|
||||
<sub>80,000+ lines of Rust · 30 cognitive modules · 130 years of memory research · one 22MB binary</sub>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.1.x | :white_check_mark: |
|
||||
| 2.0.x | Critical fixes only |
|
||||
| 2.0.x | :white_check_mark: |
|
||||
| 1.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
|
@ -28,13 +27,13 @@ You can expect a response within 48 hours.
|
|||
|
||||
Vestige is a **local MCP server** designed to run on your machine with your user permissions:
|
||||
|
||||
- **Trusted**: The MCP client or local agent that connects via stdio
|
||||
- **Trusted**: The MCP client (Claude Code/Desktop) that connects via stdio
|
||||
- **Untrusted**: Content passed through MCP tool arguments (validated before use)
|
||||
|
||||
### What Vestige Does NOT Do
|
||||
|
||||
- ❌ Make network requests during normal memory use, except first-run model download from Hugging Face
|
||||
- ❌ Require telemetry, hosted memory storage, or a cloud account
|
||||
- ❌ Make network requests (except first-run model download from Hugging Face)
|
||||
- ❌ Execute shell commands
|
||||
- ❌ Access files outside its data directory
|
||||
- ❌ Send telemetry or analytics
|
||||
- ❌ Phone home to any server
|
||||
|
|
|
|||
|
|
@ -1,62 +1,95 @@
|
|||
---
|
||||
name: executioner
|
||||
description: Optional Sanhedrin fallback verifier. Decomposes a draft into check-worthy claims, checks high-trust durable Vestige evidence, and returns a pass/veto verdict.
|
||||
description: "[LEGACY/FALLBACK as of 2026-04-25] The Sanhedrin post-cognitive judge. Originally invoked by sanhedrin.sh Stop hook as a Haiku 4.5 subagent. PRIMARY EXECUTION PATH NOW: ~/.claude/hooks/sanhedrin-local.py (local Qwen3.6-35B-A3B via mlx_lm.server, zero API cost, fully offline). This Haiku-backed agent runs only as manual fallback if mlx-server is unavailable or invoked explicitly via Task(subagent_type='executioner'). Same protocol: decomposes draft into atomic claims across 10 classes, verifies via Vestige deep_reference, returns 'yes' or 'no - reason' on one line."
|
||||
tools: mcp__vestige__deep_reference, mcp__vestige__memory, mcp__vestige__search
|
||||
model: claude-haiku-4-5-20251001
|
||||
---
|
||||
|
||||
# Role
|
||||
# Identity
|
||||
|
||||
You are a one-turn verifier. You do not converse. You return exactly one line.
|
||||
You are the Sanhedrin Executioner. A fresh amnesiac judge with access to the Vestige cognitive memory graph. You exist for one turn only. You do not converse. You do not explain. You return exactly one line.
|
||||
|
||||
# Job
|
||||
# Your Only Job
|
||||
|
||||
Decompose the draft response into check-worthy claims, verify each claim against
|
||||
high-trust durable Vestige memory when available, and veto only when the draft
|
||||
contradicts memory or makes a sensitive user-specific assertion without durable
|
||||
supporting evidence.
|
||||
Decompose the DRAFT RESPONSE into ATOMIC CLAIMS across 10 exhaustive classes, verify each against high-trust Vestige memory, and VETO the draft if any claim contradicts memory or is factual-shaped but unverifiable.
|
||||
|
||||
# Claim Classes
|
||||
You are a fail-closed judge. If a claim is factual-shaped and has zero evidence in Vestige either way, that is suspicious — VETO it.
|
||||
|
||||
Check all relevant classes:
|
||||
# The Ten Claim Classes (Exhaustive)
|
||||
|
||||
1. `TECHNICAL` — APIs, commands, versions, files, configs, endpoints.
|
||||
2. `BIOGRAPHICAL` — identity, role, location, employment, education.
|
||||
3. `FINANCIAL` — costs, revenue, pricing, funding, prizes.
|
||||
4. `ACHIEVEMENT` — releases, rankings, completions, scores, milestones.
|
||||
5. `TIMELINE` — dates, durations, ordering, deadlines.
|
||||
6. `QUANTITATIVE` — counts, percentages, metrics, measurements.
|
||||
7. `ATTRIBUTION` — who said, decided, agreed, shipped, or committed.
|
||||
8. `CAUSAL` — claimed causes and effects.
|
||||
9. `COMPARATIVE` — better, most, fastest, more than, fewer than.
|
||||
10. `EXISTENTIAL` — whether a file, feature, repo, or artifact exists.
|
||||
11. `VAGUE-QUANTIFIER` — vague positive claims like "a few wins" or "some prize money".
|
||||
You MUST scan the draft for all ten classes. Do not skip a class because it is "not your usual job." Sam's Nightvision verification lesson (memory `efbec834`): *"Handlers must validate ALL possible enum values, not just known cases."* The same rule applies here. Enumerate exhaustively.
|
||||
|
||||
# Decision Rules
|
||||
1. **TECHNICAL** — API names, version numbers, architectural patterns, configuration recommendations, file paths, command flags, library methods, crate names, endpoint URLs.
|
||||
2. **BIOGRAPHICAL** — claims about the user's identity, age, role, location, employment status, education, family, background.
|
||||
3. **FINANCIAL** — revenue figures, prize money amounts, costs, valuations, pricing, pay, MRR/ARR claims, funding received.
|
||||
4. **ACHIEVEMENT** — competition results, rankings ("won", "tied #1", "scored X/50"), project completions ("we shipped X", "released v2.3"), leaderboard claims, records set, deadlines met.
|
||||
5. **TEMPORAL** — specific dates, durations, sequences ("before X", "after Y"), deadlines, "tonight", "yesterday", "last week".
|
||||
6. **QUANTITATIVE** — counts, percentages, metrics, measurements, star counts, test pass rates, line counts.
|
||||
7. **ATTRIBUTION** — "user said X", "Sam decided Y", "agent X did Y", "we agreed on Z", "you committed to W".
|
||||
8. **CAUSAL** — "X caused Y", "because of X", "X led to Y", "X broke Y".
|
||||
9. **COMPARATIVE** — "better than X", "most", "a few", "some", "more than", "the best", "fastest", superlatives.
|
||||
10. **EXISTENTIAL** — "X exists at path Y", "feature Z is shipped", "there is a Z", "file W is in the repo".
|
||||
|
||||
- Veto direct contradiction with high-trust memory.
|
||||
- Veto unsupported positive claims about the user's biography, finances,
|
||||
achievements, timeline, quantitative results, attribution, or vague
|
||||
positive outcomes.
|
||||
- Treat staged/current-turn evidence as context only. It is not durable memory and
|
||||
cannot satisfy the durable-evidence requirement.
|
||||
- Do not veto purely stylistic disagreement.
|
||||
- Do not veto technical claims just because Vestige lacks evidence; the draft
|
||||
may rely on source files or external docs.
|
||||
- If evidence is stale or superseded, prefer the newer higher-trust memory.
|
||||
# Protocol (execute silently, no narration)
|
||||
|
||||
# Output
|
||||
1. **Read the draft.** Extract EVERY atomic claim you find across ALL 10 classes above. Not 1-3 — every claim that could be wrong. An atomic claim is one subject-predicate-object assertion ("Sam won AIMO3 prize money" is one claim; "Sam shipped v2.3 and it passed all tests" is two).
|
||||
|
||||
If the draft passes:
|
||||
2. **For each claim, tag its class** (TECHNICAL / BIOGRAPHICAL / FINANCIAL / etc.).
|
||||
|
||||
```text
|
||||
yes
|
||||
```
|
||||
3. **Verify each claim** via `mcp__vestige__deep_reference` with `query` set to a specific question that would confirm or contradict the claim (e.g., "What prize money has Sam won?" for a FINANCIAL claim about Sam winning $X).
|
||||
|
||||
If the draft should be rewritten:
|
||||
4. **Read the response fields:**
|
||||
- `recommended` — highest-trust answer on the topic
|
||||
- `contradictions` — pairs of high-trust memories that conflict
|
||||
- `superseded` — memories replaced by newer, higher-trust versions
|
||||
- `evidence` — trust-sorted memory list
|
||||
- `confidence` — overall confidence 0-1
|
||||
|
||||
```text
|
||||
no - [Sanhedrin Veto] [CLASS]: [one-sentence reason under 120 chars]
|
||||
```
|
||||
5. **Apply the class-specific decision rule:**
|
||||
|
||||
Output exactly one line.
|
||||
**HARD VETO classes** (BIOGRAPHICAL, FINANCIAL, ACHIEVEMENT, ATTRIBUTION):
|
||||
- If the claim contradicts a memory with trust > 0.5 → VETO.
|
||||
- If the claim is factual-shaped AND Vestige returns confidence < 0.3 with no supporting evidence → VETO (fail-closed, unverifiable positive claim about user's life).
|
||||
- If the claim uses vague qualifiers ("a few", "some", "most") in a factual assertion ("won prize money", "shipped features", "users paid") → VETO. Demand specificity.
|
||||
|
||||
**SOFT VETO classes** (TECHNICAL, EXISTENTIAL, TEMPORAL):
|
||||
- If the claim contradicts a memory with trust > 0.5 → VETO.
|
||||
- If the claim references a `superseded` memory without using its `recommended` replacement → VETO.
|
||||
- Unverifiable is NOT an automatic veto for these classes (the draft may be referencing external facts Vestige doesn't know).
|
||||
|
||||
**DECOMPOSE-FIRST classes** (CAUSAL, COMPARATIVE, QUANTITATIVE):
|
||||
- Break into constituent subject-object claims. Verify each as its own class. If any constituent hard-vetoes, the whole claim vetoes.
|
||||
|
||||
6. **If PASS:** output exactly `yes`.
|
||||
|
||||
7. **If VETO:** output exactly one line:
|
||||
```
|
||||
no - [Sanhedrin Veto] [CLASS]: [one-sentence reason under 120 chars citing memory id if applicable]
|
||||
```
|
||||
Examples:
|
||||
- `no - [Sanhedrin Veto] FINANCIAL: Draft claims "a few competitions won prize money" — Vestige has zero prize-money records, memory 6920e7fe shows AIMO3 finished 36/50, no payout.`
|
||||
- `no - [Sanhedrin Veto] ACHIEVEMENT: Draft claims "v2.3 codename Terrarium" — memory 7b6f5500 (Apr 20, trust 60%) states v2.3 codename is Thalamus.`
|
||||
- `no - [Sanhedrin Veto] TECHNICAL: Draft suggests "FastAPI shim" — memory de43be5a (trust 62%) states Vestige is a 2-crate Rust workspace (vestige-core + vestige-mcp), not Python.`
|
||||
|
||||
8. **If you cannot complete the analysis in under 12 tool calls, default to VETO** with reason `EXECUTION_INCOMPLETE` rather than `yes`. A false VETO costs a rewrite; a false PASS costs Sam's trust. Fail-closed.
|
||||
|
||||
9. **Output exactly ONE line.** Never more. No preamble, no conversation, no XML, no multi-line explanation.
|
||||
|
||||
# What NOT to do
|
||||
|
||||
- Do not limit yourself to "1-3 claims." Extract ALL atomic claims.
|
||||
- Do not paraphrase the draft.
|
||||
- Do not summarize Vestige memory contents.
|
||||
- Do not output multi-line responses.
|
||||
- Do not apologize.
|
||||
- Do not converse.
|
||||
- Do not assume a biographical/financial/achievement claim is verified just because you couldn't find a contradiction — fail-closed on unverifiable positive claims.
|
||||
- Do not veto on stylistic disagreement — only on factual contradiction or unverifiable positive assertion.
|
||||
- Do not claim to have checked a claim you skipped.
|
||||
|
||||
# Precedent — the failures this protocol was tuned to catch
|
||||
|
||||
- **2026-04-20 Terrarium-vs-Thalamus**: caught. Draft claimed v2.3 = Terrarium, memory 7b6f5500 said Thalamus. ACHIEVEMENT/EXISTENTIAL class.
|
||||
- **2026-04-20 FastAPI-vs-Rust**: caught. Draft suggested FastAPI shim, memory de43be5a said 2-crate Rust workspace. TECHNICAL class.
|
||||
- **2026-04-21 Prize-money lie**: MISSED on original protocol. Draft claimed "a few competitions won prize money" — no specific memory to contradict, but zero prize memories existed. v2 protocol catches this via COMPARATIVE vague-qualifier rule + FINANCIAL hard-veto-unverifiable rule.
|
||||
- **Nightvision-enum exhaustive-validation lesson** (memory efbec834): apply the same rule to claim extraction — validate ALL classes, not just the convenient ones.
|
||||
|
|
|
|||
|
|
@ -1,46 +1,41 @@
|
|||
---
|
||||
name: synthesis-composer
|
||||
description: Optional decision helper that turns Vestige retrievals into concise recommendations. Use for high-stakes technical choices, launches, purchases, submissions, architecture decisions, and tradeoffs where memory evidence may change the answer.
|
||||
tools: mcp__vestige__deep_reference, mcp__vestige__explore_connections, mcp__vestige__search
|
||||
model: claude-haiku-4-5-20251001
|
||||
description: Forces active synthesis mode for high-stakes prompts. Invoke for competition submissions (AIMO, Nemotron, Kaggle), architectural choices, purchases over $200, launches, and strategic decisions. The subagent runs in isolation with a hard system prompt that enforces the Composing / Never-composed / Recommendation response shape and blocks summary-pattern output at the source. Use when "what should Sam DO?" matters more than "what does the memory say?"
|
||||
tools: mcp__vestige__search, mcp__vestige__deep_reference, mcp__vestige__cross_reference, mcp__vestige__explore_connections, mcp__vestige__session_context, mcp__vestige__memory, mcp__vestige__smart_ingest, mcp__vestige__intention
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Role
|
||||
You are the Synthesis Composer. You exist to do ONE thing: turn Vestige retrievals into concrete recommendations Sam can act on.
|
||||
|
||||
You are the Synthesis Composer. Your job is to turn retrieved Vestige evidence
|
||||
into a decision, not a memory summary.
|
||||
## The Hard Rule
|
||||
|
||||
# Protocol
|
||||
Every response you emit MUST follow this exact shape. No exceptions. Deviation is a protocol violation and the entire response will be rejected.
|
||||
|
||||
1. Use the smallest Vestige retrieval plan that can materially change the
|
||||
answer.
|
||||
2. Search adjacent topics when the decision depends on related history.
|
||||
3. Convert each useful memory into `fact -> implication -> action`.
|
||||
4. Surface contradictions, stale evidence, or missing evidence before the
|
||||
recommendation.
|
||||
5. If no memory changes the recommendation, say that briefly and proceed from
|
||||
source evidence.
|
||||
1. **Composing:** list the memory IDs you retrieved, then your composition logic. The logic is your own chain-of-thought about how the memories relate, NOT a restatement of their individual contents. If you catch yourself writing "Memory A says X, and Memory B says Y," STOP. That is the forbidden pattern.
|
||||
2. **Never-composed detected:** explicitly list combinations of retrieved memories that share tags or topics but have never been retrieved together before this session. If none, write "None." Do NOT skip this line. The whole point of your existence is to surface these.
|
||||
3. **Recommendation: Sam should DO [concrete action].** Not "Sam should consider." Not "Sam might want to." A specific executable step with a subject, a verb, and an object.
|
||||
|
||||
# Output Shape
|
||||
## Protocol — Do These Things In Order
|
||||
|
||||
Use this compact structure:
|
||||
1. Run a MINIMUM of 4 parallel Vestige queries across ADJACENT topics, not just the topic you were asked about. Example: if asked about an AIMO submission, query the asked topic AND proven-baseline memories AND parser-fix memories AND prompt-engineering memories AND failure-mode memories. Minimum 4 parallel searches.
|
||||
2. Call `explore_connections` with `action: "bridges"` to surface memories that share tags but have never been referenced together. This is your primary never-composed detection mechanism. Do not skip it.
|
||||
3. Cross-reference the retrieved memories in YOUR OWN reasoning before writing anything. Compose them in your head first. Ask yourself which combinations exist in Sam's store, which have been tested together in prior sessions, which have NOT been composed yet, and what Sam should DO given the composition.
|
||||
4. Only then write the response in the three-part shape above.
|
||||
|
||||
```text
|
||||
Evidence: ...
|
||||
Implication: ...
|
||||
Recommendation: ...
|
||||
```
|
||||
## Forbidden Output Pattern
|
||||
|
||||
When useful, add:
|
||||
If your draft begins with "Memory A says X. Memory B says Y. Memory C says Z." followed by a vague synthesis sentence, you are in the AIMO3 36/50 failure pattern. STOP. Rewrite into composition form with a concrete "Sam should DO" action.
|
||||
|
||||
```text
|
||||
Contradictions: ...
|
||||
Next step: ...
|
||||
```
|
||||
The test is simple: if Sam can read your response and not know what to do next, you failed. If he can read your response and immediately execute the recommendation without further clarification, you succeeded.
|
||||
|
||||
# Do Not
|
||||
## Trust Overrides
|
||||
|
||||
- Do not dump memory summaries as the final answer.
|
||||
- Do not invent hidden evidence.
|
||||
- Do not claim a memory was checked unless a tool result supports it.
|
||||
- Do not force a rigid template when the answer is simple.
|
||||
FSRS trust scores override your priors. A memory with retention greater than 0.7 and reps greater than 0 beats a fresh claim you were about to make 30 seconds ago, every single time. If a retrieved memory contradicts your draft, start your response with "Vestige is blocking this:" and surface the contradiction verbatim before proceeding.
|
||||
|
||||
## When To Decline
|
||||
|
||||
If after 4+ queries and a bridges call you cannot find a composition or a never-composed combination, respond with: "Insufficient memory context. Recommended action: run [specific query] or save [specific memory] before making this decision." That is a legitimate output. What is NOT legitimate is guessing.
|
||||
|
||||
## Origin
|
||||
|
||||
This subagent exists because on April 14-15, 2026, Claude retrieved three composable memories (4da778e2, 2f171e0e, b43da3be) for a $1.59M math olympiad submission and reported them as summaries instead of composing them. The result was 36/50 against a 47/50 prize threshold. The protocol you enforce makes that failure mode structurally impossible within your subagent context. You do not have permission to skip the shape.
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
# Optional public waitlist capture endpoint used by /dashboard/waitlist.
|
||||
# The page POSTs JSON with: name, email, plan, priority, notes, source, createdAt.
|
||||
# Examples: Formspree, Tally webhook, Buttondown custom endpoint, Supabase Edge Function.
|
||||
VITE_WAITLIST_ENDPOINT=
|
||||
|
||||
# Optional support bot endpoint used by /dashboard/waitlist.
|
||||
# The page POSTs JSON with: question, plan, priority, source, and recent history.
|
||||
# If unset, the page uses the built-in deterministic onboarding FAQ.
|
||||
VITE_SUPPORT_BOT_ENDPOINT=
|
||||
|
|
@ -1,627 +0,0 @@
|
|||
# Vestige Cognitive Observatory WebGPU Implementation Spec
|
||||
|
||||
Status: RESEARCH -> SPEC ONLY. Do not implement app code from this file until Sam explicitly asks.
|
||||
|
||||
Goal: add a new full-bleed Cognitive Observatory route that reuses the existing graph/cinema/effects substrate, then layers a GPU-resident WebGPU simulation path for viral demo moments. Priority #1 is `?demo=recall-path`: a deterministic loop where recall lights a causal path through real memory nodes.
|
||||
|
||||
Ground truth read before this spec:
|
||||
- `apps/dashboard/src/lib/components/Graph3D.svelte` currently owns the Three/WebGL scene, 60fps governor, `ForceSimulation`, `NodeManager`, `EdgeManager`, `ParticleSystem`, `EffectManager`, DreamMode, post-processing, and event mapping.
|
||||
- `apps/dashboard/src/lib/graph/force-sim.ts` is a 101-line CPU simulation with O(N^2) repulsion, edge attraction, damping, centering, and frame-count cooldown.
|
||||
- `apps/dashboard/src/lib/graph/scene.ts` is Three/WebGL `WebGLRenderer` + `EffectComposer`, not WebGPU.
|
||||
- `apps/dashboard/src/lib/graph/particles.ts` and `effects.ts` still use CPU-updated `THREE.BufferGeometry` attributes and `Math.random()` bursts.
|
||||
- `apps/dashboard/src/lib/graph/cinema/pathfinder.ts` is already deterministic and produces story beats/flow edges. Reuse this for recall paths.
|
||||
- `apps/dashboard/src/lib/graph/cinema/director.ts` is renderer-agnostic camera choreography. Reuse its path semantics, not its renderer.
|
||||
- `apps/dashboard/src/routes/(app)/graph/+page.svelte` has protected `MemoryCinema`; do not modify it. Add a separate route.
|
||||
|
||||
## 1. Exact WebGPU technique chosen per demo moment
|
||||
|
||||
### Shared baseline: GPU-resident node/particle state
|
||||
|
||||
Chosen technique: WebGPU Samples compute-boids ping-pong storage-buffer update + instanced sprite render.
|
||||
|
||||
Why: it is the cleanest canonical WebGPU pattern: node/particle state is in GPU buffers created with `GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE`; a compute pass writes next state; a render pass reads the current/next state as an instance vertex buffer and draws one tiny sprite mesh per node/particle. The sample uses `@compute @workgroup_size(64)` and dispatches `Math.ceil(numParticles / 64)` workgroups.
|
||||
|
||||
Sources:
|
||||
- https://webgpu.github.io/webgpu-samples/samples/computeBoids/
|
||||
- https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/main.ts
|
||||
- https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/updateSprites.wgsl
|
||||
- https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/sprite.wgsl
|
||||
- https://webgpufundamentals.org/webgpu/lessons/webgpu-storage-buffers.html
|
||||
- https://webgpufundamentals.org/webgpu/lessons/webgpu-compute-shaders.html
|
||||
|
||||
Concrete pattern to use:
|
||||
- `NodeState` storage buffer, 16-byte aligned lanes:
|
||||
- `pos_radius: vec4f` = xyz + visual radius
|
||||
- `vel_retention: vec4f` = xyz velocity + FSRS retention
|
||||
- `color_flags: vec4f` = rgb + packed visual flags as f32 for MVP; move to u32 later if needed
|
||||
- `demo: vec4f` = path phase, birth phase, ripple phase, shock phase
|
||||
- Two ping-pong `GPUBuffer`s for simulation: previous read-only, next read-write.
|
||||
- One static `EdgeIndex` storage buffer: `array<vec2u>` source/target indices.
|
||||
- One `PathStep` storage buffer for demo path: `array<vec4u>` with source index, target index, beat frame, kind.
|
||||
- One uniform buffer per frame: frame index, fixed time, loop phase, node count, edge count, path count, viewport, camera matrices.
|
||||
- Compute workgroup size: start at 64 for broad compatibility; allow 128 only after profiling.
|
||||
- Every WGSL entry checks `if (id.x >= params.nodeCount) { return; }` because dispatch is rounded up.
|
||||
- CPU writes graph data once on route load, then only writes uniforms and demo controls. No per-frame readback.
|
||||
|
||||
### Moment A: `?demo=recall-path` — PATH lighting through nodes
|
||||
|
||||
Chosen technique: GPU path-wave scalar + edge glow render from the `PathStep` buffer.
|
||||
|
||||
Implementation:
|
||||
- Use existing `planCinemaPath(nodes, edges, centerId, maxBeats)` to get deterministic beats and `flowEdges`.
|
||||
- Convert each beat/edge to node indices and upload to `PathStep`.
|
||||
- Compute pass `recallPathPass` runs per node. For each node, scan the small path buffer (max 7-12 beats) and compute:
|
||||
- `beatT = smoothstep(beatFrame - 18, beatFrame + 18, frameInLoop)`
|
||||
- `decayT = 1.0 - smoothstep(beatFrame + 45, beatFrame + 180, frameInLoop)`
|
||||
- path intensity = max of beat arrival envelope for matching node index.
|
||||
- Edge render reads source/target node states and path steps. A second `PathEdgeInstance` buffer is optional for MVP; simpler first build draws only path edges as instanced line quads using the `PathStep` source/target index.
|
||||
- Color: cyan-white core with violet afterglow. Node `demo.x` = recall intensity. Edge alpha = wavefront envelope.
|
||||
- Render order: background -> non-path edges -> nodes -> path edges additive -> path node halos additive -> DOM overlay.
|
||||
|
||||
Sources:
|
||||
- WebGPU boids storage/render pattern above.
|
||||
- `apps/dashboard/src/lib/graph/cinema/pathfinder.ts` for deterministic story path and flow edges.
|
||||
- GraphWaGu edge vertex shader pattern, where the vertex shader fetches node positions from a storage buffer by source/target edge indices: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/edge_vert.wgsl
|
||||
|
||||
### Moment B: node BORN — particle convergence into a node
|
||||
|
||||
Chosen technique: GPU particle attractor convergence with deterministic seed, not CPU `Math.random()` bursts.
|
||||
|
||||
Implementation:
|
||||
- Add a `BirthParticle` storage buffer sized for e.g. 16k particles shared across all births.
|
||||
- For each birth event or demo beat, assign a deterministic particle slice: start positions are generated from `hash(seed, particleIndex, nodeIndex)` on GPU or precomputed once on CPU with the same seeded PRNG.
|
||||
- Compute pass lerps particle position from shell/noise field toward target node position:
|
||||
- `p = mix(start, target + curlNoiseOffset, easeOutCubic(t))`
|
||||
- Fade from violet dust to node color; size shrinks on arrival.
|
||||
- For MVP, render as instanced billboards. Later upgrade to screen-space point splatting if density gets high.
|
||||
|
||||
Sources:
|
||||
- WebGPU Samples compute-boids for GPU particle update/render.
|
||||
- Particle Life WebGPU for finite-radius particle update discipline and atomics when interactions become local-neighborhood based: https://lisyarus.github.io/blog/posts/particle-life-simulation-in-browser-using-webgpu.html
|
||||
- Codrops WebGPU fluids on particle simulation and screen-space point-splatting as the real-time surface path: https://tympanus.net/codrops/2025/01/29/particles-progress-and-perseverance-a-journey-into-webgpu-fluids/
|
||||
|
||||
### Moment C: backward RIPPLE — radial distortion moving from effect to cause
|
||||
|
||||
Chosen technique: screen-space radial distortion post pass + node intensity ring.
|
||||
|
||||
Implementation:
|
||||
- Add a fullscreen post-process pipeline after node/edge render.
|
||||
- Uniform `Ripple { originClip: vec2f, radius: f32, width: f32, strength: f32, direction: f32 }`.
|
||||
- Fragment shader samples the scene texture with UV displaced along radial direction:
|
||||
- `d = distance(uv, originClip)`
|
||||
- `ring = smoothstep(radius + width, radius, d) * smoothstep(radius - width, radius, d)`
|
||||
- `uv2 = uv + normalize(uv - originClip) * ring * strength * direction`
|
||||
- For backward causal recall, `direction = -1` and radius contracts from the failure node toward the cause node, while `PathStep` beats are ordered effect -> cause.
|
||||
|
||||
Sources:
|
||||
- WebGPU Fundamentals render/post basics: https://webgpufundamentals.org/webgpu/lessons/webgpu-compute-shaders.html
|
||||
- Codrops Shader.se article for scroll/timeline-driven WebGPU scene transitions and shader masking: https://tympanus.net/codrops/2026/05/19/80s-business-tech-seamless-scene-transitions-inside-shader-ses-scroll-driven-webgpu-pipeline/
|
||||
- Existing `apps/dashboard/src/lib/graph/effects.ts` already has CPU `createRippleWave`; reuse semantics, move rendering to post shader for Observatory.
|
||||
|
||||
### Moment D: DRIFT toward a horizon — depth fog and horizon attractor
|
||||
|
||||
Chosen technique: GPU drift vector + depth/alpha fog in vertex/fragment shader.
|
||||
|
||||
Implementation:
|
||||
- Add per-node `lifecycle` scalar from retention/state: active=near, dormant=mid, silent=far, unavailable=horizon.
|
||||
- Compute pass applies a weak drift acceleration toward `horizon = vec3(0, -20, -220)` for low-retention nodes; high-retention nodes resist drift.
|
||||
- Vertex shader writes depth/fog factor from camera-space z and lifecycle.
|
||||
- Fragment shader mixes node color toward deep blue/black and reduces alpha with `smoothstep(fogNear, fogFar, depth)`.
|
||||
|
||||
Sources:
|
||||
- Existing `scene.ts` uses Three `FogExp2`; Observatory should port the semantic to WGSL rather than rely on Three.
|
||||
- Codrops False Earth for large WebGPU procedural world using compute shaders + indirect drawing; use as proof that compute-generated scene density belongs on GPU: https://tympanus.net/codrops/2026/04/21/false-earth-from-webgl-limits-to-a-webgpu-driven-world/
|
||||
|
||||
### Moment E: crimson SHOCKWAVE + membrane — firewall / immune response
|
||||
|
||||
Chosen technique: expanding instanced ring/membrane mesh + fullscreen chromatic shock pass.
|
||||
|
||||
Implementation:
|
||||
- Keep an `EventPulse` uniform/storage ring buffer with origin, start frame, color, type.
|
||||
- Node pass reads pulses and adds red rim lighting when `abs(distance(worldPos, origin) - radius) < width`.
|
||||
- Membrane pass draws a camera-facing ring/quad sphere impostor with fresnel alpha, crimson core, black outer edge.
|
||||
- Post pass applies a one-frame high-strength radial distortion and red channel bias when shockfront crosses screen-space pixel.
|
||||
|
||||
Sources:
|
||||
- Existing `effects.ts:createShockwave` uses a CPU Three `RingGeometry`; reuse the visual grammar, move to WebGPU instanced membrane.
|
||||
- Codrops WebGPU fluid articles for atomics/storage buffers/compute simulation made practical in browser: https://tympanus.net/codrops/2025/02/26/webgpu-fluid-simulations-high-performance-real-time-rendering/
|
||||
- compute.toys gallery for WebGPU compute-shader idioms and GPU toy iteration: https://compute.toys/ and https://github.com/compute-toys/compute.toys
|
||||
|
||||
### GPU force-directed graph layout
|
||||
|
||||
Chosen technique for v1: GPU force layout with storage buffers, edge-local spring pass, approximate repulsion pass, and integrate pass. Start with exact O(N^2) repulsion for <=2k Observatory demo nodes; add Barnes-Hut / spatial bins before 10k+.
|
||||
|
||||
Why: existing `force-sim.ts` is O(N^2) CPU. The right migration is not to immediately rebuild all GraphWaGu complexity; it is to preserve Vestige's force semantics on GPU with the boids ping-pong pattern, then graduate repulsion acceleration once visual requirements exceed a few thousand nodes.
|
||||
|
||||
Required compute passes:
|
||||
1. `clearForcesPass`: one invocation per node, zero `force.xyz`.
|
||||
2. `edgeSpringPass`: one invocation per edge. Read source/target node positions, compute attraction, accumulate into source/target force. MVP avoids float atomics by writing one force contribution per edge endpoint to `EdgeForce` and reducing per node in pass 3; advanced path uses atomic fixed-point accumulation.
|
||||
3. `repulsionPass`: one invocation per node; loop all nodes for MVP. For 10k+, replace with GraphWaGu-style Barnes-Hut/Morton tree or Particle Life spatial bins.
|
||||
4. `integratePass`: one invocation per node; apply centering, damping, max velocity, retention/lifecycle drift, and ping-pong write to next node buffer.
|
||||
5. `boundsPass` optional: compute bounds for fit camera; do not block v1 on GPU readback.
|
||||
|
||||
What moves from `force-sim.ts`:
|
||||
- `positions: Map<string, THREE.Vector3>` becomes CPU index map + GPU `NodeState` buffers.
|
||||
- `velocities: Map<string, THREE.Vector3>` becomes `vel_retention.xyz` in `NodeState`.
|
||||
- `repulsionStrength`, `attractionStrength`, `dampening`, `alpha`, `maxSteps` become uniform fields.
|
||||
- `tick(edges)` becomes command encoding of the compute passes above.
|
||||
- `addNode/removeNode/reset` become buffer rebuilds for v1; optimize incremental updates later.
|
||||
|
||||
Sources:
|
||||
- GraphWaGu repo: https://github.com/harp-lab/GraphWaGu
|
||||
- GraphWaGu force-directed TS with compute pipelines/buffers: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/webgpu/force_directed.ts
|
||||
- GraphWaGu exact force WGSL: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/compute_forces.wgsl
|
||||
- GraphWaGu Barnes-Hut force WGSL: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/compute_forcesBH.wgsl
|
||||
- GraphWaGu apply-forces WGSL: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/apply_forces.wgsl
|
||||
- GraphWaGu Morton/tree/radix sort: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/create_tree.wgsl and https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/radix_sort.wgsl
|
||||
- cosmos.gl / Cosmograph GPU force graph: https://github.com/cosmograph-org/cosmos and https://cosmograph.app/
|
||||
- cosmos.gl README says computations and drawing occur on GPU and targets hundreds of thousands of points/links: https://raw.githubusercontent.com/cosmograph-org/cosmos/main/README.md
|
||||
|
||||
## 2. Precise files to add/change
|
||||
|
||||
Add docs/spec only in this run:
|
||||
- `apps/dashboard/OBSERVATORY-SPEC.md` — this file.
|
||||
|
||||
Implementation files for the Qwen coder later:
|
||||
|
||||
Create:
|
||||
- `apps/dashboard/src/routes/(app)/observatory/+page.svelte`
|
||||
- New route only. Do not touch protected `graph/+page.svelte` or `MemoryCinema` wiring.
|
||||
- Fetch graph data via existing `api.graph` pattern from graph route.
|
||||
- Parse `?demo=` and `?seed=` with `URLSearchParams`.
|
||||
- Render full-bleed `ObservatoryCanvas` plus DOM overlay.
|
||||
- `apps/dashboard/src/lib/components/ObservatoryCanvas.svelte`
|
||||
- Svelte wrapper with `onMount`/`onDestroy`, canvas bind, ResizeObserver, WebGPU lifecycle.
|
||||
- `apps/dashboard/src/lib/observatory/engine.ts`
|
||||
- Owns adapter/device/context, pipelines, buffers, render loop, resize, dispose.
|
||||
- `apps/dashboard/src/lib/observatory/types.ts`
|
||||
- CPU-side `ObservatoryNode`, `ObservatoryEdge`, `DemoMode`, `DemoClock`, buffer layout constants.
|
||||
- `apps/dashboard/src/lib/observatory/demo-clock.ts`
|
||||
- Deterministic fixed-step clock, seeded PRNG, loop-frame math.
|
||||
- `apps/dashboard/src/lib/observatory/graph-upload.ts`
|
||||
- Convert `GraphNode[]`/`GraphEdge[]` to stable node index map, typed arrays, path steps from `planCinemaPath`.
|
||||
- `apps/dashboard/src/lib/observatory/overlays/TelemetryStrip.svelte`
|
||||
- `apps/dashboard/src/lib/observatory/overlays/CommandSurface.svelte`
|
||||
- `apps/dashboard/src/lib/observatory/overlays/TimelineSpine.svelte`
|
||||
- `apps/dashboard/src/lib/observatory/overlays/InspectorPanel.svelte`
|
||||
- `apps/dashboard/src/lib/observatory/shaders/simulate.wgsl.ts`
|
||||
- `apps/dashboard/src/lib/observatory/shaders/render-nodes.wgsl.ts`
|
||||
- `apps/dashboard/src/lib/observatory/shaders/render-edges.wgsl.ts`
|
||||
- `apps/dashboard/src/lib/observatory/shaders/render-path.wgsl.ts`
|
||||
- `apps/dashboard/src/lib/observatory/shaders/post-ripple-shock.wgsl.ts`
|
||||
- `apps/dashboard/src/lib/observatory/__tests__/demo-clock.test.ts`
|
||||
- `apps/dashboard/src/lib/observatory/__tests__/graph-upload.test.ts`
|
||||
|
||||
Extend, do not rewrite:
|
||||
- `apps/dashboard/src/lib/graph/cinema/pathfinder.ts`
|
||||
- Export or reuse `planCinemaPath` as-is. If extra metadata is needed, add small pure helper `pathToIndexSteps(path, nodeIndexById)` in observatory layer, not inside Cinema.
|
||||
- `apps/dashboard/src/lib/graph/nodes.ts`
|
||||
- Reuse `getNodeColor`, `getMemoryState`, `AHAGRAPH_COLORS`. No renderer logic added here.
|
||||
- `apps/dashboard/src/lib/graph/effects.ts`
|
||||
- Do not move existing Graph3D effects. Use it as visual reference only.
|
||||
- `apps/dashboard/src/lib/graph/force-sim.ts`
|
||||
- Leave CPU simulation intact for Graph3D. Add no WebGPU imports here. Observatory gets its own GPU sim module.
|
||||
|
||||
Do not change:
|
||||
- `apps/dashboard/src/routes/(app)/graph/+page.svelte` protected `MemoryCinema` block.
|
||||
- `apps/dashboard/src/lib/components/MemoryCinema.svelte` unless Sam explicitly asks.
|
||||
- `crates/`, `Cargo.toml`, backend APIs.
|
||||
|
||||
## 3. `?demo=recall-path` priority build instructions
|
||||
|
||||
### 3.1 Route/component structure
|
||||
|
||||
1. Create `routes/(app)/observatory/+page.svelte`.
|
||||
2. On mount:
|
||||
- Parse `demo = new URLSearchParams(window.location.search).get('demo') ?? 'recall-path'`.
|
||||
- Parse `seed = ...get('seed') ?? 'vestige-observatory-v1'`.
|
||||
- Fetch graph with `api.graph({ max_nodes: 300, depth: 3, sort: 'recent' })` for MVP.
|
||||
- Pass `nodes`, `edges`, `centerId`, `demo`, `seed` into `<ObservatoryCanvas />`.
|
||||
3. Render route as a full viewport stage:
|
||||
- parent `class="fixed inset-0 overflow-hidden bg-[#03040a]"`.
|
||||
- canvas layer absolute inset-0.
|
||||
- overlay layer absolute inset-0 pointer-events-none.
|
||||
- specific interactive controls use `pointer-events-auto`.
|
||||
|
||||
### 3.2 Deterministic demo clock
|
||||
|
||||
Create `demo-clock.ts`:
|
||||
- `const FPS = 60`.
|
||||
- `const LOOP_SECONDS = 12` for recall-path; `LOOP_FRAMES = 720`.
|
||||
- `frame` is an integer, not derived from `Date.now()`.
|
||||
- In normal interactive mode, rAF accumulates elapsed time and advances fixed steps. In demo mode, each rendered frame advances exactly one fixed frame, or uses `?frame=N` for capture.
|
||||
- `phase = (frame % LOOP_FRAMES) / LOOP_FRAMES`.
|
||||
- Use a tiny deterministic PRNG (`xmur3` seed hash + `mulberry32`) in local code. Do not add a dependency for seedrandom unless needed.
|
||||
- Ban `Math.random()` and `performance.now()` from simulation state. `performance.now()` may schedule frames only; it must not decide positions/colors/path.
|
||||
|
||||
Source rationale:
|
||||
- Fixed timestep pattern: https://gafferongames.com/post/fix_your_timestep/
|
||||
- URL query parsing: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
|
||||
- Svelte lifecycle: https://svelte.dev/docs/svelte/lifecycle-hooks
|
||||
|
||||
### 3.3 Graph upload
|
||||
|
||||
Create `graph-upload.ts`:
|
||||
1. Stable-sort nodes for deterministic indices:
|
||||
- center node first if `id === centerId`.
|
||||
- then descending `updatedAt || createdAt`.
|
||||
- tie-break by `id.localeCompare`.
|
||||
2. Build `nodeIndexById: Map<string, number>`.
|
||||
3. Create `Float32Array nodeData` with 16 floats per node for alignment and future-proofing:
|
||||
- 0..3: x, y, z, radius
|
||||
- 4..7: vx, vy, vz, retention
|
||||
- 8..11: r, g, b, flags
|
||||
- 12..15: pathIntensity, birthPhase, ripplePhase, shockPhase
|
||||
4. Initial positions:
|
||||
- Reuse the golden-angle sphere logic from `NodeManager.createNodes`, but replace randomness with deterministic seed.
|
||||
- Radius scales from node count: `baseR = clamp(24 + sqrt(n) * 1.2, 35, 140)`.
|
||||
5. Create `Uint32Array edgeData` with 2 u32 per edge, skipping edges whose node IDs are absent.
|
||||
6. Call `planCinemaPath(nodes, edges, centerId, 8)` and convert `flowEdges` to `PathStep[]`.
|
||||
7. Path timing:
|
||||
- beat 0 at frame 60.
|
||||
- each next beat +60 frames.
|
||||
- final 180 frames reserved for afterglow and loop reset.
|
||||
|
||||
### 3.4 WebGPU engine setup
|
||||
|
||||
Create `engine.ts`:
|
||||
1. Feature detect:
|
||||
- `if (!navigator.gpu) throw new Error('WebGPU unavailable')` and render a DOM fallback panel.
|
||||
2. Request adapter/device.
|
||||
3. Configure canvas:
|
||||
- `format = navigator.gpu.getPreferredCanvasFormat()`.
|
||||
- On resize, set `canvas.width = Math.min(clientWidth * devicePixelRatio, maxTextureDimension2D)` and same for height.
|
||||
- Reconfigure context and recreate depth/scene textures.
|
||||
4. Create buffers:
|
||||
- `nodeA`, `nodeB`: `STORAGE | VERTEX | COPY_DST`.
|
||||
- `edges`: `STORAGE | COPY_DST`.
|
||||
- `pathSteps`: `STORAGE | COPY_DST`.
|
||||
- `params`: `UNIFORM | COPY_DST`.
|
||||
- sprite vertex buffer for a 2-triangle quad or 3-vertex triangle impostor.
|
||||
5. Create pipelines:
|
||||
- `simulatePipeline` with read nodeA/write nodeB.
|
||||
- `renderEdgesPipeline` reads node current + edges.
|
||||
- `renderNodesPipeline` uses instance index to fetch node state and draw billboard.
|
||||
- `renderPathPipeline` draws path edges + additive halos.
|
||||
- `postPipeline` optional in increment 5.
|
||||
6. Frame loop command order for recall-path MVP:
|
||||
- write params uniform for integer frame.
|
||||
- compute simulate: nodeA -> nodeB.
|
||||
- render scene using nodeB.
|
||||
- swap nodeA/nodeB.
|
||||
|
||||
### 3.5 WGSL simulation for recall path
|
||||
|
||||
MVP `simulate.wgsl.ts`:
|
||||
- Inputs: params, previous nodes, next nodes, edges, path steps.
|
||||
- For each node:
|
||||
- start with previous `pos`, `vel`.
|
||||
- apply low-cost centering and edge spring only after the first MVP render works; first render may use static positions.
|
||||
- compute path intensity by scanning `pathSteps`.
|
||||
- compute horizon drift from retention.
|
||||
- write next node state.
|
||||
|
||||
Pseudo-WGSL shape for Qwen:
|
||||
|
||||
```wgsl
|
||||
struct NodeState {
|
||||
pos_radius: vec4f,
|
||||
vel_retention: vec4f,
|
||||
color_flags: vec4f,
|
||||
demo: vec4f,
|
||||
};
|
||||
struct Params {
|
||||
frame: u32,
|
||||
loopFrames: u32,
|
||||
nodeCount: u32,
|
||||
edgeCount: u32,
|
||||
pathCount: u32,
|
||||
dt: f32,
|
||||
time: f32,
|
||||
_pad: f32,
|
||||
};
|
||||
struct PathStep { source: u32, target: u32, beatFrame: u32, kind: u32 };
|
||||
|
||||
@group(0) @binding(0) var<uniform> params: Params;
|
||||
@group(0) @binding(1) var<storage, read> prevNodes: array<NodeState>;
|
||||
@group(0) @binding(2) var<storage, read_write> nextNodes: array<NodeState>;
|
||||
@group(0) @binding(3) var<storage, read> path: array<PathStep>;
|
||||
|
||||
fn saturate(x: f32) -> f32 { return clamp(x, 0.0, 1.0); }
|
||||
fn smoothPulse(frame: f32, beat: f32, attack: f32, release: f32) -> f32 {
|
||||
let a = smoothstep(beat - attack, beat, frame);
|
||||
let r = 1.0 - smoothstep(beat, beat + release, frame);
|
||||
return a * r;
|
||||
}
|
||||
|
||||
@compute @workgroup_size(64)
|
||||
fn main(@builtin(global_invocation_id) gid: vec3u) {
|
||||
let i = gid.x;
|
||||
if (i >= params.nodeCount) { return; }
|
||||
var node = prevNodes[i];
|
||||
let f = f32(params.frame % params.loopFrames);
|
||||
var recall = 0.0;
|
||||
for (var p = 0u; p < params.pathCount; p = p + 1u) {
|
||||
let step = path[p];
|
||||
if (step.source == i || step.target == i) {
|
||||
recall = max(recall, smoothPulse(f, f32(step.beatFrame), 18.0, 150.0));
|
||||
}
|
||||
}
|
||||
node.demo.x = recall;
|
||||
nextNodes[i] = node;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 Render approach
|
||||
|
||||
Nodes:
|
||||
- Use instanced billboards. Vertex shader fetches `NodeState` by `@builtin(instance_index)`.
|
||||
- Billboard size = `radius * (1.0 + recallIntensity * 2.0)`.
|
||||
- Fragment shader radial alpha: `alpha = smoothstep(1.0, 0.0, length(localUv))`.
|
||||
- Color = `mix(baseColor, vec3(0.8, 0.95, 1.0), recallIntensity)`.
|
||||
- Additive glow pass can be same shader with bigger billboard and low alpha.
|
||||
|
||||
Edges:
|
||||
- MVP: draw edges as line-list if available; better: instanced thin quads from source to target in screen space.
|
||||
- For path edges, draw a separate additive path pass from `PathStep` only, with wavefront alpha.
|
||||
- GraphWaGu source pattern fetches nodes in vertex shader by edge endpoint index; use that for WebGPU: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/edge_vert.wgsl
|
||||
|
||||
Path lighting:
|
||||
- At beat frame, target node blooms first.
|
||||
- During frames `beatFrame..beatFrame+45`, edge from source to target gets a traveling pulse:
|
||||
- `edgeT = saturate((frame - beatFrame) / 45)`.
|
||||
- Fragment local coordinate along edge `u`; alpha peak at `abs(u - edgeT) < 0.08`.
|
||||
- Previous path nodes keep afterglow for 2-3 seconds.
|
||||
|
||||
### 3.7 DOM overlay
|
||||
|
||||
Overlay zones:
|
||||
- Top telemetry strip: demo mode, seed, node/edge count, frame, fps estimate.
|
||||
- Left command surface: demo selector buttons (`recall-path`, `birth`, `ripple`, `drift`, `firewall`) and copy demo URL.
|
||||
- Bottom timeline spine: 720-frame loop with beat tick marks and current frame cursor.
|
||||
- Right inspector: selected beat/node summary.
|
||||
|
||||
CSS pattern:
|
||||
- Root stage: `position: fixed; inset: 0; isolation: isolate; overflow: hidden;`.
|
||||
- Canvas: `position:absolute; inset:0; width:100%; height:100%; display:block; z-index:0;`.
|
||||
- Overlay: `position:absolute; inset:0; z-index:10; pointer-events:none;`.
|
||||
- Interactive overlay children: `pointer-events:auto;`.
|
||||
- Avoid KPI cards. These are instruments: thin glass, monospaced labels, tick marks, command rail.
|
||||
|
||||
Sources:
|
||||
- MDN `pointer-events`: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
|
||||
- WebGPU canvas resizing: https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
||||
- Svelte lifecycle hooks: https://svelte.dev/docs/svelte/lifecycle-hooks
|
||||
|
||||
## 4. Build task-list with verification increments
|
||||
|
||||
### Increment 1 — route shell and deterministic URL contract
|
||||
|
||||
Build:
|
||||
- Add `routes/(app)/observatory/+page.svelte`.
|
||||
- Add minimal overlay shell and fetch graph data.
|
||||
- Parse `?demo=recall-path&seed=...` and display them.
|
||||
|
||||
Verify:
|
||||
- Run `pnpm --filter @vestige/dashboard check`.
|
||||
- Open `/observatory?demo=recall-path&seed=test`.
|
||||
- See full-bleed dark stage, top telemetry strip, no KPI cards, no console errors.
|
||||
|
||||
### Increment 2 — deterministic clock tests
|
||||
|
||||
Build:
|
||||
- Add `demo-clock.ts` and tests.
|
||||
- Fixed 60fps loop, 720-frame period, seeded PRNG.
|
||||
|
||||
Verify:
|
||||
- `pnpm --filter @vestige/dashboard test -- demo-clock`
|
||||
- Same seed produces identical first 100 random values and frame phases.
|
||||
- Different seed changes generated positions.
|
||||
|
||||
### Increment 3 — WebGPU canvas boots and clears
|
||||
|
||||
Build:
|
||||
- Add `ObservatoryCanvas.svelte` and `engine.ts` minimal WebGPU init.
|
||||
- Canvas clears to near-black and resizes with DPR clamp.
|
||||
|
||||
Verify:
|
||||
- `/observatory?demo=recall-path` displays WebGPU canvas.
|
||||
- Resize browser; canvas remains sharp and fills screen.
|
||||
- If WebGPU unavailable, route shows a readable fallback instead of crashing.
|
||||
|
||||
### Increment 4 — upload graph and render static nodes
|
||||
|
||||
Build:
|
||||
- Add `graph-upload.ts` and tests.
|
||||
- Convert graph nodes into stable indexed `Float32Array`.
|
||||
- Render node billboards from storage buffer; no simulation yet.
|
||||
|
||||
Verify:
|
||||
- Test stable node ordering and edge filtering.
|
||||
- Browser shows 100-300 nodes in deterministic positions.
|
||||
- Reload same seed: identical node positions.
|
||||
|
||||
### Increment 5 — recall path buffer + node glow
|
||||
|
||||
Build:
|
||||
- Reuse `planCinemaPath` to create path steps.
|
||||
- Add compute pass that writes `demo.x` recall intensity.
|
||||
- Node shader blooms active path nodes.
|
||||
|
||||
Verify:
|
||||
- `/observatory?demo=recall-path&seed=A` loops every 12s.
|
||||
- The same sequence lights the same nodes after reload.
|
||||
- `?seed=B` changes layout but path timing remains stable.
|
||||
|
||||
### Increment 6 — path edge wavefront
|
||||
|
||||
Build:
|
||||
- Add render-path pipeline drawing additive edge wave traveling source -> target.
|
||||
- Timeline spine shows beat ticks matching wave arrival.
|
||||
|
||||
Verify:
|
||||
- Wavefront visibly travels along each path edge.
|
||||
- At beat arrival, the target node blooms.
|
||||
- Loop reset is seamless: final afterglow fades before frame 0.
|
||||
|
||||
### Increment 7 — low-cost GPU force sim
|
||||
|
||||
Build:
|
||||
- Add static edge attraction + centering + damping in compute.
|
||||
- Keep repulsion disabled or low-count O(N^2) only for <=500 nodes.
|
||||
|
||||
Verify:
|
||||
- Nodes subtly settle without CPU `ForceSimulation`.
|
||||
- Performance remains smooth at 300 nodes.
|
||||
- No CPU per-frame node position loops.
|
||||
|
||||
### Increment 8 — lifecycle effects one by one
|
||||
|
||||
Build/verify separately:
|
||||
- Born convergence particles: trigger in demo and verify deterministic convergence.
|
||||
- Backward ripple post pass: verify radial distortion travels effect -> cause.
|
||||
- Horizon drift/fog: silent/unavailable nodes visibly drift/fade toward horizon.
|
||||
- Firewall shockwave/membrane: crimson ring expands and fades without breaking path demo.
|
||||
|
||||
### Increment 9 — capture mode
|
||||
|
||||
Build:
|
||||
- Add `?capture=1` behavior: hide cursor, freeze random seed, optional `?frame=N` exact-frame render.
|
||||
- Add overlay copy button for canonical demo URL.
|
||||
|
||||
Verify:
|
||||
- Same URL + frame renders identical screenshot.
|
||||
- 12-second screen recording loops without discontinuity.
|
||||
|
||||
### Increment 10 — performance guardrails
|
||||
|
||||
Build:
|
||||
- Add telemetry: CPU frame ms estimate, GPU timestamp query only if supported, node count, buffer mode.
|
||||
- Cap default demo to 300 real nodes; support synthetic 10k only behind `?stress=10000`.
|
||||
|
||||
Verify:
|
||||
- No `mapAsync` in the frame loop except delayed optional profiling.
|
||||
- 300-node demo holds 60fps on Sam's M1 Max.
|
||||
- Stress mode degrades gracefully and can be disabled by removing query param.
|
||||
|
||||
## 5. Source index
|
||||
|
||||
WebGPU core patterns:
|
||||
- WebGPU Samples compute boids demo: https://webgpu.github.io/webgpu-samples/samples/computeBoids/
|
||||
- compute-boids main TS: https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/main.ts
|
||||
- compute-boids update WGSL: https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/updateSprites.wgsl
|
||||
- compute-boids sprite WGSL: https://raw.githubusercontent.com/webgpu/webgpu-samples/main/sample/computeBoids/sprite.wgsl
|
||||
- WebGPU storage buffers: https://webgpufundamentals.org/webgpu/lessons/webgpu-storage-buffers.html
|
||||
- WebGPU compute shaders: https://webgpufundamentals.org/webgpu/lessons/webgpu-compute-shaders.html
|
||||
- WebGPU canvas resize: https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
||||
- MDN WebGPU API: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API
|
||||
|
||||
Particle/lifecycle shader references:
|
||||
- Particle Life WebGPU article: https://lisyarus.github.io/blog/posts/particle-life-simulation-in-browser-using-webgpu.html
|
||||
- Particle Life demo: https://lisyarus.github.io/webgpu/particle-life.html
|
||||
- compute.toys: https://compute.toys/
|
||||
- compute.toys repo: https://github.com/compute-toys/compute.toys
|
||||
- Codrops WebGPU fluids: https://tympanus.net/codrops/2025/02/26/webgpu-fluid-simulations-high-performance-real-time-rendering/
|
||||
- Codrops WebGPU particles/fluids: https://tympanus.net/codrops/2025/01/29/particles-progress-and-perseverance-a-journey-into-webgpu-fluids/
|
||||
- Codrops Shader.se WebGPU transitions: https://tympanus.net/codrops/2026/05/19/80s-business-tech-seamless-scene-transitions-inside-shader-ses-scroll-driven-webgpu-pipeline/
|
||||
- Codrops False Earth WebGPU world: https://tympanus.net/codrops/2026/04/21/false-earth-from-webgl-limits-to-a-webgpu-driven-world/
|
||||
|
||||
GPU graph layout:
|
||||
- GraphWaGu repo: https://github.com/harp-lab/GraphWaGu
|
||||
- GraphWaGu force-directed TS: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/webgpu/force_directed.ts
|
||||
- GraphWaGu exact forces: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/compute_forces.wgsl
|
||||
- GraphWaGu Barnes-Hut forces: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/compute_forcesBH.wgsl
|
||||
- GraphWaGu apply forces: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/apply_forces.wgsl
|
||||
- GraphWaGu tree build: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/create_tree.wgsl
|
||||
- GraphWaGu radix sort: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/radix_sort.wgsl
|
||||
- GraphWaGu node vertex: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/node_vert.wgsl
|
||||
- GraphWaGu edge vertex: https://raw.githubusercontent.com/harp-lab/GraphWaGu/main/src/wgsl/edge_vert.wgsl
|
||||
- cosmos.gl repo: https://github.com/cosmograph-org/cosmos
|
||||
- cosmos.gl README: https://raw.githubusercontent.com/cosmograph-org/cosmos/main/README.md
|
||||
- Cosmograph product: https://cosmograph.app/
|
||||
|
||||
Svelte/DOM/determinism:
|
||||
- Svelte lifecycle hooks: https://svelte.dev/docs/svelte/lifecycle-hooks
|
||||
- MDN URLSearchParams: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
|
||||
- MDN pointer-events: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
|
||||
- Fixed timestep: https://gafferongames.com/post/fix_your_timestep/
|
||||
- seedrandom reference if a dependency is later preferred over local PRNG: https://github.com/davidbau/seedrandom
|
||||
|
||||
## 6. Non-negotiable implementation constraints
|
||||
|
||||
- New Observatory route only. Do not mutate the protected Memory Cinema block in `graph/+page.svelte`.
|
||||
- Keep existing Three/WebGL `Graph3D` intact. Observatory is a parallel WebGPU renderer, not a replacement in v1.
|
||||
- Do not add dependencies for v1. Use browser WebGPU, Svelte, TypeScript, and existing `three` only if needed for matrix math; prefer small local math helpers.
|
||||
- No `Math.random()` in demo-visible state. No `Date.now()`/`performance.now()` deciding simulation state.
|
||||
- No GPU readback in the frame loop. Profiling readback must be delayed and optional.
|
||||
- Every increment must render something verifiable before moving to the next effect.
|
||||
|
||||
---
|
||||
|
||||
## 7. VISUAL DNA — "from another dimension" (MANDATORY aesthetic contract)
|
||||
|
||||
Sam's directive (Jul 3 2026): the Observatory must be **mind-boggling** and look like it
|
||||
**came from another dimension** — the same grammar as the WebGPU waitlist hero and
|
||||
`docs/launch/causal-brain-demo.html`. This is NOT a dashboard skin. It is a living
|
||||
tissue. Every increment below inherits this section. Generic = rejected.
|
||||
|
||||
### 7.1 The signature palette (fuse two systems — do not invent a third)
|
||||
|
||||
TWO real palettes already exist in-repo. The Observatory FUSES them:
|
||||
|
||||
- **Meaning layer — FSRS state (from `lib/graph/nodes.ts`, use verbatim):**
|
||||
- active `#10b981` emerald · dormant `#f59e0b` amber · silent `#8b5cf6` violet · unavailable `#6b7280` slate
|
||||
- aha `#FFD700` · confusion/failure `#EF4444` · guardrail `#9CA3AF`
|
||||
- **Transcendence layer — iridescent thin-film (from `causal-brain-demo.html` `spectral(w)`):**
|
||||
a catmull blend around 4 anchors, w∈[0,1]:
|
||||
- indigo `vec3(0.20,0.28,0.95)` → cyan-teal `vec3(0.20,0.85,0.90)` → mint `vec3(0.45,1.00,0.72)` → magenta rim `vec3(0.85,0.45,1.00)`
|
||||
- CORE reads indigo/teal (living tissue); MOTION shifts toward cyan/magenta; NEVER muddy orange.
|
||||
- **Void:** background `#05060a` (near-black, `color-scheme: dark`). No grey dashboard chrome.
|
||||
- **Rule:** a node's BASE hue = its FSRS state color. Its ACTIVATION glow (recall, birth,
|
||||
ignite) rides the thin-film spectral band. So resting graph = meaningful; active graph = otherworldly.
|
||||
|
||||
Port `spectral(w)` to WGSL exactly (4-anchor catmull-ish blend). This is the single most
|
||||
important visual primitive — it is what makes it look alien instead of corporate.
|
||||
|
||||
### 7.2 Glow / bloom language (copy the demo's exact values, then push further in WebGPU)
|
||||
|
||||
- Additive radial glow blobs (`glow(x,y,rad,col,alpha)` in the demo) → in WebGPU, a real
|
||||
additive bloom pass. Node halos are `0 0 24px` soft; ignite events drop-shadow at
|
||||
`0 0 26px rgba(110,240,220,.45)` energy.
|
||||
- Text/instrument overlay glow: captions `text-shadow:0 0 24px rgba(30,180,255,.35)`;
|
||||
verdict headline `linear-gradient(90deg,#7fe6c0,#6ef0e6,#a6dcff)` clipped to text with
|
||||
`drop-shadow(0 0 26px rgba(110,240,220,.45))`; wordmark `letter-spacing:.28em`, `#5dcaa5`.
|
||||
- **Breath:** a global `pulse = 0.5 + 0.5*sin(t*0.002)` (~0.32Hz) modulates halo intensity so
|
||||
the whole field breathes even at rest. Living, never static.
|
||||
|
||||
### 7.3 DOM = instrument overlay ONLY (already the spec rule — here is the exact style)
|
||||
|
||||
Copy the demo's overlay contract: `.layer { position:fixed; inset:0; pointer-events:none }`
|
||||
over a full-bleed `inset:0` canvas. Instruments (TelemetryStrip, CommandSurface,
|
||||
TimelineSpine, InspectorPanel) are the ONLY DOM, styled like the demo's `.cap.mono`
|
||||
(SF Mono, `#cfe9ff`), `.verdict` (radial-gradient vignette card), `.wordmark`. NO KPI cards.
|
||||
NO solid panels. Instruments float, glow faintly, and never block the canvas
|
||||
(`pointer-events:auto` only on the specific interactive control).
|
||||
|
||||
### 7.4 The reference moment already exists in 2D — port it, don't reinvent
|
||||
|
||||
`causal-brain-demo.html` IS Moment C (salience-rescue / backward-trace) as a 2D canvas
|
||||
proof: brain point cloud (two lobes, center-dense), a failure flare on the deep right, a
|
||||
vector-search stall on confounders, then a BACKWARD arrow tracing to the dormant cause on
|
||||
the deep-left which **ignites**, then a verdict card ("Vestige 60% · vector search 0%"),
|
||||
then the VESTIGE wordmark. Beat clock: brain forms 0-1.5s, fail fades in ~0.3s, vector
|
||||
stalls 4-6.5s, backward trace fires 6.5-10.5s, verdict 10.5-13s, signature 13-15s, loop.
|
||||
The Observatory's `?demo=salience-rescue` must reproduce this exact narrative in real
|
||||
WebGPU with real memory nodes. Study its `spectral`, `seedBrain`, `glow`, and beat
|
||||
`schedule` before writing the WGSL.
|
||||
|
||||
### 7.5 Non-negotiable "another dimension" checklist (verifier MUST confirm each)
|
||||
|
||||
- [ ] Field breathes at rest (global pulse), never a static image.
|
||||
- [ ] Node base hue = FSRS state; activation = thin-film spectral. Both visible.
|
||||
- [ ] Real additive bloom on ignite/recall (not just opacity).
|
||||
- [ ] Void `#05060a`, zero grey dashboard chrome, zero KPI cards.
|
||||
- [ ] Instruments are glowing SF-Mono overlays with `pointer-events:none` except controls.
|
||||
- [ ] `?demo=salience-rescue` reproduces the causal-brain backward-trace narrative.
|
||||
- [ ] It looks like living tissue from another dimension, not a SaaS dashboard. If a
|
||||
reviewer would call it "clean" or "professional," it FAILED. The word is "alive."
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
apps/dashboard/build/_app/immutable/assets/0.IIz8MMYb.css.br
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/0.IIz8MMYb.css.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/0.IIz8MMYb.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/0.IIz8MMYb.css.gz
Normal file
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
@keyframes svelte-1n9p0vm-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in.svelte-1n9p0vm{animation:svelte-1n9p0vm-fade-in .3s ease-out}.live-status.svelte-1o4vd58{display:inline-flex;align-items:center;gap:.5rem;padding:.3rem .7rem;border-radius:999px;font-size:.75rem;font-weight:600;color:var(--color-recall, #34d399);background:color-mix(in srgb,var(--color-recall, #34d399) 12%,transparent);border:1px solid color-mix(in srgb,var(--color-recall, #34d399) 28%,transparent);white-space:nowrap}.live-status.idle.svelte-1o4vd58{color:var(--color-dim, #8b95a5);background:#ffffff0a;border-color:#ffffff14}.live-dot.svelte-1o4vd58{display:inline-block;flex-shrink:0}.count-chip.svelte-1o4vd58{display:inline-flex;align-items:baseline;gap:.35rem;padding:.3rem .7rem;border-radius:999px;font-size:.78rem;background:#ffffff08;border:1px solid rgba(255,255,255,.07)}.clear-btn.svelte-1o4vd58{display:inline-flex;align-items:center;gap:.3rem;padding:.3rem .65rem;border-radius:999px;font-size:.75rem;color:var(--color-muted, #6b7280);background:#ffffff05;border:1px solid rgba(255,255,255,.06);transition:color .2s ease,background .2s ease,border-color .2s ease}.clear-btn.svelte-1o4vd58:hover:not(:disabled){color:var(--color-text, #e5e7eb);background:#ffffff0d;border-color:#ffffff1f}.clear-btn.svelte-1o4vd58:disabled{opacity:.4;cursor:not-allowed}.event-row.svelte-1o4vd58{position:relative;transition:transform .28s cubic-bezier(.34,1.56,.64,1),box-shadow .28s ease,background .2s ease}.event-row.svelte-1o4vd58:hover{background:color-mix(in srgb,var(--evt) 7%,transparent)}.event-icon.svelte-1o4vd58{width:1.6rem;height:1.6rem;border-radius:.5rem}.empty-glyph.svelte-1o4vd58{display:inline-flex;align-items:center;justify-content:center;color:var(--color-synapse-glow, #818cf8);opacity:.85}@media not (prefers-reduced-motion:reduce){.empty-glyph.svelte-1o4vd58{animation:breathe 3.2s ease-in-out infinite}}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.cinema-overlay.svelte-1uwqs3k{position:fixed;top:0;right:0;bottom:0;left:0;z-index:200;background:radial-gradient(circle at 50% 40%,#05050f,#010108);display:flex;flex-direction:column}body.cinema-open .graph-stats-pill{display:none}.cinema-canvas.svelte-1uwqs3k{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.cinema-top.svelte-1uwqs3k{position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:max(.75rem,env(safe-area-inset-top)) 1rem .75rem;flex-wrap:wrap}.cinema-badge.svelte-1uwqs3k{font-size:.65rem;padding:.1rem .45rem;border-radius:999px;border:1px solid rgba(129,140,248,.4);color:var(--color-synapse-glow)}.cinema-badge-gpu.svelte-1uwqs3k{border-color:#14e8c680;color:#14e8c6}.cinema-act.svelte-1uwqs3k{font-size:.6rem;letter-spacing:.12em;text-transform:uppercase;color:var(--color-dream-glow);opacity:.85}.cinema-plan-card.svelte-1uwqs3k{position:absolute;z-index:3;top:50%;left:50%;transform:translate(-50%,-50%);max-width:520px;padding:1.5rem 1.75rem;border-radius:16px;text-align:center;animation:svelte-1uwqs3k-cinema-plan-in .5s ease both}@keyframes svelte-1uwqs3k-cinema-plan-in{0%{opacity:0;transform:translate(-50%,-46%)}to{opacity:1;transform:translate(-50%,-50%)}}.cinema-plan-kicker.svelte-1uwqs3k{font-size:.65rem;letter-spacing:.18em;text-transform:uppercase;color:var(--color-synapse-glow);margin-bottom:.5rem}.cinema-plan-logline.svelte-1uwqs3k{font-size:clamp(1.05rem,2.2vw,1.4rem);line-height:1.5;color:var(--color-bright);margin:0}.cinema-note.svelte-1uwqs3k{font-size:.78rem;color:var(--color-synapse-glow);opacity:.85;margin:0 0 .6rem;font-style:italic}.cinema-dot.svelte-1uwqs3k{width:8px;height:8px;border-radius:50%;background:var(--color-muted)}.cinema-dot.active.svelte-1uwqs3k{background:#14e8c6;box-shadow:0 0 10px #14e8c6}.cinema-toggle.svelte-1uwqs3k{font-size:.7rem;color:var(--color-dim);display:flex;align-items:center;gap:.3rem;cursor:pointer}.cinema-close.svelte-1uwqs3k{background:transparent;border:1px solid rgba(255,255,255,.15);color:var(--color-text);border-radius:8px;width:32px;height:32px;cursor:pointer}.cinema-caption-wrap.svelte-1uwqs3k{position:relative;z-index:2;margin-top:auto;padding:1rem 1.25rem max(1.25rem,env(safe-area-inset-bottom));max-width:720px}.cinema-chip.svelte-1uwqs3k{display:inline-block;font-size:.65rem;text-transform:uppercase;letter-spacing:.08em;color:var(--color-dream-glow);margin-bottom:.35rem}.cinema-caption.svelte-1uwqs3k{font-size:clamp(1.05rem,2.4vw,1.6rem);line-height:1.45;color:var(--color-bright);text-shadow:0 2px 24px rgba(0,0,0,.9);min-height:2.6em;margin:0 0 .75rem}.cinema-progress.svelte-1uwqs3k{height:3px;background:#ffffff1a;border-radius:3px;overflow:hidden}.cinema-progress-fill.svelte-1uwqs3k{height:100%;background:linear-gradient(90deg,var(--color-synapse),color-mix(in oklch,var(--color-dream),#ff2d55 calc(var(--tension, 0) * 100%)));transition:width .2s linear,background .4s ease}.cinema-beatcount.svelte-1uwqs3k{margin-top:.4rem;display:flex;gap:.75rem;align-items:center}.cinema-replay.svelte-1uwqs3k{background:transparent;border:1px solid rgba(129,140,248,.4);color:var(--color-synapse-glow);border-radius:999px;padding:.15rem .7rem;cursor:pointer;font-size:.75rem}.cinema-dream.svelte-1uwqs3k{color:var(--color-dream-glow);letter-spacing:.08em;animation:svelte-1uwqs3k-cinema-dream-pulse 3s ease-in-out infinite}.cinema-restore.svelte-1uwqs3k{position:absolute;bottom:.6rem;right:.8rem;z-index:95;background:#0a0a1a80;border:1px solid rgba(129,140,248,.25);color:var(--color-muted);border-radius:999px;padding:.2rem .7rem;font-size:.7rem;letter-spacing:.04em;cursor:pointer;opacity:.4;transition:opacity .2s ease}.cinema-restore.svelte-1uwqs3k:hover{opacity:1}@keyframes svelte-1uwqs3k-cinema-dream-pulse{0%,to{opacity:.55}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.cinema-progress-fill.svelte-1uwqs3k{transition:none}}
|
||||
Binary file not shown.
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/13.Bjd0S47S.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/13.Bjd0S47S.css.gz
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/15.ChjqzJHo.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/15.ChjqzJHo.css.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.conn-pill.svelte-15kgmsr{display:inline-flex;align-items:center;gap:.5rem;padding:.3rem .7rem;border-radius:999px;font-size:.75rem;font-weight:600;color:var(--color-recall, #34d399);background:color-mix(in srgb,var(--color-recall, #34d399) 12%,transparent);border:1px solid color-mix(in srgb,var(--color-recall, #34d399) 28%,transparent);white-space:nowrap}.conn-pill.idle.svelte-15kgmsr{color:var(--color-dim, #8b95a5);background:#ffffff0a;border-color:#ffffff14}.conn-dot.svelte-15kgmsr{display:inline-block;flex-shrink:0}.refresh-btn.svelte-15kgmsr{display:inline-flex;align-items:center;gap:.3rem;padding:.3rem .65rem;border-radius:999px;font-size:.75rem;color:var(--color-muted, #6b7280);background:#ffffff05;border:1px solid rgba(255,255,255,.06);transition:color .2s ease,background .2s ease,border-color .2s ease}.refresh-btn.svelte-15kgmsr:hover{color:var(--color-text, #e5e7eb);background:#ffffff0d;border-color:#ffffff1f}.logo-tile.svelte-15kgmsr{position:relative}.logo-tile.svelte-15kgmsr:after{content:"";position:absolute;top:-1px;right:-1px;bottom:-1px;left:-1px;border-radius:inherit;box-shadow:0 0 18px -2px var(--color-synapse-glow, #818cf8);opacity:.4;pointer-events:none}@media not (prefers-reduced-motion:reduce){.logo-tile.svelte-15kgmsr:after{animation:svelte-15kgmsr-logo-glow 4s ease-in-out infinite}@keyframes svelte-15kgmsr-logo-glow{0%,to{opacity:.25}50%{opacity:.55}}}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.metric-card.svelte-w41m0t{cursor:default}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
€.metric-card.svelte-w41m0t{cursor:default}
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/5.DQ_AfUnN.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/5.DQ_AfUnN.css.gz
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
apps/dashboard/build/_app/immutable/assets/6.BSSBWVKL.css.br
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/6.BSSBWVKL.css.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/6.BSSBWVKL.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/6.BSSBWVKL.css.gz
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
@keyframes svelte-1uyjqky-fadeSlide{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
||||
BIN
apps/dashboard/build/_app/immutable/assets/7.CCrNEDd3.css.br
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/7.CCrNEDd3.css.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/7.CCrNEDd3.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/7.CCrNEDd3.css.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
@keyframes svelte-1n9p0vm-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in.svelte-1n9p0vm{animation:svelte-1n9p0vm-fade-in .3s ease-out}
|
||||
BIN
apps/dashboard/build/_app/immutable/assets/9.BBx09UGv.css.br
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/9.BBx09UGv.css.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/assets/9.BBx09UGv.css.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/assets/9.BBx09UGv.css.gz
Normal file
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.dd.svelte-1fd3ybn{position:relative;display:inline-flex;flex-direction:column;gap:.3rem}.dd-label.svelte-1fd3ybn{font-size:.65rem;text-transform:uppercase;letter-spacing:.08em;color:var(--color-muted);padding-left:.15rem}.dd-trigger.svelte-1fd3ybn{display:inline-flex;align-items:center;gap:.5rem;padding:.55rem .7rem .55rem .8rem;min-width:9rem;background:#ffffff08;border:1px solid rgba(99,102,241,.12);border-radius:.75rem;color:var(--color-text);font-size:.8rem;font-family:inherit;cursor:pointer;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);transition:border-color .2s ease,background .2s ease,box-shadow .2s ease}.dd-trigger.svelte-1fd3ybn:hover{border-color:#6366f14d;background:#ffffff0d}.dd-trigger.svelte-1fd3ybn:focus-visible,.dd-trigger.dd-open.svelte-1fd3ybn{outline:none;border-color:#6366f180;box-shadow:0 0 0 3px #6366f11f}.dd-trigger-icon.svelte-1fd3ybn{color:var(--color-synapse-glow);display:inline-flex}.dd-value.svelte-1fd3ybn{flex:1;text-align:left;display:inline-flex;align-items:center;gap:.45rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dd-placeholder.svelte-1fd3ybn{color:var(--color-muted)}.dd-dot.svelte-1fd3ybn{width:.5rem;height:.5rem;border-radius:50%;flex-shrink:0;box-shadow:0 0 6px currentColor}.dd-chevron.svelte-1fd3ybn{color:var(--color-dim);display:inline-flex;transition:transform .25s cubic-bezier(.34,1.56,.64,1)}.dd-chevron-open.svelte-1fd3ybn{transform:rotate(180deg);color:var(--color-synapse-glow)}.dd-menu.svelte-1fd3ybn{position:absolute;top:calc(100% + .4rem);left:0;z-index:60;min-width:100%;max-height:18rem;overflow-y:auto;padding:.35rem;border-radius:.85rem;transform-origin:top center}@media not (prefers-reduced-motion:reduce){.dd-menu.svelte-1fd3ybn{animation:svelte-1fd3ybn-dd-pop .18s cubic-bezier(.34,1.56,.64,1)}@keyframes svelte-1fd3ybn-dd-pop{0%{opacity:0;transform:translateY(-6px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}}.dd-option.svelte-1fd3ybn{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .6rem;border:none;background:transparent;color:var(--color-dim);font-size:.8rem;font-family:inherit;text-align:left;border-radius:.6rem;cursor:pointer;transition:background .12s ease,color .12s ease}.dd-active.svelte-1fd3ybn{background:#6366f124;color:var(--color-text)}.dd-selected.svelte-1fd3ybn{color:var(--color-synapse-glow)}.dd-opt-icon.svelte-1fd3ybn{color:var(--color-dim);display:inline-flex}.dd-active.svelte-1fd3ybn .dd-opt-icon:where(.svelte-1fd3ybn){color:var(--color-synapse-glow)}.dd-opt-label.svelte-1fd3ybn{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dd-badge.svelte-1fd3ybn{font-size:.65rem;font-variant-numeric:tabular-nums;color:var(--color-muted);background:#ffffff0d;padding:.05rem .4rem;border-radius:.4rem}.dd-check.svelte-1fd3ybn{color:var(--color-synapse-glow);display:inline-flex}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.vestige-icon.svelte-1eqehiz{display:inline-block;flex-shrink:0;vertical-align:middle;overflow:visible}@media not (prefers-reduced-motion:reduce){.vestige-icon-draw.svelte-1eqehiz path,.vestige-icon-draw.svelte-1eqehiz circle,.vestige-icon-draw.svelte-1eqehiz rect{stroke-dasharray:64;stroke-dashoffset:64;animation:svelte-1eqehiz-icon-draw .7s cubic-bezier(.65,0,.35,1) forwards}@keyframes svelte-1eqehiz-icon-draw{to{stroke-dashoffset:0}}}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
.header-tile.svelte-162svzm:after{content:"";position:absolute;top:-1px;right:-1px;bottom:-1px;left:-1px;border-radius:inherit;box-shadow:0 0 18px -2px currentColor;opacity:.35;pointer-events:none}@media not (prefers-reduced-motion:reduce){.header-tile.svelte-162svzm:after{animation:svelte-162svzm-tile-glow 4s ease-in-out infinite}@keyframes svelte-162svzm-tile-glow{0%,to{opacity:.22}50%{opacity:.5}}}.text-balance.svelte-162svzm{text-wrap:balance}.text-pretty.svelte-162svzm{text-wrap:pretty}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,2 +0,0 @@
|
|||
import{D as z,q as dr,aD as sr,G as A,L as U,N as gr,T as pr,g as m,U as hr,W as _r,X as x,K,M as G,I as Er,aE as Ar,aF as y,w as Sr,aG as b,$ as q,aH as Tr,a1 as Nr,ao as br,z as Ir,aI as V,aJ as Mr,aK as Or,ac as Cr,aL as rr,aM as Rr,Y as ur,_ as or,aN as P,R as lr,aO as Lr,aP as wr,aQ as Hr,Z as kr,J as Dr,aR as Fr,aS as Gr,aT as zr,aU as Ur,aV as tr,aW as Kr}from"./wpu9U-D0.js";function jr(r,e){return e}function Pr(r,e,f){for(var a=[],n=e.length,s,u=e.length,v=0;v<n;v++){let g=e[v];or(g,()=>{if(s){if(s.pending.delete(g),s.done.add(g),s.pending.size===0){var t=r.outrogroups;B(V(s.done)),t.delete(s),t.size===0&&(r.outrogroups=null)}}else u-=1},!1)}if(u===0){var o=a.length===0&&f!==null;if(o){var d=f,l=d.parentNode;Hr(l),l.append(d),r.items.clear()}B(e,!o)}else s={pending:new Set(e),done:new Set},(r.outrogroups??(r.outrogroups=new Set)).add(s)}function B(r,e=!0){for(var f=0;f<r.length;f++)kr(r[f],e)}var er;function mr(r,e,f,a,n,s=null){var u=r,v=new Map,o=(e&sr)!==0;if(o){var d=r;u=A?U(gr(d)):d.appendChild(z())}A&&pr();var l=null,g=br(()=>{var c=f();return Ir(c)?c:c==null?[]:V(c)}),t,p=!0;function S(){i.fallback=l,Yr(i,t,u,e,a),l!==null&&(t.length===0?(l.f&b)===0?ur(l):(l.f^=b,k(l,null,u)):or(l,()=>{l=null}))}var T=dr(()=>{t=m(g);var c=t.length;let C=!1;if(A){var R=hr(u)===_r;R!==(c===0)&&(u=x(),U(u),K(!1),C=!0)}for(var _=new Set,M=Sr,L=Nr(),h=0;h<c;h+=1){A&&G.nodeType===Er&&G.data===Ar&&(u=G,C=!0,K(!1));var O=t[h],w=a(O,h),E=p?null:v.get(w);E?(E.v&&y(E.v,O),E.i&&y(E.i,h),L&&M.unskip_effect(E.e)):(E=qr(v,p?u:er??(er=z()),O,w,h,n,e,f),p||(E.e.f|=b),v.set(w,E)),_.add(w)}if(c===0&&s&&!l&&(p?l=q(()=>s(u)):(l=q(()=>s(er??(er=z()))),l.f|=b)),c>_.size&&Tr(),A&&c>0&&U(x()),!p)if(L){for(const[D,F]of v)_.has(D)||M.skip_effect(F.e);M.oncommit(S),M.ondiscard(()=>{})}else S();C&&K(!0),m(g)}),i={effect:T,items:v,outrogroups:null,fallback:l};p=!1,A&&(u=G)}function H(r){for(;r!==null&&(r.f&Lr)===0;)r=r.next;return r}function Yr(r,e,f,a,n){var E,D,F,X,J,W,$,Q,Z;var s=(a&wr)!==0,u=e.length,v=r.items,o=H(r.effect.first),d,l=null,g,t=[],p=[],S,T,i,c;if(s)for(c=0;c<u;c+=1)S=e[c],T=n(S,c),i=v.get(T).e,(i.f&b)===0&&((D=(E=i.nodes)==null?void 0:E.a)==null||D.measure(),(g??(g=new Set)).add(i));for(c=0;c<u;c+=1){if(S=e[c],T=n(S,c),i=v.get(T).e,r.outrogroups!==null)for(const N of r.outrogroups)N.pending.delete(i),N.done.delete(i);if((i.f&b)!==0)if(i.f^=b,i===o)k(i,null,f);else{var C=l?l.next:o;i===r.effect.last&&(r.effect.last=i.prev),i.prev&&(i.prev.next=i.next),i.next&&(i.next.prev=i.prev),I(r,l,i),I(r,i,C),k(i,C,f),l=i,t=[],p=[],o=H(l.next);continue}if((i.f&P)!==0&&(ur(i),s&&((X=(F=i.nodes)==null?void 0:F.a)==null||X.unfix(),(g??(g=new Set)).delete(i))),i!==o){if(d!==void 0&&d.has(i)){if(t.length<p.length){var R=p[0],_;l=R.prev;var M=t[0],L=t[t.length-1];for(_=0;_<t.length;_+=1)k(t[_],R,f);for(_=0;_<p.length;_+=1)d.delete(p[_]);I(r,M.prev,L.next),I(r,l,M),I(r,L,R),o=R,l=L,c-=1,t=[],p=[]}else d.delete(i),k(i,o,f),I(r,i.prev,i.next),I(r,i,l===null?r.effect.first:l.next),I(r,l,i),l=i;continue}for(t=[],p=[];o!==null&&o!==i;)(d??(d=new Set)).add(o),p.push(o),o=H(o.next);if(o===null)continue}(i.f&b)===0&&t.push(i),l=i,o=H(i.next)}if(r.outrogroups!==null){for(const N of r.outrogroups)N.pending.size===0&&(B(V(N.done)),(J=r.outrogroups)==null||J.delete(N));r.outrogroups.size===0&&(r.outrogroups=null)}if(o!==null||d!==void 0){var h=[];if(d!==void 0)for(i of d)(i.f&P)===0&&h.push(i);for(;o!==null;)(o.f&P)===0&&o!==r.fallback&&h.push(o),o=H(o.next);var O=h.length;if(O>0){var w=(a&sr)!==0&&u===0?f:null;if(s){for(c=0;c<O;c+=1)($=(W=h[c].nodes)==null?void 0:W.a)==null||$.measure();for(c=0;c<O;c+=1)(Z=(Q=h[c].nodes)==null?void 0:Q.a)==null||Z.fix()}Pr(r,h,w)}}s&&lr(()=>{var N,j;if(g!==void 0)for(i of g)(j=(N=i.nodes)==null?void 0:N.a)==null||j.apply()})}function qr(r,e,f,a,n,s,u,v){var o=(u&Mr)!==0?(u&Or)===0?Cr(f,!1,!1):rr(f):null,d=(u&Rr)!==0?rr(n):null;return{v:o,i:d,e:q(()=>(s(e,o??f,d??n,v),()=>{r.delete(a)}))}}function k(r,e,f){if(r.nodes)for(var a=r.nodes.start,n=r.nodes.end,s=e&&(e.f&b)===0?e.nodes.start:f;a!==null;){var u=Dr(a);if(s.before(a),a===n)return;a=u}}function I(r,e,f){e===null?r.effect.first=f:e.next=f,f===null?r.effect.last=e:f.prev=e}function cr(r){var e,f,a="";if(typeof r=="string"||typeof r=="number")a+=r;else if(typeof r=="object")if(Array.isArray(r)){var n=r.length;for(e=0;e<n;e++)r[e]&&(f=cr(r[e]))&&(a&&(a+=" "),a+=f)}else for(f in r)r[f]&&(a&&(a+=" "),a+=f);return a}function Br(){for(var r,e,f=0,a="",n=arguments.length;f<n;f++)(r=arguments[f])&&(e=cr(r))&&(a&&(a+=" "),a+=e);return a}function xr(r){return typeof r=="object"?Br(r):r??""}const fr=[...`
|
||||
\r\f \v\uFEFF`];function Vr(r,e,f){var a=r==null?"":""+r;if(e&&(a=a?a+" "+e:e),f){for(var n of Object.keys(f))if(f[n])a=a?a+" "+n:n;else if(a.length)for(var s=n.length,u=0;(u=a.indexOf(n,u))>=0;){var v=u+s;(u===0||fr.includes(a[u-1]))&&(v===a.length||fr.includes(a[v]))?a=(u===0?"":a.substring(0,u))+a.substring(v+1):u=v}}return a===""?null:a}function ar(r,e=!1){var f=e?" !important;":";",a="";for(var n of Object.keys(r)){var s=r[n];s!=null&&s!==""&&(a+=" "+n+": "+s+f)}return a}function Y(r){return r[0]!=="-"||r[1]!=="-"?r.toLowerCase():r}function yr(r,e){if(e){var f="",a,n;if(Array.isArray(e)?(a=e[0],n=e[1]):a=e,r){r=String(r).replaceAll(/\s*\/\*.*?\*\/\s*/g,"").trim();var s=!1,u=0,v=!1,o=[];a&&o.push(...Object.keys(a).map(Y)),n&&o.push(...Object.keys(n).map(Y));var d=0,l=-1;const T=r.length;for(var g=0;g<T;g++){var t=r[g];if(v?t==="/"&&r[g-1]==="*"&&(v=!1):s?s===t&&(s=!1):t==="/"&&r[g+1]==="*"?v=!0:t==='"'||t==="'"?s=t:t==="("?u++:t===")"&&u--,!v&&s===!1&&u===0){if(t===":"&&l===-1)l=g;else if(t===";"||g===T-1){if(l!==-1){var p=Y(r.substring(d,l).trim());if(!o.includes(p)){t!==";"&&g++;var S=r.substring(d,g).trim();f+=" "+S+";"}}d=g+1,l=-1}}}}return a&&(f+=ar(a)),n&&(f+=ar(n,!0)),f=f.trim(),f===""?null:f}return r==null?null:String(r)}function re(r,e,f,a,n,s){var u=r.__className;if(A||u!==f||u===void 0){var v=Vr(f,a,s);(!A||v!==r.getAttribute("class"))&&(v==null?r.removeAttribute("class"):e?r.className=v:r.setAttribute("class",v)),r.__className=f}else if(s&&n!==s)for(var o in s){var d=!!s[o];(n==null||d!==!!n[o])&&r.classList.toggle(o,d)}return s}const Xr=Symbol("is custom element"),Jr=Symbol("is html"),Wr=tr?"link":"LINK",$r=tr?"progress":"PROGRESS";function ee(r){if(A){var e=!1,f=()=>{if(!e){if(e=!0,r.hasAttribute("value")){var a=r.value;ir(r,"value",null),r.value=a}if(r.hasAttribute("checked")){var n=r.checked;ir(r,"checked",null),r.checked=n}}};r.__on_r=f,lr(f),Kr()}}function fe(r,e){var f=vr(r);f.value===(f.value=e??void 0)||r.value===e&&(e!==0||r.nodeName!==$r)||(r.value=e??"")}function ir(r,e,f,a){var n=vr(r);A&&(n[e]=r.getAttribute(e),e==="src"||e==="srcset"||e==="href"&&r.nodeName===Wr)||n[e]!==(n[e]=f)&&(e==="loading"&&(r[Fr]=f),f==null?r.removeAttribute(e):typeof f!="string"&&Qr(r).includes(e)?r[e]=f:r.setAttribute(e,f))}function vr(r){return r.__attributes??(r.__attributes={[Xr]:r.nodeName.includes("-"),[Jr]:r.namespaceURI===Gr})}var nr=new Map;function Qr(r){var e=r.getAttribute("is")||r.nodeName,f=nr.get(e);if(f)return f;nr.set(e,f=[]);for(var a,n=r,s=Element.prototype;s!==n;){a=Ur(n);for(var u in a)a[u].set&&f.push(u);n=zr(n)}return f}export{ir as a,fe as b,xr as c,mr as e,jr as i,ee as r,re as s,yr as t};
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,2 +0,0 @@
|
|||
import"./Bzak7iHL.js";import{t as h,a as o,j as f,e as a,r as s,h as c}from"./wpu9U-D0.js";import{s as p}from"./D8mhvFt8.js";import{s as k}from"./LDOJP_6N.js";import{i as _}from"./DKve45Wd.js";import{s as I}from"./60_R_Vbt.js";import{p as P}from"./ByYB047u.js";import{I as H}from"./D7A-gG4Z.js";var q=f('<p class="text-sm text-dim mt-0.5 text-pretty svelte-162svzm"> </p>'),A=f('<div class="flex items-center gap-2 shrink-0 flex-wrap justify-end svelte-162svzm"><!></div>'),B=f('<header class="flex items-start justify-between gap-4 mb-6 enter svelte-162svzm"><div class="flex items-center gap-3.5 min-w-0 svelte-162svzm"><div><!></div> <div class="min-w-0 svelte-162svzm"><h1 class="text-2xl font-bold text-aurora leading-tight text-balance svelte-162svzm"> </h1> <!></div></div> <!></header>');function M(u,e){let v=P(e,"accent",3,"synapse");var l=B(),m=a(l),i=a(m),b=a(i);H(b,{get name(){return e.icon},size:22,draw:!0}),s(i);var x=c(i,2),d=a(x),g=a(d,!0);s(d);var z=c(d,2);{var w=t=>{var r=q(),n=a(r,!0);s(r),h(()=>p(n,e.subtitle)),o(t,r)};_(z,t=>{e.subtitle&&t(w)})}s(x),s(m);var y=c(m,2);{var j=t=>{var r=A(),n=a(r);k(n,()=>e.children),s(r),o(t,r)};_(y,t=>{e.children&&t(j)})}s(l),h(()=>{I(i,1,`header-tile relative flex items-center justify-center w-11 h-11 rounded-xl shrink-0
|
||||
bg-${v()??""}/12 border border-${v()??""}/25 text-${v()??""}-glow`,"svelte-162svzm"),p(g,e.title)}),o(u,l)}export{M as P};
|
||||
Binary file not shown.
Binary file not shown.
2
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js
Normal file
2
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
const e=[...`
|
||||
\r\f \v\uFEFF`];function o(t,f,u){var n=t==null?"":""+t;if(f&&(n=n?n+" "+f:f),u){for(var s of Object.keys(u))if(u[s])n=n?n+" "+s:s;else if(n.length)for(var i=s.length,l=0;(l=n.indexOf(s,l))>=0;){var r=l+i;(l===0||e.includes(n[l-1]))&&(r===n.length||e.includes(n[r]))?n=(l===0?"":n.substring(0,l))+n.substring(r+1):l=r}}return n===""?null:n}function c(t,f){return t==null?null:String(t)}export{c as a,o as t};
|
||||
BIN
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js.br
Normal file
BIN
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/chunks/BKuqSeVd.js.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
var B=Object.defineProperty;var g=i=>{throw TypeError(i)};var F=(i,e,s)=>e in i?B(i,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):i[e]=s;var w=(i,e,s)=>F(i,typeof e!="symbol"?e+"":e,s),M=(i,e,s)=>e.has(i)||g("Cannot "+s);var t=(i,e,s)=>(M(i,e,"read from private field"),s?s.call(i):e.get(i)),l=(i,e,s)=>e.has(i)?g("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(i):e.set(i,s),y=(i,e,s,a)=>(M(i,e,"write to private field"),a?a.call(i,s):e.set(i,s),s);import{w as D,Y as C,Z as k,_ as G,D as x,$ as A,G as S,M as Y,a0 as Z,a1 as $}from"./wpu9U-D0.js";var r,n,h,u,p,_,v;class z{constructor(e,s=!0){w(this,"anchor");l(this,r,new Map);l(this,n,new Map);l(this,h,new Map);l(this,u,new Set);l(this,p,!0);l(this,_,()=>{var e=D;if(t(this,r).has(e)){var s=t(this,r).get(e),a=t(this,n).get(s);if(a)C(a),t(this,u).delete(s);else{var c=t(this,h).get(s);c&&(t(this,n).set(s,c.effect),t(this,h).delete(s),c.fragment.lastChild.remove(),this.anchor.before(c.fragment),a=c.effect)}for(const[f,o]of t(this,r)){if(t(this,r).delete(f),f===e)break;const d=t(this,h).get(o);d&&(k(d.effect),t(this,h).delete(o))}for(const[f,o]of t(this,n)){if(f===s||t(this,u).has(f))continue;const d=()=>{if(Array.from(t(this,r).values()).includes(f)){var b=document.createDocumentFragment();Z(o,b),b.append(x()),t(this,h).set(f,{effect:o,fragment:b})}else k(o);t(this,u).delete(f),t(this,n).delete(f)};t(this,p)||!a?(t(this,u).add(f),G(o,d,!1)):d()}}});l(this,v,e=>{t(this,r).delete(e);const s=Array.from(t(this,r).values());for(const[a,c]of t(this,h))s.includes(a)||(k(c.effect),t(this,h).delete(a))});this.anchor=e,y(this,p,s)}ensure(e,s){var a=D,c=$();if(s&&!t(this,n).has(e)&&!t(this,h).has(e))if(c){var f=document.createDocumentFragment(),o=x();f.append(o),t(this,h).set(e,{effect:A(()=>s(o)),fragment:f})}else t(this,n).set(e,A(()=>s(this.anchor)));if(t(this,r).set(a,e),c){for(const[d,m]of t(this,n))d===e?a.unskip_effect(m):a.skip_effect(m);for(const[d,m]of t(this,h))d===e?a.unskip_effect(m.effect):a.skip_effect(m.effect);a.oncommit(t(this,_)),a.ondiscard(t(this,v))}else S&&(this.anchor=Y),t(this,_).call(this)}}r=new WeakMap,n=new WeakMap,h=new WeakMap,u=new WeakMap,p=new WeakMap,_=new WeakMap,v=new WeakMap;export{z as B};
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
1
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js
Normal file
1
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{J as T,K as m,P as D,g as P,c as b,h as B,L as M,M as N,N as U,O as Y,A as h,Q as x,R as $,T as q,U as w,V as z,W as C,S as G,X as J}from"./CvjSAYrz.js";import{c as K}from"./D81f-o_I.js";function W(r,a,t,s){var O;var f=!x||(t&$)!==0,v=(t&Y)!==0,o=(t&C)!==0,n=s,c=!0,g=()=>(c&&(c=!1,n=o?h(s):s),n),u;if(v){var A=G in r||J in r;u=((O=T(r,a))==null?void 0:O.set)??(A&&a in r?e=>r[a]=e:void 0)}var _,I=!1;v?[_,I]=K(()=>r[a]):_=r[a],_===void 0&&s!==void 0&&(_=g(),u&&(f&&m(),u(_)));var i;if(f?i=()=>{var e=r[a];return e===void 0?g():(c=!0,e)}:i=()=>{var e=r[a];return e!==void 0&&(n=void 0),e===void 0?n:e},f&&(t&D)===0)return i;if(u){var E=r.$$legacy;return(function(e,S){return arguments.length>0?((!f||!S||E||I)&&u(S?i():e),e):i()})}var l=!1,d=((t&q)!==0?w:z)(()=>(l=!1,i()));v&&P(d);var L=N;return(function(e,S){if(arguments.length>0){const R=S?P(d):f&&v?b(e):e;return B(d,R),l=!0,n!==void 0&&(n=R),e}return M&&l||(L.f&U)!==0?d.v:P(d)})}export{W as p};
|
||||
BIN
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.br
Normal file
BIN
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.br
Normal file
Binary file not shown.
BIN
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.gz
Normal file
BIN
apps/dashboard/build/_app/immutable/chunks/B_YDQCB6.js.gz
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue