agentleFS
GabrielMartinMoranGabrielMartinMoran/mind/AGENTS.md

mind

AGENTS.md193 starsChanged 26 days agoMITView on GitHub

This document describes the mind project's architecture, behavior, technical choices, and usage. It is intended for AI agents and human maintainers. Read Mind's purpose and philosophy to understand the product goal and principles, and CONTRIBUTING.md for the contribution workflow. Agents should read the philosophy page before proposing or implementing product behavior. Agents that modify this codebase must keep this file updated when they change architecture, add commands, change config, or alter behavior (see Keeping this document updated). mind is a…

  • Reads credentials
  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,700 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository5 other files it gives its agents.

The file

We split this AGENTS.md into the rules it gives an agent

4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Storage: All persistent data goes through the MindStore interface (defined in src/store/mind-store.ts), implemented by createSqliteStore …

    line 45
  2. Very specific:

    Output: All user-facing messages go through the Logger interface (src/helpers/logger.ts), so tests can swap in a mock logger.

    line 47
  3. Very specific:

    LRU eviction: when a tier is full, the least-recently-used non-pinned memory is demoted one tier down (no cascading).

    line 105
  4. Very specific:

    Search reset behavior is covered by web/test/search-controller.spec.ts (clears stale results without a request) and …

    line 161

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

AGENTS.md — Project guide for AI agents and maintainers

This document describes the mind project's architecture, behavior, technical choices, and usage. It is intended for AI agents and human maintainers. Read Mind's purpose and philosophy to understand the product goal and principles, and CONTRIBUTING.md for the contribution workflow. Agents should read the philosophy page before proposing or implementing product behavior. Agents that modify this codebase must keep this file updated when they change architecture, add commands, change config, or alter behavior (see Keeping this document updated).


1. Project overview

mind is a local, open-source persistent cognitive workspace for AI coding agents. It preserves useful project and work context—decisions, constraints, discoveries, and unfinished tasks—so agents can resume across sessions, tools, and context windows. Its purpose and guiding principles are documented in Mind's philosophy. Data is organized into named spaces containing memories, with full-text search, tags, links, checkpoints, session summaries, living references, and a 3-tier access-frequency system.

  • Runtime: Bun
  • Language: TypeScript (strict mode, ESNext)
  • Entry point: the mind Bash script at project root; invokes src/mind.ts. Supports subcommands: serve (HTTP server), mcp (MCP server), setup (agent configuration), and update (self-update from GitHub releases). Also supports --complete flag to delegate to src/complete.ts (not yet implemented).
  • Persistence: SQLite database at data/mind.db (path configurable via MIND_DATA_DIR env var or MIND_DB_PATH for full path override). The legacy brain.json is supported as a migration source via mind import.
  • RAG/Embeddings: Optional semantic search with a selectable embedding provider (MIND_EMBEDDING_PROVIDER: openai default or openrouter; invalid values disable RAG without fallback). Enable with MIND_RAG=true + OPENAI_API_KEY (OpenAI) or OPENROUTER_API_KEY (OpenRouter). The model stays text-embedding-3-small (openai/text-embedding-3-small on OpenRouter) at 1536 dimensions, so stored vectors remain compatible without re-embedding. Embeddings are stored as BLOBs in SQLite and generated with an awaited request on add/update/move/patch (not fire-and-forget).
  • Search pipeline: One unified relevance pipeline backs CLI search, MCP memory_query(search), and GET /api/search. A parser turns input into an AST (quoted "phrases", uppercase OR, AND, NOT, trailing *; lowercase operator words are ordinary terms; malformed input degrades to a literal AND and never makes parseQuery throw) and logically independent channels collect candidates: lexical rungs (phrase → all → any), trigram substring, fuzzy (Damerau–Levenshtein ≤2, capped expansions), LIKE for sub-trigram terms, token-set coverage, and the optional semantic channel. The channels execute sequentially on one synchronous SQLite connection, so “fan-out” describes the candidate model, not concurrent execution. Parser syntax fallback and search-level validation are separate: a supplied search whose positive text has no informative term after common stopwords are removed throws one typed validation error before any channel or embedding call, even when the parser degraded the query; an omitted field stays a metadata listing (MCP) or an empty 200 response (API). For plain questions containing ? or ¿, lexical recall uses informative non-stopword terms, keeps complementary partial matches, and lets fusion rank them; unpunctuated keyword searches and explicit searches keep strict admission. A per-query weighted fusion (with an agreement bonus) ranks results deterministically and attaches a per-result confidence bucket (high/medium/low) plus methods provenance. Semantic admission is independent of the lexical gate: natural-language queries (one group, no NOT, only plain terms, no explicit uppercase AND) admit semantic candidates at cosine ≥0.6 even when lexical results exist, while explicit phrases, prefixes, and operators stay lexical. With RAG off the semantic channel is omitted silently; a query-time embedding failure opens a ~5-minute in-memory breaker so a failing provider cannot trigger retry storms.
  • Layout: src/ contains CLI, MCP, and API server code. test/ contains backend/CLI tests. web/ contains frontend source (web/src), styles (web/styles), static assets (web/assets), static HTML shell (web/public), and web-specific tests (web/test). scripts/ contains E2E and evaluation scripts (including scripts/search-eval.ts, the relevance-suite runner).
  • Cognitive lifecycle docs: The documentation index groups all living pages. docs/cognitive-memory-lifecycle.md explains the memory model, tiers, lifecycle, writing, supersession, linking, living references, and tool usage; docs/skill-first-distribution.md explains the skill-first activation and installation model; docs/agent-integration-matrix.md records per-client paths and validation status; and docs/search-engine.md describes current retrieval behavior. Exceptional historical evidence lives under docs/history/; execution, merge, and validation reports stay in .pas/, and no report is added to the docs root. The normative agent instructions remain the canonical protocol in src/resources/protocols/mind-cognitive-protocol.md.
  • Neural Map MVP: web SPA includes a read-only per-space graph view using a minimal graph API payload and on-demand memory detail fetch, with adaptive multi-lane radial placement, dense-map culling (no persistent labels; one transient label on hover/focus/selection, bounded edges, in-circle degree numbers, zero overlaps), dragging that never selects graph text (the accessible table stays selectable), and higher zoom ceiling for dense maps.
  • Web SPA URL routing: client-side URL contract is / (All spaces), /spaces/{encodedSpace}?view=list|map&memory=&q=&tag=&tier=&tiers=1,3&confidence=&semantic (space detail with in-space search), and /logs, with reload restore, browser back/forward support (popstate), and safe fallback canonicalization when route params are invalid. All spaces is the first sidebar entry (a real anchor to / with aria-current only on home) and the topbar has no breadcrumb. All spaces has a compact, client-only search over loaded visible spaces (name, description and tags; case- and accent-insensitive AND tokens) that never changes the URL or calls the memory API and keeps its query across space navigation; it has no space/memory/embeddings summary, and the sidebar storage row always uses the global status. Search lives inside the open space via the header search input (/ focuses it); there is no global search route, and /search canonicalizes to / (or the current space). A query or confidence filter opens the space-search view; tier/tiers/tag alone stay list filters.
  • In-space search clearing: clearing the query removes stale results and returns to the memory list. An already loaded list is reused when its filters still match.

2. Architecture

2.1 High-level flow

User → ./mind <command> [args] [--flag value]
         ↓
    mind (Bash script at repo root)
         ↓
    bun run src/mind.ts "$@"
         ↓
    executeCommand(args, store, logger)
         ↓
    CLI command registry (atomic command modules) → command-executor (dispatch)
         ↓
    MindStore (SQLite) + Logger (stdout/stderr)
  • Entry: src/mind.ts creates store/logger and delegates all command handling to executeCommand from src/cli/command-executor.ts.
  • Commands: Declared as atomic modules in src/cli/commands/*.ts and registered by src/cli/commands/index.ts. src/cli/command-executor.ts acts as dispatcher/registry.
  • Storage: All persistent data goes through the MindStore interface (defined in src/store/mind-store.ts), implemented by createSqliteStore (src/store/sqlite-store.ts). Uses bun's native bun:sqlite.
  • FTS: Full-text search uses SQLite's FTS5 with a porter tokenizer. FTS is synced manually (bun:sqlite has a bug with content-sync triggers — see § 3).
  • Output: All user-facing messages go through the Logger interface (src/helpers/logger.ts), so tests can swap in a mock logger.
  • Web/API: The single canonical HTTP server is src/api/server.ts (via mind serve), and it serves API routes plus static web files from the web/ tree.

2.2 Main modules and responsibilities

ModulePathResponsibility
Entry scriptmind (Bash)Resolve repo root, dispatch to src/mind.ts.
Entry modulesrc/mind.tsBootstrap store/logger and run CLI command executor.
CLI command modulessrc/cli/commands/*.tsAtomic command definitions/handlers grouped by domain (spaces, memories, tiers, links, search, status, tags, checkpoint, guide, migration, runtime). CLI search flags include --space (* = all), --tag, --tier, --detail, --limit (default 25, max 500), and --offset.
CLI executorsrc/cli/command-executor.tsLoad command groups from src/cli/commands/index.ts, dispatch matched command, and render help sections.
Arg parsersrc/cli/arg-parser.tsMatch CLI args to a shape (positional <param>, aliases a|b, --flag value), extract params + flags, render help.
Setup/runtime helperssrc/cli/setup.tsAgent setup, detected integration refresh, and detached process management helpers for MCP/web servers. Uses a capability-driven adapter model (L1 MCP, L2 instruction injection, L3 hooks automation) plus a separate skill-installation surface, with explicit status (supported/unsupported/unverified) and visible fallback diagnostics. Skill installation follows an exact-name policy: only mind-management in a managed path is installed or updated, with or without the ownership marker (the marker is provenance, not authorization); other skills are never touched, and content-signature heuristics were removed. Updates replace SKILL.md atomically without persistent backups inside skill paths, preserve auxiliary files, use lstat/realpath, unlink foreign or broken symlinks and replace them without writing through them while the warning names the old target, and repair a non-directory managed path instead of raising ENOTDIR; ancestor-repair and agent config backups remain outside skill paths, and historical skill backups are not auto-deleted. OpenCode/Claude/Codex/Pi L2 injection renders an activation pointer from the shared activation text, while preserving idempotent/non-destructive managed-file behavior. The complete protocol lives in the installed mind-management skill; MCP initialize.instructions is the same activation pointer and system_instructions is the full fallback. Pi is wired at ~/.pi/agent/mcp.json with a managed ~/.pi/agent/AGENTS.md pointer and the shared ~/.agents skill, without a Pi plugin. Cursor setup writes the documented {version:1,hooks:{...}} envelope with sessionStart, preCompact, sessionEnd, and stop; event payloads, argv, and execution stay unverified, so Cursor L3 is not claimed functional. All reads and writes of user-owned agent config files go through the safe-config helpers in src/setup/safe-config.ts so parse failures abort the run and content changes are backed up and atomic.
Safe config I/Osrc/setup/safe-config.tsreadJsonOrThrow / readJsoncOrThrow parse existing JSON/JSONC strictly and throw MalformedConfigError on failure (callers abort). backupIfExists produces timestamped sibling backups before content-changing writes. atomicWriteText / safeWriteJson / safeWriteJsonc stage writes in a sibling .tmp file and rename them into place. safeWriteJsonc uses jsonc-parser.modify to preserve comments and formatting when only existing top-level keys are modified. Backups are not pruned.
Shared helperssrc/helpers/*.tsShared helpers: logger, tag normalization, formatting/memory refs, markdown resource loading, RAG helpers, embedding provider registry/resolvers (src/helpers/embedding-providers.ts), shared memory-ref resolution (resolveRefWithFallback), link-building (buildLinkedMemoriesArray, mapLinkedSummariesToLinksFormat, transformLinkedSummary), and checkpoint-content (buildCheckpointContent, fetchCheckpointContent).
MindStore interfacesrc/store/mind-store.tsAbstract interface for all data operations.
SQLite storesrc/store/sqlite-store.tsFull MindStore implementation using bun:sqlite. Uses repository factory pattern internally (6 repositories in src/store/repositories/). Handles tiers, LRU eviction, tags, links, FTS (standard + trigram), status, import, and search pagination (paginateSearchResults clamps limit to [1, SEARCH_MAX_LIMIT] = 500). Generates embeddings with awaited provider requests on add/update/move/patch when RAG is enabled.
Store repositoriessrc/store/repositories/*.ts6 focused repositories: SpaceRepository, MemoryRepository, LinkRepository, TagRepository, LogRepository, SearchRepository. SearchRepository runs the unified search pipeline: logically independent channels (phrase/all/any rungs, trigram substring, fuzzy, LIKE, token-set, semantic) executed sequentially on one synchronous SQLite connection, coverage-based admission, NOT exclusions, and fusion via search-fusion. Composed by sqlite-store.ts into the full MindStore.
Store search sharedsrc/store/shared/*.tsShared relevance internals: query-parser.ts (query AST + safe FTS5 MATCH builders + relaxation rungs), matching-tokenizer.ts (fold case/accents, split camelCase/acronym boundaries, plus the per-store write-generation counter that invalidates the P-A fuzzy vocabulary cache), search-fusion.ts (per-channel normalization, weights, agreement bonus, confidence buckets, compatibility search_method mapping, admission predicate), fts-helpers.ts (manual memories_fts and contentless memories_fts_trigram sync, plus the delete-all+repopulate recovery), and index.ts re-exports.
Migration safetysrc/store/migration-safety.tsOpens SQLite databases through the automatic migration safety wrapper. Existing outdated DBs are backed up with VACUUM INTO, migrated, validated, restored on migration/validation failure, and pruned to the latest 3 automatic backups per DB path. Fresh/current DBs don't create migration backups.
Schemasrc/store/schema.tsSQLite schema (tables, indexes, FTS5 tables). No triggers (see §3). initializeDatabase() function. Schema version 10 (migrates v1→v2→v3→v4→v5→v6→v7→v8→v9→v10; v9 adds memories_fts_trigram, v10 makes it contentless + remove_diacritics 1 and is the final consolidated schema — no search-term dictionary).
MCP serversrc/mcp/server.tsMCP stdio server using @modelcontextprotocol/sdk. Exposes tools across spaces, memories, links, checkpoints, and system categories.
MCP toolssrc/mcp/tools/Tool declarations and wiring only: spaces.ts, memories.ts, links.ts, checkpoint.ts, status.ts, system.ts. Endpoint schemas live in src/mcp/schemas/<family>/<endpoint>.ts, endpoint handlers live in src/mcp/handlers/<family>/<endpoint>.ts, and MCP-only helpers (including YAML parity + JSON-schema conversion) live in src/mcp/helpers/.
API serversrc/api/server.tsBun HTTP server that serves /api/* routes and static web files from web/ (SPA shell in web/public/index.html, frontend modules in web/src, styles in web/styles, assets in web/assets).
API routersrc/api/router.tsRoute matcher/dispatcher for API endpoints.
API routessrc/api/routes/*.tsAtomic REST route declarations grouped by domain (spaces, memories, search, status, logs). GET /api/spaces/:space/tags returns that space's distinct normalized memory tags, alphabetically sorted (empty for an unknown space), and feeds the shared All tags filter select. GET /api/search accepts q, space (* = all spaces), tag, tier, tiers (comma-separated, inclusive; tier stays compatible and tiers takes precedence), confidence, semantic (on/off), and limit/offset (default 25, max 500), returns additive X-Total-Count/X-Has-More headers, and result items carry additive score/confidence/methods fields. GET /api/memories/query accepts the same tier/tiers filter pair plus space, tag, from/to, and limit/offset. GET /api/spaces returns each space's additive tier_counts {t1,t2,t3} field (the three counts sum to memory_count), and MCP space_list includes the same field. Unknown /api/* routes return a JSON 404; the memory detail presenter strips embedding, fts_id, and space_id.
Configsrc/config.tsCONFIG.dataDir, CONFIG.dbPath, CONFIG.legacyJsonPath, CONFIG.rag. Respects MIND_DATA_DIR and MIND_DB_PATH env vars. TIER_LIMITS per-tier capacity constants.
Typessrc/types.tsAll domain types: Space, Memory, Link, Tier, SearchResult, StatusResult, LegacyBrain, etc.
Helperssrc/helpers/*.tsShared helpers: logger, tag normalization, formatting/memory refs, markdown resource loading, and RAG helpers.
Protocol resourcessrc/resources/protocols/*.mdmind-cognitive-protocol.md is the single token-free canonical body (ORIENT, RECALL, LEARN, RELATE, MAINTAIN, HANDOFF). The installed mind-management skill is the complete artifact: frontmatter + load note + full body. L2 setup instructions and MCP initialize.instructions are activation pointers rendered from src/cli/skill-activation.ts; system_instructions is the complete fallback when the skill is not listed or cannot be loaded.
Sync (Autosync)src/sync/Bidirectional file sync with file-based config: ConfigFileService (read/write .mind/config.yml), FileSyncService (manifest v2 DB→FS export and managed pruning), SyncCoordinator + withAutoExport (non-blocking auto-export decorator for CLI/API/MCP store mutations), AutoSyncService (file watcher/import), importer (shared file-to-DB import with metadata parity), status-diagnostics (manifest/filesystem/DB drift evaluation), ConflictResolver (db-wins/file-wins/latest-wins), FileWatcher, Frontmatter, and Normalizer. Spaces live in .mind/spaces/<hash>/ where hash = SHA256 truncated to 8 hex chars. Manifest v2 stores canonical content/metadata hashes and UTC timestamps for baseline dirty detection. Loop prevention uses per-space DB-origin locks in .mind/spaces/<hash>/.mind-sync/.syncing. MCP server auto-starts watchers for enabled spaces.
Web frontendweb/src/*, web/styles/*, web/assets/*, web/public/index.htmlSPA for browsing, searching, and editing spaces and memories. Frontend runtime code is native ES modules in web/src/ with no build pipeline, split into api/ (fetch boundary), domain/ (pure models, presenters, sanitizer), views/ (DOM renderers), app/ (store, search controller, page composition, polling), and features/ (routing and graph math), with @ts-check + JSDoc and web/jsconfig.json type-checking. Styles use web/styles/tokens.css plus web/styles/components/ and main.css; static assets include the vendored marked renderer (web/assets/vendor/) and the self-hosted Lucide 0.547.0 icon sprite (web/assets/icons.svg, notices in web/assets/vendor/LICENSE.lucide). Command actions render that sprite through web/src/views/icon.js (no CDN or runtime icon package); visible labels stay by default, icon-only mobile controls keep accessible names, decorative icons are aria-hidden, and state/data marks stay icon-free. Routing covers home, spaces with in-space search and list/map views, and /logs, with deep-link/reload/back-forward restoration. The home view filters loaded visible spaces locally (name, description, tags) without a request and without replacing the search input. See docs/web-ui.md.
  • Search-state handling: the search controller clears stale results when filter state updates without a search request; the app reuses a matching loaded memory list after query clear.

Neural Map API/UI touchpoints:

  • GET /api/spaces/:space/graph?limit=<n> (implemented in memory routes)
  • MindStore.getSpaceGraph(space, opts) backed by SQLite implementation
  • SPA view toggle (List / Neural Map) with concentric tier rings (T1..T3), anchored pan/zoom, deterministic best-effort overlap mitigation, and click-to-fetch details via the existing memory detail endpoint
  • Node radius encodes combined in/out degree (square-root scale, 8.5–21 px, capped for dense graphs), and the link count is rendered inside the node with a fitted font (8–13 px) so it does not overflow
  • Selection highlights incoming and outgoing incident edges, emphasizes neighbors, and mutes unrelated edges; dense maps always materialise every incident edge for the selected node even when the 200-edge context cap omitted it, as a transient DOM-only patch removed on deselect without a rebuild or refetch
  • Graph search highlighting/dimming, "Only matches", and tier filters are applied client-side in v1; the map requests all available nodes (backend limit 1,000) and a backend-capped payload shows only a quiet truncation note, with no "Load full graph" action
  • The SVG is role="group" with roving-tabindex nodes (arrows/Home/End/Enter); an accessible table mirrors every rendered node, node aria-labels include "N links", small maps label every node (25-char truncation) and dense maps show only one transient hover/focus/selection label (24-char truncation), with the full name available to assistive technology
  • SPA URL contract and state sync for search/space/view/memory: / (All spaces, first sidebar entry with no topbar breadcrumb), /spaces/{encodedSpace}?view=list|map&memory=&q=&tag=&tier=&tiers=1,3&confidence=&semantic (search is scoped to the open space), and /logs; /search canonicalizes to / or the current space

2.3 Data model

  • Brain: A SQLite database (mind.db) at data/ in the repo root (or MIND_DATA_DIR).
  • Space: { id: string (UUID), name: string, description: string, hidden: boolean, tags: string[], created_at, updated_at }. Identified by name (unique); UUID primary key for internal references.
  • Hidden spaces: Spaces can be marked hidden and are omitted from default list; include them with list --hidden.
  • Checkpoints: Session checkpoints are stored as tagged memories (checkpoint tag) in the same project space.
  • Memory: { id: string (UUID), space_name: string, name: string, content: string, tier: 1|2|3, pinned: boolean, access_count: number, last_accessed_at: string|null, tags: string[], embedding: Float32Array|null, created_at, updated_at, changed_at }. UUID primary identity; fts_id (number) is the SQLite FTS5 surrogate. Identified by (space_name, name).
  • Tier system:
    • 🔴 T1 (hot) — frequently accessed (limit: 25/space)
    • 🟡 T2 (warm) — default for new memories (limit: 50/space)
    • 🔵 T3 (cold) — rarely used (unlimited capacity)
    • Auto-promotion on CLI read: each read promotes one tier up (T3→T2, T2→T1). Skipped silently if pinned or if destination is full and all are pinned.
    • LRU eviction: when a tier is full, the least-recently-used non-pinned memory is demoted one tier down (no cascading). T3 is unlimited, so no eviction from T3. If all memories in a tier are pinned, addMemory and promote throw an error; recordAccess promotion silently skips.
    • New memories can be added to T1, T2, or T3 only.
    • Pinned memories are immune to auto-promotion and LRU eviction.
  • Link: Directional edge between two memories with a label (default: "related"). Stored as (source_id TEXT, target_id TEXT, label) (UUID foreign keys).
  • Tags: Both spaces and memories can have multiple string tags. Tags are normalized on input: converted to lowercase, leading # stripped, validated against allowed characters (a-z, 0-9, -, _, ., :, /, =, +, @). Tags cannot be empty or contain spaces. Displayed with # prefix in CLI output.
  • FTS: memories_fts (FTS5, porter unicode61) and memories_fts_trigram (FTS5, trigram remove_diacritics 1, contentless, schema v10) are standalone virtual tables synced manually on add/update/delete. memories_fts powers token/fuzzy matching via the porter tokenizer; memories_fts_trigram powers substring matching for terms of 3+ characters and folds diacritics so accented and unaccented queries match both ways (R1).
  • Search pipeline: Search is one unified multi-channel pipeline (SearchRepository.searchMemories) used by the CLI, MCP, and API. A parser builds a query AST ("phrases", OR, AND, NOT, trailing *); logically independent channels collect candidates (phrase/all/any rungs, trigram substring, fuzzy Damerau–Levenshtein ≤2, LIKE for sub-trigram terms, token-set coverage, and semantic when RAG is enabled) and execute sequentially on one synchronous SQLite connection; candidates pass a coverage-based admission gate; and a weighted fusion with an agreement bonus ranks them deterministically. Semantic-only candidates from natural-language queries can bypass the lexical gate at cosine ≥0.6; explicit operators remain lexical. Each result carries a normalized score, a confidence bucket (high|medium|low), and methods provenance. RAG-off search stays fully functional (the semantic channel is omitted); a query-time embedding failure opens a ~5-minute in-memory breaker. The embedding provider is selectable (openai default or openrouter) without changing the ranking math; both providers produce 1536-dimension vectors, so stored embeddings stay compatible.

2.4 SQLite schema tables

TableKey columnsNotes
metakey, valueTracks schema_version.
spacesid (TEXT PK), name (UNIQUE), description, hidden, timestampsUUID primary identity.
space_tagsspace_name (FK), tagCascades on space rename/delete.
memoriesid (TEXT PK), space_id (TEXT FK → spaces.id), name, content, tier (CHECK tier BETWEEN 1 AND 3), pinned, access_count, last_accessed_at, embedding, fts_id (INTEGER UNIQUE), timestamps (created_at, updated_at, changed_at)UUID primary identity; fts_id is SQLite FTS5 surrogate. UNIQUE on (space_id, name). Cascades on space delete/rename.
memory_tagsmemory_id (TEXT FK), tagCascades on memory delete.
linkssource_id (TEXT FK), target_id (TEXT FK), labelNo self-links. Cascades on memory delete.
idx_*idx_memories_space_id, idx_memories_fts_id, idx_memories_space_id_name, idx_spaces_idPerformance indexes for lookups.
memories_ftsFTS5 virtual table: name, contentSynced manually (no triggers).
memories_fts_trigramFTS5 virtual table: name, content (tokenize trigram remove_diacritics 1; content='', contentless_delete=1)Standalone, synced manually (no triggers); schema v10. Contentless: reads return NULL, 'rebuild' is unsupported (recovery uses delete-all + repopulate). Folds diacritics (R1). Powers substring matching for terms of 3+ characters.
fts_id_sequenceentity (TEXT PK), next_value (INTEGER)Transactional FTS5 surrogate ID assignment.
logsid (PK), source, operation, level, input_data, output_data, error_message, caller_info, duration_ms, timestampOperation audit logging (fire-and-forget).

3. Technical considerations

  • Schema version: Current schema is version 10. Existing v1 databases (tier CHECK (tier BETWEEN 1 AND 3)) are migrated automatically via a 12-step rename-and-recreate pattern in MIGRATE_V1_TO_V2. V2→V3 adds the embedding BLOB column. V3→V4 adds changed_at and backfills it from updated_at. V4→V5 adds spaces.hidden with default 0. V5→V6 adds the logs table for operation auditing. V6→V7 removes T4 (frozen) tier; all T4 memories migrate to T3 which becomes unlimited. V7→V8 converts spaces and memories from INTEGER AUTOINCREMENT to UUID TEXT primary keys, adds memories.fts_id (INTEGER) as local surrogate for SQLite FTS5 rowid, adds memories.space_id (TEXT FK) normalizing the relationship to spaces, adds spaces.id (TEXT PK), adds the fts_id_sequence table for transactional ID assignment. V8→V9 adds the standalone memories_fts_trigram FTS5 table (tokenize trigram) repopulated from memories. V9→V10 (final consolidated schema) recreates memories_fts_trigram in place with remove_diacritics 1 + content='' + contentless_delete=1 (R1 + size) and repopulates it. The intermediate schemas v10 (with a per-document search-term dictionary) and v11 (dictionary retired) were development-only and never published; the final v10 is functionally identical to that dev v11 and has no dictionary. There is no permanent v10→v11 compatibility in the engine: dev databases still stamped version 11 are normalized to 10 with the opt-in scripts/normalize-dev-db.ts (copies only; refuses data/mind.db). Every step runs under the migration-safety wrapper.
  • Migration safety: Store initialization detects existing DB schema version before migration. If the DB exists and is outdated, mind creates an automatic *.migration-backup.*.db backup with SQLite VACUUM INTO, runs migrations, validates the final schema version, PRAGMA quick_check, and PRAGMA foreign_key_check, and restores the backup if migration or validation fails. Fresh/current DBs skip migration backups, and automatic migration backups are pruned to the latest 3 per DB path.
  • Trigram index cost: memories_fts_trigram (contentless, schema v10+) on the real corpus is about 19.9 MB after the contentless change — roughly 24 % smaller than the old non-contentless trigram (26.18 MB → ≈19.9 MB; −6.27 MB). On the synthetic scalability corpus at 50k the contentless index measures 111.70 MB vs 149.44 MB for the old engine (−25.3 %), and the compact DB drops from 268.37 MB to 230.63 MB (−14.1 %). These are host-specific measurements from the pre-optimization comparison; see docs/search-engine.md for the current envelope and docs/search-benchmarks.md for reproduction.
  • Semantic breaker: A query-time embedding failure (for example an expired key) opens an in-memory breaker with a ~5-minute TTL (SEMANTIC_BREAKER_TTL_MS in src/helpers/rag.ts). While open, the semantic channel is skipped entirely so a failing provider cannot trigger a retry storm; lexical search is unaffected.
  • Bun and lockfile: The project runs and tests with Bun. Use bun run, bun test, and Bun's built-in TypeScript + SQLite support. No separate compile step. bun.lock is the only root lockfile; package-lock.json was removed and the release script has no npm-lock handling. The benchmark subproject owns benchmarks/agent-memory/bun.lock.
  • CI: .github/workflows/main.yml pins Bun 1.3.14 and, after a frozen install, runs bun audit --audit-level=high, bun run typecheck, bun run format:check, bun run lint, and bun test test/ web/test. The benchmark job runs its own frozen install plus the blocking high-severity audit, typecheck, bun test test, and bun test experiments. No paid stage runs in CI, and audit failures are never suppressed with || true or continue-on-error. On 2026-10-24 with Bun 1.3.14, the root audit (high and default levels) reports no advisories and the benchmark high-severity audit exits 0; the benchmark's default audit still reports one low @ai-sdk/provider-utils advisory through the pinned @opencode/sdk@2.0.28, which has no fix inside the current pin. CI triggers on every push (including branch names with /), every pull request, and manual dispatch. Hosted run evidence for a feature commit is recorded in its .pas/ feature report; do not claim a green run until it is observed.
  • Checkpoint completion atomicity: MindStore.completeCheckpoint creates the T3 session-* summary, copies inbound and outbound links with labels and directions, and deletes the checkpoint in one synchronous SQLite transaction. A summary, link, or delete failure rolls back the entire transformation, leaving the checkpoint and original links intact, so a retry cannot duplicate the summary. Embedding generation runs after the commit and auto-export runs once. checkpoint-done.ts only builds content and calls the store; MCP and CLI surfaces are unchanged.
  • bun:sqlite FTS5 bug: bun:sqlite (v1.2.10) cannot handle FTS5 content=table sync triggers — any UPDATE or DELETE on the source table errors with "N values for M columns". Workaround: memories_fts and memories_fts_trigram are standalone FTS5 tables (no content= option, no triggers). Both are synced manually through the FtsHelper class in src/store/shared/fts-helpers.ts (insert/update/delete, mirrored across both indexes) from addMemory, updateMemory, deleteMemory, deleteMemoryByName, deleteSpace, and importFromJson. Because the trigram index is contentless (content=''), FTS5's 'rebuild' is unsupported; recovery uses delete-all + repopulate (recoverTrigramIndex).
  • Fuzzy channel (P-A, schema v10): the fuzzy recall channel generates candidates from the full folded document vocabulary, folded once and cached in memory per store and keyed by the store write generation (storeGeneration/bumpStoreGeneration in src/store/shared/matching-tokenizer.ts, bumped by every FtsHelper write). A steady-state search pays no SQL round-trip for candidate generation; a write can never leave a stale vocabulary behind. Expansions use bandedOsa (OSA ≤2 with a hard cap and early exit), a length band, a deterministic sorted order, and the documented prefix-3 rule (FUZZY_PREFIX_LENGTH = 3): a typo in the first three characters of a word is not recoverable. The per-document search_terms/memory_terms dictionary was a development-only prototype (never published) whose storage/rebuild cost did not pay off at 50k; the final v10 does not include it.
  • Styling: Terminal output uses ansi-styles for bold, colors, etc. Tests assert on the styled strings.
  • Config / storage path: src/config.ts resolves CONFIG.dbPath from MIND_DB_PATH env var (full path override) or MIND_DATA_DIR env var + mind.db (defaults to data/ at repo root). The web server uses MIND_DATA_DIR (or /data in Docker). data/ is in .gitignore. HTTP idle timeouts are configurable via MIND_MCP_IDLE_TIMEOUT (default 120s) and MIND_API_IDLE_TIMEOUT (default 30s). Log retention is configurable via MIND_LOG_RETENTION_MINUTES (default 10080 minutes = 7 days). Web server port is controlled via MIND_PORT (default: 30303). RAG is disabled by default; enable it with MIND_RAG=true. MIND_EMBEDDING_PROVIDER selects the embedding provider (openai default or openrouter; invalid values disable RAG without fallback), and the per-provider API keys are OPENAI_API_KEY (OpenAI) and OPENROUTER_API_KEY (OpenRouter).
  • Setup behavior: mind setup configures all supported agent integrations; mind setup <agent> targets one agent, and mind setup compatibility prints the capability matrix. Agent setups are isolated: when one agent fails, its error is reported and the remaining agents still run, and the success summary is printed only when every agent succeeds. mind setup refresh reconfigures detected Mind-managed integrations by default without creating unrelated first-install configs. Detection includes existing Mind MCP config/stanza, managed protocol file/block, managed hook/plugin/script, or installed mind-management skill signal. Refresh also supports --dry-run, --all, and --agent <agent>. After a successful installer run, mind update first runs the newly installed mind status when a DB existed before the update to force automatic migration/restore, then runs detected integration refresh unless --no-refresh-integrations is passed. Fresh installs with no DB skip the status step to avoid creating a DB.
  • Claude setup behavior: mind setup claude-code deep-merges ~/.claude/settings.json, writes/refreshes ~/.claude/instructions/mind-memory-protocol.md, and upserts a managed block in ~/.claude/CLAUDE.md pointing to that protocol. Managed-block/hook wiring now self-heals dirty duplicate entries on reruns, and setup removes known legacy per-agent protocol files to prevent regressions. L3 hook automation is opt-in (MIND_SETUP_CLAUDE_ENABLE_HOOKS=true) and non-blocking; failures fall back to manual workflow guidance.
  • Capability declarations beyond wired adapters: VS Code/Copilot, Antigravity, and Pi Agent are supported agents with L1 wiring; their L2/L3 and skill surfaces are documented honestly in docs/agent-integration-matrix.md.
  • OpenCode setup behavior: mind setup opencode deep-merges existing JSON config (preserving unknown keys), configures mcp.mind as local command transport (type: "local", command: ["<path-to-mind>", "mcp"]), writes/refreshes ~/.config/opencode/instructions/mind-memory-protocol.md, and ensures that exact path is present exactly once as the first entry in the OpenCode instructions list. Reruns sanitize dirty instruction lists (dedupe + remove known legacy protocol paths/files). L3 prudent session/compaction automation is default-on and non-blocking: setup writes a managed plugin at ~/.config/opencode/plugins/mind-automation.js that handles session.created, session.compacted, compaction continuity, and prudent session-end summaries with deterministic caps/idempotency. The generated plugin default-exports an OpenCode V2 definition (id + setup, using ctx.session.hook('context'|'compaction') and ctx.event.subscribe) and also exposes V1 server() hooks, so it loads on OpenCode V2 and on V1 builds that support object plugin entrypoints (1.18.29+); older V1 builds keep loading the plugin through the named MindAutomationPlugin export.
  • OpenCode JSONC support: mind setup opencode prefers ~/.config/opencode/opencode.jsonc over opencode.json when both exist, never creates opencode.json if opencode.jsonc is already present, and creates a new file as opencode.jsonc (the JSONC superset of JSON that OpenCode accepts natively). The setup uses jsonc-parser to parse existing JSONC and to apply edits that preserve comments and formatting when only existing top-level keys are modified. Files that mix JSONC (e.g. with comments or trailing commas) and standard JSON are both supported.
  • Setup file safety (parse-safely / backup / atomic write): All setup flows that touch a user-owned agent config file (JSON, JSONC, and TOML) now go through src/setup/safe-config.ts. JSON/JSONC covers opencode, claude fallback, cursor, windsurf/devin, gemini-cli, vscode/copilot, antigravity, and pi. TOML covers codex (~/.codex/config.toml), backed by Bun.TOML.parse with a feature-detect guard (no TOML npm dependency) and a new safeWriteToml helper that mirrors the JSON/JSONC contract. The contract is: existing files are parsed strictly, and a parse failure never overwrites the malformed file with an empty default. A parse failure aborts that agent's setup with a clear error: a single-agent mind setup <agent> fails outright, while a bare mind setup reports the failing agent and continues with the remaining agents. Content-changing writes are preceded by a timestamped sibling backup (<file>.bak.YYYYMMDDTHHMMSSmmmZ) holding the pre-write bytes, and the new content is staged in a sibling .tmp file and renamed into place so a crash mid-write cannot leave a partial file. Backups are intentionally not pruned by setup — users can manage them by hand. The same contract applies to mind setup refresh and to the post-update integration refresh path. MalformedConfigError.parser is now 'json' | 'jsonc' | 'toml' so callers can branch on the parser without losing type safety.
  • Cursor setup behavior: mind setup cursor deep-merges ~/.cursor/mcp.json for L1 MCP and configures managed L3 hooks in ~/.cursor/hooks.json using the documented { "version": 1, "hooks": { ... } } schema (events: sessionStart, preCompact, sessionEnd, stop) backed by a non-mutating shim script at ~/.cursor/hooks/mind-session-continuity.sh. The shim does not create, overwrite, or complete checkpoints. Hook setup deduplicates dirty managed entries on reruns, migrates an older top-level event map, preserves unrelated keys, and remains non-blocking with explicit safe fallback messaging. L3 stays unverified because hook execution and payload shape were not live-tested.
  • Codex setup behavior: mind setup codex writes a local MCP stanza in ~/.codex/config.toml with command = "<path-to-mind>" and args = ["mcp"] (stdio/local transport, no forced HTTP args), and upserts a managed Mind activation pointer block in ~/.codex/AGENTS.md non-destructively. Project AGENTS.md files must point to the skill and fallback instead of restating the protocol, because project files can override the global block. Reruns collapse duplicate managed blocks and remove known legacy per-agent protocol files. The Codex write path now goes through the TOML-aware safe-config pipeline (readTomlOrThrow + safeWriteToml in src/setup/safe-config.ts, backed by Bun.TOML.parse with a feature-detect guard — no TOML npm dependency): existing files are parse-validated before any write, malformed TOML aborts the run without overwriting, content-changing writes are backed up, an outdated [mcp_servers.mind] stanza is replaced in place (preserving unrelated tables and comments), and a missing stanza is appended. isAgentIntegrationDetected('codex') dispatches on cfg.format and uses tomlFileHasMindMcp for TOML agents so the detector no longer probes config.toml with JSON.parse.
  • Pi setup behavior: mind setup pi writes ~/.pi/agent/mcp.json with mcpServers.mind over stdio, upserts a managed activation pointer block in ~/.pi/agent/AGENTS.md non-destructively, and installs the shared ~/.agents/skills/mind-management skill while migrating only Mind-managed ~/.pi/agent/skills shadow copies. Pi documents extensions, but Mind does not install a Pi plugin and marks L3 unverified.
  • Corrected integration paths: Windsurf/Devin writes ~/.config/devin/mcp_config.json (legacy ~/.windsurf/mcp.json is detection-only); VS Code/Copilot writes portable ~/.copilot/mcp-config.json with mcpServers (VS Code-native servers is documented as an alternative and not written); Antigravity writes ~/.gemini/config/mcp_config.json and uses ~/.gemini/config/skills. Codex/Gemini/VS Code/Antigravity document hooks, but Mind implements no L3 automation for them.
  • Skill source of truth and protocol distribution: The single canonical body is src/resources/protocols/mind-cognitive-protocol.md (token-free, six responsibilities, real tool examples). The installed mind-management skill composes it through skill-mind-management.md and src/cli/mind-management-skill.ts; it is the single source of truth and agents load it unconditionally at session start and after compaction, before any Mind use. L2 setup payloads (mind-memory-protocol.template.md, src/cli/memory-protocol.ts) and MCP initialize.instructions (via src/cli/skill-activation.ts and src/mcp/server.ts) are activation pointers only and do not contain the body. system_instructions composes the full body through mind-system-instructions.md and src/cli/system-instructions.ts and is the complete fallback at version 2.3.0 when the skill is not listed or cannot be loaded; the skill is the primary source of truth. Project AGENTS.md files must point to the skill and the fallback and must not restate the protocol, because project files can override the global Codex block. The template renderer operates in strict mode: unresolved placeholders/conditionals (or leftover template tokens) throw errors for all render paths. Skill installation uses the exact mind-management name in managed paths; the ownership marker is provenance. docs/skill-first-distribution.md explains the current model and installation policy, and docs/agent-integration-matrix.md records validation status (including free OpenCode discovery versus the unrun paid B11).
  • MCP YAML stage 1: Structured MCP tools now return one raw YAML text item serialized directly from the same payload exposed via structuredContent. This is built through src/mcp/helpers/yaml-response.ts (not hidden in src/mcp/server.ts). Stage-1 exclusions remain text-only: system_instructions, space_delete, memory_delete, link_create, and link_delete. checkpoint_query includes an explicit error field (null on success, { code, message } on soft error), returns full pending text without preview truncation, memory/checkpoint MCP payloads rely on changed_at instead of exposing created_at / updated_at, memory MCP payloads also omit access_count / last_accessed_at, and space_get now returns an orientation summary with overview, changed-at trending_memories blocks per tier (bounded T3 preview plus total availability), a references block of living references, and plural active_checkpoints whose checkpoint items reuse the checkpoint_query shape.
  • Testing: Backend/CLI tests live in test/. Web-specific tests live in web/test/. Both use bun:test and rely on:
    • test-store.ts (test/mocks/test-store.ts): creates a temporary SQLite DB in /tmp/ per test instance; returns { store, cleanup }.
    • mocked-logger.ts (test/mocks/mocked-logger.ts): captures logInfo/logError for assertions.
    • Backend/CLI test files include: test/mind-store.spec.ts (store-level, including graph retrieval), test/migration-safety.spec.ts (automatic migration backup/restore/retention), test/api-routes.spec.ts (HTTP route-level behavior), test/command-executor.spec.ts (CLI-level), test/mcp-tools.spec.ts (MCP tools), test/mcp-yaml-content.spec.ts (stage-1 YAML parity + exclusions), test/setup-safe-config.spec.ts (safe config I/O: parse-failure abort, backup, atomic write, JSONC with comments/trailing commas), test/setup-opencode.spec.ts (OpenCode JSONC preference + safe writes + parse-failure abort), test/setup-capabilities.spec.ts (cross-agent safe writes + parse-failure abort), test/skill-installation.spec.ts (exact-name updates, no skill backups, symlink safety, extras, nine clients), test/checkpoint-atomicity.spec.ts (summary/link/delete rollback and retry), test/ci-workflow.spec.ts (format, audit, Bun pin, isolated installs), test/release-script.spec.ts (no npm-lock handling), test/memory-protocol-renderer.spec.ts, test/system-tools.spec.ts, test/template-renderer.spec.ts, and test/arg-parser.spec.ts. Search-specific suites: test/query-parser.spec.ts (grammar/AST), test/search-fusion.spec.ts (fusion/confidence math), test/trigram-search.spec.ts (substring/R1 + contentless sync parity), test/fuzzy-search.spec.ts (P-A vocabulary cache + banded OSA + the documented prefix-3 limitation), test/search-consistency.spec.ts (cross-surface ranking), test/search-scenarios.spec.ts (v2 taxonomy + snapshot gate), test/search-eval.spec.ts (v1 immutable + v2 snapshot/ranking gate), test/search-diagnostics.spec.ts (diagnostics sink byte-equivalence + content-free payload), and test/search-bench-smoke.spec.ts (structural smoke of scripts/bench-search.ts).
    • Web test files use happy-dom for DOM integration: web/test/search-view.spec.ts/search-page.spec.ts (search UI, filters, async states), web/test/memory-list-app.spec.ts and memory-panel-app.spec.ts (list/panel wiring, focus, CRUD), web/test/modals-app.spec.ts (dialogs and validation), web/test/graph-view.spec.ts/graph-app.spec.ts (accessible graph, filtering, keyboard), web/test/logs-view.spec.ts/logs-app.spec.ts (filters, polling lifecycle, cap), web/test/responsive-navigation.spec.ts (drawer), web/test/design-system.spec.ts (tokens/contrast), web/test/neural-map-graph-math.spec.ts (zoom/layout/label math), web/test/spa-routing.spec.ts (URL contract parse/build), web/test/css-concern-separation.spec.ts, web/test/shell-markup.spec.ts, and web/test/web-index-assets.spec.ts (deep-route-safe asset paths). bun run typecheck also runs tsc -p web/jsconfig.json over web/src and web/test; web/assets/vendor/marked.min.js is vendored locally (no CDN).
    • Search reset behavior is covered by web/test/search-controller.spec.ts (clears stale results without a request) and web/test/search-app-wiring.spec.ts (restores the existing list after query clear).
    • scripts/test-rag.sh: E2E integration test for RAG. Requires OPENAI_API_KEY, makes real OpenAI API calls. Uses MIND_DB_PATH to create a temp DB. Run via make test-rag or directly.
  • Docker: web/Dockerfile builds the web app; docker-compose.yml runs it with volume ./data (or BRAIN_DATA_DIR) mounted at /data, port 3000, and restart: unless-stopped.
  • Dependencies: Production: @modelcontextprotocol/sdk, ansi-styles, jsonc-parser, yaml, zod. Dev: @types/bun plus the lint/format toolchain. Peer: typescript ^5. The benchmark harness owns @opencode/sdk@2.0.28 and its own lockfile under benchmarks/agent-memory/; the root does not depend on it. Root overrides pin patched transitive versions, including body-parser 2.4.0, which clears GHSA-27r3-jxmh-p828 under Bun 1.3.14. The benchmark keeps one flat top-level zod override, 4.6.7, in its package.json (lockfileVersion 1), which clears GHSA-mrhx-c7xc-m3w5 and resolves every consumer, including gitlab-ai-provider, to zod 4; the free benchmark suites and the no-paid smoke path passed, but no live GitLab provider call was verified.
  • Shell completion: The mind bash script supports --complete flag, delegating to src/complete.ts. This file is not yet implemented.

4. Usage

4.1 Setup

bun install

4.2 Running the CLI

From the project root:

./mind <command> [args] [--flag value]

Example: ./mind help, ./mind create my-space "Description", ./mind search "auth" --tier 1.

The data/ directory and mind.db are created automatically on first run.

4.3 Running the Web Server

./mind serve start                  # Start HTTP server on port 3000
./mind serve start --port 8080      # Custom port
./mind serve start --detached       # Run in background
./mind serve stop                   # Stop detached server

Clearing the in-space search removes old results and returns to the memory list. If the loaded list still matches its filters, the app reuses it without another memory-list request.

4.4 Running the MCP Server

./mind mcp                          # Start MCP server (stdio transport)
./mind mcp start --http             # Start MCP over HTTP (foreground)
./mind mcp start --http --detached  # Start MCP over HTTP (background)
./mind mcp stop                     # Stop detached MCP server

Add to your agent's MCP config:

OpenCode (~/.config/opencode/opencode.jsonc, or opencode.json if only the legacy file exists):

{
  "mcp": {
    "mind": {
      "type": "local",
      "command": ["/absolute/path/to/mind", "mcp"],
      "enabled": true
    }
  },
  "instructions": ["~/.config/opencode/instructions/mind-memory-protocol.md"]
}

Claude Code (~/.claude/settings.json):

{
  "mcpServers": {
    "mind": {
      "command": ["/path/to/mind", "mcp"],
      "enabled": true
    }
  }
}

4.5 Setting up agents

./mind setup               # Configure all supported agents
./mind setup compatibility # Show agent integration compatibility
./mind setup claude-code   # Auto-configure Claude Code
./mind setup opencode      # Auto-configure OpenCode
./mind setup cursor        # Auto-configure Cursor
./mind setup codex        # Auto-configure Codex
./mind setup windsurf     # Auto-configure Windsurf
./mind setup gemini-cli   # Auto-configure Gemini CLI
./mind setup vscode       # Auto-configure VS Code / GitHub Copilot
./mind setup antigravity  # Auto-configure Antigravity
./mind setup pi           # Auto-configure Pi Agent
./mind setup refresh      # Refresh detected mind-managed integrations

./mind setup compatibility prints an explicit capability matrix for all supported adapters plus non-wired declarations. It prints full per-level status/confidence/evidence/fallback diagnostics for each listed adapter, plus the separate skill path/strategy line. Cursor L3 uses the documented hooks schema but remains unverified; Codex, Gemini CLI, VS Code/Copilot, and Antigravity document hooks but Mind implements no L3 automation for them. Windsurf/Devin, VS Code/Copilot, and Antigravity use their corrected documented MCP paths, and Pi Agent is wired without a Pi plugin. ./mind setup refresh refreshes only detected Mind-managed integrations by default; use --dry-run, --all, or --agent <agent> to control the refresh.

4.6 Running tests

# Unit tests
bun test test/ web/test

# Web-only tests
bun test web/test

# RAG E2E integration test (requires OPENAI_API_KEY, makes real API calls)
make test-rag
# or directly:
OPENAI_API_KEY=sk-... ./scripts/test-rag.sh

# Search relevance evaluation suite (deterministic fixture corpus, no API key; CI-apt)
make search-eval

# Search benchmarks / differential (opt-in, NOT part of bun test)
make bench-search                         # fixture corpus
make bench-scalability CORPUS=1k|10k|50k|100k
make search-diff                          # old-vs-new per-query comparison

# Agent memory benchmark (subproject; free tests run in CI; see benchmarks/agent-memory/README.md)
cd benchmarks/agent-memory && bun install --frozen-lockfile
cd benchmarks/agent-memory && bun test test     # unit + contract (integration skipped)
cd benchmarks/agent-memory && bun test experiments
# free platform/isolation probes:
make bench-agent-memory-probe
# paid stages require --budget and are not runnable until later tasks:
# make bench-agent-memory-smoke | -locomo | -scenarios | -full | -report
# make bench-agent-memory-clean [ALL=1]   # remove run dirs (ALL=1 also removes worktrees)

# Maintainer release flows
make release-patch
make release-minor
make release-major
make release-simulate TYPE=patch
./scripts/release.sh minor --notes-file docs/release-notes/v1.5.0.md

Search benchmark methodology and reproducibility: docs/search-benchmarks.md.

OmniMemEval / LongMemEval-S lives under benchmarks/omnimemeval/. The external 500-question answer-quality benchmark uses a pinned official harness with a thin Mind adapter and can only be started with .github/workflows/omnimemeval-mind.yml (workflow_dispatch). It is paid and must never run on push, pull request, or routine CI. OmniMemEval uses GPT-6 Luna low for both answerer and judge; results are not directly comparable to the original GPT-4o-mini-judged published results. The independent agent-memory paid harness also pins OpenRouter GPT-6 Luna with variant low instead of its previous DeepSeek V4.1 Flash default. The OmniMemEval manual workflow accepts rag_mode=off|on; RAG-on must index and query embeddings through OpenRouter, and fail rather than silently behave as RAG-off. Runs check the available OpenRouter key budget before installing benchmark dependencies. The README reports the completed 120-question stratified pilot separately from competitors' 500-question published results; the 500-question Mind attempt was incomplete because of the OpenRouter key usage limit. Do not present this as an official rank. The separate agent-memory benchmark and search-relevance/latency harnesses are intentionally preserved.

The agent memory benchmark (benchmarks/agent-memory/) is a separate, opt-in harness that compares OpenCode with and without Mind over a LoCoMo subset and agent scenarios; its README documents isolation, budget policy and how to add another engine. It is an independent Bun subproject with its own package.json, bun.lock, and tsconfig.json, and it declares @opencode/sdk@2.0.28 itself; the root project is not a workspace and does not install those dependencies. Free unit, contract, and experiment suites run in CI; paid stages never do. Every mind-current A2 and B run applies the real <checkout>/mind setup opencode once per isolated environment, while mind-v9/mind-v10 and no-memory keep their original integration; current-versus-historical comparisons therefore include skill and L2 overhead, and paid budgets need re-approval. It has no production impact.

4.7 Migrating from legacy brain.json

./mind import

Reads data/brain.json (or $MIND_DATA_DIR/brain.json) and imports all spaces and memories into SQLite at tier 2.

4.8 CLI commands

| Intent | Command | Aliases | Params | Flags | Description | | ------------------- | --------------------- | ------------------------------------------- | ------------------------------ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | ---- | ------ | --- | --------------------- | --------- | ---------------------------------------- | | Help | help | h | — | — | List all commands. | | Create space | create | c | <space> <description> | --tags | Create a new space (comma-sep tags). | | List spaces | list | ls, l | — | --tag, --hidden | List all visible spaces by default (optionally include hidden). | | List memories | list | ls, l | <space> | --tier, --tag | List T1+T2 memories in a space (use --tier 3 for cold). | | Delete space | delete | d | <space> | — | Delete a space and all its memories. | | Rename space | rename | rn | <old> <new> | — | Rename a space. | | Describe space | describe | ds | <space> <description> | — | Change a space's description. | | Update space | update | — | <space> | --description, --hidden, --no-hidden | Update space description and/or visibility. | | Tag space | tag | t | <space> <tag> | — | Add a tag to a space. | | Untag space | untag | — | <space> <tag> | — | Remove a tag from a space. | | Add memory | add | a | <space> <name> <content> | --tags, --tier | Add a memory. | | Read memory | read | r | <space> <name> | — | Print a memory (bumps access + auto-promote). | | Edit memory | edit | e | <space> <name> <content> | — | Update a memory's content. | | Remove memory | remove | rm | <space> <name> | — | Remove a memory by name. | | Tag memory | tag | t | <space> <name> <tag> | — | Add a tag to a memory. | | Untag memory | untag | — | <space> <name> <tag> | — | Remove a tag from a memory. | | Promote | promote | up | <space> <name> | — | Move memory one tier up (T3→T2, T2→T1). | | Demote | demote | down | <space> <name> | — | Move memory one tier down (T1→T2, T2→T3). | | Pin | pin | — | <space> <name> | — | Pin a memory (immune to auto-promotion). | | Unpin | unpin | — | <space> <name> | — | Unpin a memory. | | Link | link | — | <source> <target> | --label | Link two memories (space/name format). | | Unlink | unlink | — | <source> <target> | — | Remove a link between memories. | | Show links | links | — | <space> <name> | — | Show all links for a memory. | | Search | search | s | <query> | --space, --tag, --tier, --detail, --limit, --offset | Unified relevance search across memories (fused ranking with per-result confidence). Grammar: quoted phrases, uppercase AND/OR/NOT operators, and a trailing * prefix. A supplied query with no informative term returns a validation error requiring a specific term. Default output includes memory ref, tier, changed timestamp, and [high\|medium\|low]. --detail adds content preview. --limit defaults to 25 and is capped at 500; --offset is zero-based. | | Query | query | q | — | --space, --tag, --tier, --from, --to, --limit, --offset | Query memories by metadata/date with pagination (ordered by latest semantic memory changes). | | Status (global) | status | — | — | — | Show storage info and per-tier breakdown. | | Status (space) | status | — | <space> | — | Show tier breakdown for a specific space. | | List tags | tags | tgs | — | --spaces, --memories | List all tags in the system (defaults to both). | | Checkpoint set | checkpoint set | cp set | <space> <goal> <pending> | --notes, --linked-memories | Create or update an active checkpoint in the project space. | | Checkpoint complete | checkpoint complete | cp complete, checkpoint done, cp done | <space> <name> <what> | — | Complete a checkpoint and transform it into a same-space session-* T3 summary in projects/<repo>. The checkpoint is deleted after the summary is created. | | Checkpoint recover | checkpoint recover | cp recover | <space> | --name | Recover checkpoint by name (use checkpoint list first to find available checkpoints; output is JSON). | | Checkpoint list | checkpoint list | cp list | <space> | --status | List checkpoints from the project space (filtered by checkpoint tag). | | Session migration | migrate sessions | — | <space> | --dry-run | Explicitly migrate legacy sessions/<repo> summaries into projects/<repo> with deterministic naming and preserved links. | | Guide | guide | g | — | — | Show usage guide (human mode). | | Guide (mode) | guide | g | <mode> | — | Show guide (agent or human). | | Import | import | — | — | — | Import legacy brain.json into SQLite. | | Agent setup | setup | install | [<agent>] | — | Without an agent, configure every supported integration; with an agent, configure only that agent. | | Compatibility | setup compatibility | install compatibility | — | — | Show the supported agents and their integration capability matrix. | | Setup refresh | setup refresh | install refresh | — | --dry-run, --all, --agent | Refresh detected Mind-managed agent integrations without bulk-creating unrelated configs. | | Update | update | — | — | --check, --version, --repo, --no-refresh-integrations | Update mind from GitHub releases, then refresh detected integrations unless opted out. | | Sync init | sync init | — | — | — | Initialize .mind/ directory with config.yml and .gitignore. | | Sync status | sync status | sync ls | — | --space | Show sync status for spaces. | | Sync enable | sync enable | — | — | --space | Enable autosync for a project space. | | Sync disable | sync disable | — | — | --space | Disable autosync for a space. | | Sync now | sync now | — | — | --space | Force immediate sync (export + import). | | Sync export | sync export | — | — | --space | Export space memories to markdown files. | | Sync import | sync import | — | — | --space | Import markdown files into a space. | | Sync conflict | sync conflict | — | — | --space, --strategy | Configure conflict resolution strategy. | | Sync remove | sync remove | — | — | --space | Remove space from sync config. | | Sync config | sync config | — | — | — | Show config file contents. | | Sync serve | sync serve | — | — | --space | Start file watcher for a space (foreground). |

Note: tag and untag are disambiguated by argument count: 2 positional args = space tag, 3 positional args = memory tag.

4.9 MCP Tools

The MCP server exposes 18 tools for agent integration:

Spaces (5 tools)

ToolDescription
space_createCreate a new space (requires tags)
space_listList all spaces
space_getGet a space by name; returns an orientation summary with overview counts, T1/T2/T3 previews with T3 availability, living references, and active checkpoints
space_updateUpdate a space description
space_deleteDelete a space and all its memories

Memories (4 tools)

ToolDescription
memory_addAdd a memory to a space (requires tags); links_to is best-effort and returns links_created and links_failed arrays
memory_readRead + record access (auto-promote); returns links_to, linked_by, tier_change. Use noPromote:true to inspect without side effects.
memory_updateUpdate name/content/tags, set pinned, or move one tier with tierTransition (promote/demote); tags replaces the existing set
memory_deleteDelete a memory by space/name

Query (1 tool)

ToolDescription
memory_queryUnified memory listing (use search parameter for full-text search; tier: null means all tiers). Search results always expose confidence (high|medium|low) plus total/limit/offset. Compact by default: score, methods, and the top-level search_method compatibility mapping (fts5/like/trigram/fuzzy/embeddings/mixed) appear only when the Mind MCP process sets USE_DEBUGGING_EXPANDED_TOOLS_RESPONSE=true (exact string); search_method stays absent when a search has no hits. Store/CLI/HTTP results keep all diagnostics

The 00004 search optimization (R1 diacritic folding, contentless trigram, P-A fuzzy) did not change the CLI/MCP/API search contract: the channels, query grammar, result fields (score/confidence/methods), pagination, and search_method mapping are unchanged. Only recall and storage changed. See docs/search-engine.md for current behavior and docs/history/00004-search-optimization/search-optimization-report.md for the frozen measurements.

Links (2 tools)

ToolDescription
link_createCreate a directional link (source → target) with a label; re-creating the same pair replaces the label
link_deleteDelete a directional link; an absent link is a no-op and memories are unaffected

Checkpoint (4 tools)

ToolDescription
checkpoint_saveCreate or update a checkpoint (goal, pending, notes, linked_memories).
checkpoint_loadRestore a specific checkpoint by name. Returns full checkpoint text plus all linked_memories in memory_read format.
checkpoint_queryQuery checkpoints with filters: status, date range, tag, limit/offset, plus explicit soft-error reporting.
checkpoint_doneTransform checkpoint to a same-space session-* T3 summary memory in projects/<repo> and delete the checkpoint

System (2 tools)

ToolDescription
statusGet storage status
system_instructionsReturns the complete Mind protocol (six responsibilities and tool examples); use it when the mind-management skill is not listed or cannot be loaded

For stage 1 MCP content rendering, all structured tools above except system_instructions emit a single raw YAML text item that is semantically identical to structuredContent. Content-only tools (space_delete, memory_delete, link_create, link_delete) remain unchanged.

Every MCP tool call writes caller_info (agent, agentSource, clientName, clientVersion, transport, mcpSession). agent comes from MIND_AGENT, which mind setup writes into each agent's mind MCP entry, with the MCP initialize clientInfo.name as fallback; the web Logs table renders it in an Agent column. Attribution is observability only and implies no authorization.

4.10 Mind source of truth and memory protocol

The mind-management skill is the single source of truth for Mind. Load it unconditionally at session start and after compaction, before any Mind use; do not call a Mind MCP tool until it is loaded. AGENTS.md, MCP initialize.instructions, tool descriptions, and these docs are activation pointers only. If the skill is not listed or cannot be loaded, call system_instructions and follow it.

When using mind via MCP, follow these conventions:

The full cognitive model is explained in docs/cognitive-memory-lifecycle.md, and current retrieval behavior is in docs/search-engine.md. The canonical six-responsibility protocol is src/resources/protocols/mind-cognitive-protocol.md.

Tags with prefixes:

  • type:project — project space
  • type:user — user preferences
  • type:config — global configuration
  • type:learning — learned knowledge
  • type:session — session summaries
  • cat:decision — architectural decision
  • cat:bugfix — bug fix
  • cat:pattern — established pattern
  • cat:discovery — technical discovery
  • cat:preference — user preference
  • cat:config — configuration
  • status:* — convention-only lifecycle tags, such as status:proposed, status:validated, status:failed, status:superseded, status:obsolete, status:final, and status:living
  • type:reference + exactly one ref:* + status:living — living reference memory tags

Space hierarchy (use repo name):

For software projects, use the repository/directory name as the space name (e.g., projects/mind, projects/arcana-web). This makes memories discoverable by future agents.

  • projects/<name> — one space per project
  • same-space session summaries live inside projects/<name> as session-* memories tagged type:session + cat:summary at T3
  • user/preferences — global user preferences
  • user/patterns — user patterns
  • global/config — cross-project config

Tier usage:

  • T1 (hot) — critical active info
  • T2 (warm) — default for new memories
  • T3 (cold) — unlimited

Memory quality guidance:

  • Checkpoints are live/ephemeral work state.
  • Session summaries are chronological recovery logs and evidence, not canonical truth.
  • Durable/canonical memories are atomic actionable knowledge for future sessions.
  • Living reference memories are maintained current-truth maps for project, architecture, style, domain, or workflow context.
  • Create durable memories for stable decisions, verified root causes, final fixes, reusable patterns, user preferences, and significant config/domain facts.
  • Avoid durable memories for transient observations, routine progress, or routine validation results with no new findings.

Living reference convention: use T2 by default, allow natural promotion to T1, and pin only 1–3 critical references when explicitly warranted or approved. Tags are authoritative: use type:reference, exactly one ref:* category tag, and status:living. Recommended refs are ref:project-map, ref:architecture, ref:domain, ref:workflow, ref:style, ref:key-decisions, and ref:known-pitfalls; the memory name is a readable stable kebab-case identifier such as architecture-overview, project-map, style-guide, domain-model, workflow-notes, key-decisions, or known-pitfalls. Include Purpose, Current truth, Key areas/files/concepts, Active conventions, Source memories, Last reviewed, and Maintenance notes. Update living references with memory_update when current truth changes.

Deletion guidance: delete only memories that are clearly obsolete, no longer applicable, and have no historical value. Otherwise, mark status:obsolete or status:superseded and link the replacement.

Continuity rule: link directly relevant memories for recovery continuity. memory_add with links_to is best-effort — check links_failed in the response.

4.11 Autosync (Experimental)

Mind can synchronize project spaces with .md files on the filesystem. The config is stored in .mind/config.yml and is versioned with git. Enabled spaces export automatically after successful CLI, API/web, or MCP DB mutations; export failures and conflicts are logged without reverting the primary DB operation.

Initialize sync:

mind sync init

Enable a space:

mind sync enable --space projects/mind

Directory structure:

.mind/
├── config.yml           # spaces config (VERSIONADO)
├── .gitignore
└── spaces/
    ├── a1b2c3d4/        # hash of "projects/mind"
    │   ├── manifest.json
    │   └── memory-1.md
    └── ...

Commands:

CommandDescription
mind sync initInitialize .mind/ directory
mind sync statusShow configured spaces and drift summary
mind sync enable --space <name>Enable sync for a space
mind sync disable --space <name>Disable sync
mind sync now --space <name>Immediate sync
mind sync export --space <name>Export to files
mind sync import --space <name>Import from files
mind sync conflict --space <name> --strategy <strategy>Set conflict strategy
mind sync remove --space <name>Remove from sync
mind sync configShow config
mind sync serve --space <name>Start file watcher

Conflict resolution strategies:

  • db-wins — DB version wins on real conflicts; only manifest-managed stale files are pruned.
  • file-wins — file version wins on real conflicts; automatic DB→FS export skips conflicting files and logs a warning.
  • latest-wins — hashes detect dirty sides first, then normalized UTC timestamps choose a winner. Near-future timestamps within 5 minutes are accepted for clock skew; farther future or invalid timestamps produce conservative warnings/skips.

Manifest v2 and conflicts: manifest entries track memory name, managed path, optional DB ID, canonical content and metadata hashes, normalized UTC timestamps, last file mtime, and last sync time. Hashes decide dirty state against the common baseline; file existence alone is not a conflict. Timestamps are for audit, ordering, and latest-wins tie-breaking only. mind sync status --space <name> reports DB/file/manifest counts, dirty DB and file counts, conflicts, tombstones, missing managed files, and the latest auto-export warning or error when available.

MCP integration: When MCP server starts, it auto-starts watchers for all enabled spaces.

config.yml format:

# mind autosync config

version: 1

# Spaces to sync with this project
# To enable a new space, add it below with enabled: true
# Valid conflictResolution values: db-wins, file-wins, latest-wins
spaces:
  # projects/mind:
  #   enabled: true
  #   conflictResolution: db-wins

Limitations:

  • File deletion does not auto-delete from DB during watcher imports; missing managed files are reported as warning/drift by sync status without modifying the DB.
  • Existing-memory imports update supported metadata when file-to-DB wins: content, tags, tier, pinned state, and best-effort links_to. Frontmatter names do not rename existing memories in this phase.

5. Keeping this document updated

If you modify this repo, keep AGENTS.md in sync with the code.

Changelog policy (mandatory):

  • Every non-trivial change (features, behavior changes, architecture changes, bug fixes) must be added to CHANGELOG.md under ## [Unreleased].
  • Release commands (make release-patch, make release-minor, make release-major) require unreleased changelog entries and promote Unreleased to a versioned section.
  • Use ./scripts/release.sh <patch|minor|major> --notes-file <path> for curated GitHub release notes; omit --notes-file to use GitHub generated notes.
  • make release-simulate TYPE=patch|minor|major must show what would happen without modifying files/tags/releases.
  • Changes to the mind script or completion: Update § 1, § 2.1, § 2.2, and § 4.2.
  • Changes to the web app or Docker: Update § 1, § 2.2, § 3, and § 4.3.
  • New or removed commands: Update § 4.6 Commands and, if the architecture changes, § 2.1 / § 2.2.
  • New modules or major refactors: Update § 2.2 Main modules and § 2.1.
  • Config or storage changes: Update § 2.3 Data model, § 3, and § 4.
  • New dependencies or runtime requirements: Update § 1 and § 3.
  • New or removed test utilities: Update § 3 (Testing).
  • Schema changes: Update § 2.4 SQLite schema tables.

After editing AGENTS.md, re-read the sections you changed to ensure they stay accurate and consistent with the rest of the document.

Before marking work done, use this checklist:

  • Updated AGENTS.md if architecture/commands/config changed
  • Updated CHANGELOG.md under ## [Unreleased] for significant changes
  • Updated README.md if user-facing behavior/install/update/release flow changed

6. Documentation philosophy and maintenance

Documentation is part of the product. Treat it as a current map of the code, not as a record of every iteration.

Source of truth and status vocabulary

The code and tests are the source of truth for behavior. Documentation explains and points to them; it never overrides them. Use this vocabulary consistently:

  • Living — describes current behavior and is maintained with the code.
  • Historical — frozen evidence from a past feature. It is not current truth.
  • Session — work-in-progress state or a task report; it belongs in .pas/.
  • Unverified — implemented or documented, but not confirmed by a live run.
  • Not run — prepared but not executed, especially for paid benchmark stages.

Never present a historical report or an unrun check as current behavior. Date external claims and validation statements so readers can judge freshness. The canonical agent protocol is src/resources/protocols/mind-cognitive-protocol.md; living pages explain it but do not replace it.

Living versus temporal documentation

  • Living pages live in docs/ and are indexed by docs/README.md. They are the default place to explain current behavior.
  • Execution, merge, validation, and test reports belong in .pas/ and are not a permanent documentation surface. No feature is required to produce a permanent report, and a completed feature does not need a page in docs/.
  • docs/history/ is not an automatic archive. Retain a historical report there only when it has durable technical value, such as measured experiments, rejected alternatives, or open research questions that a living page does not reproduce. Every retained report is listed explicitly in docs/README.md and keeps a two-line frozen banner naming the feature, the freeze date, and the living page that supersedes it.
  • Release notes live in docs/release-notes/ and are immutable; never move or rewrite them.

Documentation locations

ContentLocation
Documentation indexdocs/README.md
Living behavior and conceptsdocs/*.md
Exceptional retained evidencedocs/history/<feature>/*.md
Release historydocs/release-notes/*.md
User-facing install and usageREADME.md
Project purpose and principlesdocs/mind-philosophy.md
Contributor workflowCONTRIBUTING.md
Agent architecture and guidanceAGENTS.md
Change logCHANGELOG.md
Benchmark methodologybenchmarks/agent-memory/README.md
Generated benchmark reportbenchmarks/agent-memory/REPORT.md

Update before you create

Prefer updating the living page that already owns a topic. Create a new living page only when the topic has a distinct audience or a clearly separate job that would overload the existing page. Do not duplicate the same behavior across a living page, README.md, and AGENTS.md; link to the canonical page instead.

Index and link maintenance

  • Every living page must be linked from docs/README.md.
  • Relative links must resolve, including links into docs/history/, src/, test/, and benchmarks/.
  • When you move or rename a page, update its inbound links in the same task.
  • When you change a heading that is linked elsewhere, update the anchor.
  • test/docs-links.spec.ts enforces the invariants rather than a fixed list: the living index, retained-evidence links, frozen banners, non-empty Markdown, relative links, release notes, and the absence of temporal reports in the docs root. Do not add a filename to the test to make a report permanent.

Documentation update matrix

ChangeUpdate
User-facing behavior or setupREADME.md and the owning living page
Architecture, commands, schema, configAGENTS.md
Search behavior, limits, or performancedocs/search-engine.md and docs/search-benchmarks.md
Agent setup or capability statusdocs/skill-first-distribution.md and docs/agent-integration-matrix.md
Verification processdocs/verification-harness.md
Non-trivial or user-visible changeCHANGELOG.md under ## [Unreleased]
Benchmark report format or linksbenchmarks/agent-memory/src/report.ts and REPORT.md

Historical evidence and benchmark reproducibility

Keep reproducible scripts and fixtures in the repository. Keep raw or host-local artifacts external or under /tmp, and record only aggregate evidence. Historical reports keep their original claims and measurements; do not rewrite them when behavior changes. Instead, add or update the living page and point the historical banner at it. There is no fixed list of retained reports: the docs test discovers what remains under docs/history/ and checks that it is indexed. Treat host-specific benchmark numbers as context, not contracts; document the method and ratios, and regenerate before quoting absolutes.

Review checklist

  • Living behavior changed? The owning living page is updated.
  • A page moved? History banner, index, and inbound links are updated.
  • New page? It is linked from docs/README.md and has a single clear job.
  • A report? It is in .pas/ unless it has durable technical value.
  • Claims dated or qualified where the evidence is external or unverified.
  • No temporal report added to the docs/ root.
  • bun test test/docs-links.spec.ts passes.
  • CHANGELOG.md and README.md reflect user-visible changes.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.