Bastra.Recall
A persistent teammate memory for any AI assistant — across every surface. Ein persistentes Teammate-Gedächtnis für jeden AI-Assistenten — über jede Oberfläche hinweg.
🇬🇧 English
What it is — A long-term memory for any AI assistant or agent: Claude (Code, Desktop, Web), ChatGPT (via Custom GPT Actions), Cursor, and anything else that speaks MCP or HTTP. Whenever you correct it, state a rule, or commit to a decision, it gets saved as a small note. In your next chat — days or weeks later, in any tool — the AI pulls those notes back automatically. No more repeating yourself. Everything stays on your own Mac as plain Markdown files (Obsidian-compatible). All your AI tools share the same memory at the same time.
Status — 🟢 Early beta. M0 (eval) and M1 (read path) done, M2 (save path) functional, and the Claude Code reflex layer ships with hooks for SessionStart, UserPromptSubmit, PreToolUse file edits / todos / bash safety, PostToolUse bash act-signals + failure recall, plus optional Stop save-eval. Distribution and multi-surface hardening are active. See PLAN.md.
Why
Working with an AI assistant over months means re-explaining the same things. Pitfalls it already learned in one project recur in the next. Stable preferences ("give me a recommendation, not a 5-option menu") get forgotten between sessions. Project-specific facts get re-discovered every time.
Most AI tools have memory features, but they're passive: a static index file at best, no proactive recall, no cross-surface continuity.
The cost isn't just frustration — it's that the user ends up thinking for the AI. "Wait, didn't we solve this last week?" That's the bug.
What bastra-recall does
A persistent memory layer that:
- Saves autonomously — when a lesson is learned (frustration, repeated correction, durable preference, finalized decision), the AI writes it to the vault without being asked. Trigger discipline ships as a Claude Code Skill; other clients are conditioned through their own system prompt or Custom GPT instructions.
- Recalls before acting — not only when the user prompts. The AI is instructed to query the vault before writing code, before plans, and at session start. The highest-weighted search field is
recall_when, declared at save time. - Works across surfaces — one local daemon serves all your AI tools at once: Claude Code (via MCP), Claude Desktop (via MCP), ChatGPT (via Custom GPT Actions over HTTP), Cursor, and anything else that speaks MCP or HTTP.
- Plain markdown, Obsidian-compatible — the vault is a folder of
.mdfiles with YAML frontmatter. Edit in Obsidian, in the AI, or by hand. Vaults on Google Drive / iCloud / Dropbox mounts are supported via automatic polling-mode in the file watcher.
The single success metric
The user doesn't have to think for the AI anymore.
If recurring mistakes still recur, if the user still has to re-state preferences each session — the project failed, regardless of how clean the architecture is.
How it works
Vault (configurable, plain markdown + YAML frontmatter, Obsidian-compatible)
│ chokidar (auto-polls on cloud-storage mounts)
▼
bastra-recall daemon (TypeScript / Node 22+, single local process)
- In-memory BM25 index (MiniSearch) — recall_when×5, title×4, tags×3, doc2query×2
- Hybrid recall: BM25 + embeddings (Ollama or OpenAI) via RRF fusion
- doc2query (#117): offline Ollama paraphrases triggers at write time → far
recall, query path unchanged (off via BASTRA_TRIGGER_EXPAND=0)
- Tools: recall, load_memory, save_memory, find/read/save_document,
save_product_doc
- Save path: validates frontmatter → writes file → force-reindexes
(so a save and a recall in the same turn are consistent)
- Transport: stdio MCP + HTTP REST (for non-MCP clients)
│
▼
One daemon ↔ many AI clients
- Claude Code / Desktop / Cursor → via thin MCP forwarder (stdio → HTTP)
- ChatGPT Custom GPT, web apps, custom scripts → via REST /api/v1/*
- All clients share the same vault, index, telemetry stream
The Claude Code reflex layer ships with seven quiet hooks by default, all speaking to the daemon's loopback HTTP endpoint:
PreToolUse(bastra-recall-hook) — fires before everyWrite/Edit/MultiEdit/NotebookEdit. Topic-detects from the tool intent and injects<recall-hints>asadditionalContext.SessionStart(bastra-recall-session-hook) — fires onstartup/resume/clear/compact. Preloads top user-prefs + cross-project rules + project-scoped memories as<session-context>so the AI knows who, what, and what-not from the first prompt.UserPromptSubmit,TodoWrite, Bash safety, and Bash failure hooks cover lookup prompts, topology recall before plans, destructive-command safety, and command-failure lesson recall.
The Stop save-eval hook is on by default: since the #48 redesign it is
silent — suggestions go to a file the next session reads, with no chat noise.
Opt out with bastra install claude-code --no-stop-hook.
Telemetry (scripts/stats.ts) tracks per-hook latency, hint-quality, and
follow-through (did the AI actually load_memory after a hint).
Details: docs/architecture.md, docs/memory-schema.md, docs/triggers.md.
Memory shape
Each memory is a markdown file with structured frontmatter:
---
id: css-input-focus-ring-stacking
title: "Don't stack focus styles on inputs"
type: lesson
summary: "Stacking ring + outline + custom :focus on nested inputs causes double focus rings. Use single :focus-visible."
topic_path: [css, input, focus]
tags: [css, input, focus-ring, ui-bug]
scope: all-projects
recall_when:
- creating new input component
- writing input or form css
- focus or accessibility styling
related: [css-effects-stacking-antipattern]
source: "carnexus, recurring lesson"
confidence: 0.95
---
The recall_when field is the bridge between save and recall: when saving, the AI declares the contexts under which future-sessions should be reminded. See docs/memory-schema.md for full field semantics and six example memories covering lesson, preference, project-fact, meta-working, decision, workflow.
Self-learning taxonomy
The vault grows its own structure. When recent memories keep forming the same ad-hoc cluster (people, places, tools, …) without a home, the stop hook suggests recording a convention — a memory in the reserved scope taxonomy that fixes the cluster's folder, topic_path shape and tags. Active conventions are injected at session start and are binding for future saves. save_memory takes a folder argument so cluster members get a real folder (e.g. memories/people/), and re-saving with a changed folder moves the file (the old copy lands in the vault trash, recoverable). All of it lives per-vault on the free axes — the type schema stays fixed. Details: docs/taxonomy.md.
Valence & reflex — memory that feels and fires
Memories can carry an emotional charge: salience (0–1) and emotion (frustration | success | risk | neutral), stamped by the capture rules when a moment is hot — recurring frustration, a hard-won fix, an explicit "remember this well". High-salience memories age slower, may rank higher (shadow-mode first, lift-gated), and glow in the vault map with the emotion as their color. On top sits the reflex lane: promote a memory to recall_mode: reflex — always your explicit call, the curator only proposes candidates from usage evidence — and it self-injects (strictly budgeted, max 2 per prompt) whenever one of its recall_when triggers hard-matches what you type, no lookup query needed. Full details: Valence & Reflex (wiki).
Install
Three paths, in order of friction. bastra-recall is self-contained: the daemon, the MCP server, the REST gateway, the bastra CLI, and the Skill all ship in this repo — nothing else needed for full vault functionality.
A) One double-click — easiest, for non-coders (rolling out)
- Download Install Bastra.command from the latest GitHub release.
- Double-click it in Finder.
- Done. Restart Claude Code / Claude Desktop / Cursor.
The script installs Homebrew if it's missing, adds the bastra tap, installs bastra-recall, and hands over to the guided setup (bastra install): selection lists for the memory vault, your AI clients, and semantic recall — no terminal knowledge required.
B) One command — for developers
Pre-requisites: Node 22+, Git.
git clone https://github.com/n0mad-ai/bastra-recall.git
cd bastra-recall
npm install
npm run build
node packages/daemon/dist/cli.js install all --vault /abs/path/to/your/vault
node packages/daemon/dist/cli.js doctor
node packages/daemon/dist/cli.js doctor --fix # repair stale/missing registrations
node packages/daemon/dist/cli.js uninstall all
Adapter status:
| Surface | What gets installed | Status |
|---|---|---|
claude-desktop |
MCP server entry in claude_desktop_config.json + Skill in .claude/skills/ |
✅ implemented |
claude-code |
MCP server in .claude.json + Skill in .claude/skills/ + hooks & powerline statusLine in .claude/settings.json |
✅ implemented |
cursor |
MCP server entry in .cursor/mcp.json |
✅ implemented (Cursor Rules layer is a separate roadmap item) |
Every write is idempotent (re-runs are no-ops), atomic (tmp file + rename), backed up (timestamped .bak-… next to the original), and parse-safe (broken JSON aborts the run instead of corrupting it). Vault path resolves in this order: --vault <path> flag → BASTRA_VAULT_PATH env → auto-detect from an existing registration in ~/.claude.json or claude_desktop_config.json. If none of those produce a path (a fresh machine), an interactive bastra install offers to create ~/BastraVault for you; non-interactive runs (piped, --yes, --dry-run) keep the clear deterministic error.
Once installed through Homebrew or npm, this collapses to a single command. From the first npm release on:
npx bastra-recall install # zero-install: guided setup with selection lists
npx bastra-recall install all # direct: all clients (script-friendly, add --yes for CI)
# or install the CLI globally:
npm install -g bastra-recall
bastra install
C) Fully manual — fallback
Add the MCP server block to your client's config (~/.claude.json for Claude Code, ~/Library/Application Support/Claude/claude_desktop_config.json for Claude Desktop, ~/.cursor/mcp.json for Cursor).
Recommended (forwarder mode — shares one daemon across all sessions):
"bastra-recall": {
"command": "node",
"args": ["/abs/path/to/bastra-recall/packages/daemon/dist/mcp-forwarder.js"],
"env": {
"BASTRA_VAULT_PATH": "/abs/path/to/your/vault"
}
}
The forwarder is a thin stdio-MCP wrapper that talks to a single local HTTP daemon (port 6723 by default). All MCP clients — Claude Code, Claude Desktop, Cursor, additional sessions — share the same vault state, embedding index, and telemetry. The forwarder auto-spawns the daemon on first run if no one is listening yet.
Standalone mode (one MCP client only, no sharing):
"bastra-recall": {
"command": "node",
"args": ["/abs/path/to/bastra-recall/packages/daemon/dist/index.js"],
"env": {
"BASTRA_VAULT_PATH": "/abs/path/to/your/vault"
}
}
For Claude Code, also drop the Skill + hooks by hand:
bash packages/skill/install.sh # copies SKILL.md → ~/.claude/skills/bastra-recall/
bash packages/skill/install-hook.sh # registers all 7 reflex-layer hooks (opt out of the Stop save-eval with --no-stop-hook)
bastra install claude-code does both of these for you in path B. Re-run install.sh whenever SKILL.md changes; re-run install-hook.sh only if hook binary paths move. To remove the hooks again: bash packages/skill/install-hook.sh --uninstall.
Semantic recall (optional)
Recall is hybrid: BM25 keyword search is the always-on default, and a semantic layer — an optional, configurable second pass — kicks in once an embedding provider is set up. Enabling it is one command:
bastra embeddings on # installs Ollama via Homebrew (if missing), pulls embeddinggemma (~620 MB), persists the choice
bastra embeddings status # effective provider + how it was resolved (env / cli-settings / default) + model presence
bastra embeddings off # back to BM25 keyword-only
At the end of a successful bastra install, bastra asks once whether to enable semantic recall (interactive terminals only — never with --yes or --dry-run, and never in scripts; those print the bastra embeddings on hint instead of hanging). --ollama sets it up without asking, --no-ollama skips. The Ollama login service is a toggle (bastra config set ollama.autostart off); the daemon also re-starts a stopped local Ollama on boot (probe-first, loopback only, honours the same toggle). Without an embedding provider, recall stays on BM25 — nothing breaks. bastra status shows the active mode, and bastra doctor says explicitly when semantic recall is off or the model is missing.
Manual (no Homebrew): install + start Ollama, ollama pull embeddinggemma, then bastra embeddings on. Note: --yes does not trigger the Ollama download (use --ollama). Homebrew and the model come from third parties (Homebrew core, ollama.com). Full details: System Requirements (wiki).
Bastra Commons (beta)
bastra commons enable adds a second, read-only recall source: Bastra Commons, a community vault of verified engineering recipes — solutions with their failed paths, proven by use, where best-practice status is earned through independent verification records, never declared. Commons hits surface in recall with scope: commons, ranked just below your personal memories; the clone is git-synced (bastra commons update) and the daemon never writes into it. (The Commons repository opens to the public with its launch — see the wiki page for the model.)
Product docs (optional)
Beyond memories, the vault can keep living product documentation per project — user-facing docs ("how do I use this?") in dokumentationen/<project>/, one markdown file per feature area, updated in place via the save_product_doc tool. Off by default; enable with:
bastra config set docs.mode suggest # agent proposes a doc update when a feature area is finished
bastra config set docs.mode auto # agent updates the doc autonomously
bastra config set docs.language de # language the docs are written in (default: en)
With docs.mode set, the session hook injects the capture instruction: when a user-facing feature area is completely finished (works end-to-end, commit landed), the agent creates or refreshes that area's doc — written for the end user, no code internals. Developer-facing state (file maps, architecture) stays in project-fact memories. Docs are searchable via find_document; in the default recall they rank deliberately below memories so long doc bodies never crowd out lessons. Full details: Product Docs (wiki).
Vault map (optional)
bastra map opens an interactive, local-only map of your vault in the browser (http://127.0.0.1:6723/ui). Four views: Mindspace (the default — your vault as a navigable universe: galaxies, solar systems, nebulae and shooting stars, recenter with C), Clouds (force layout along your folder structure), Ring (a drill-down wheel over the memory building blocks, with a meta ring for taxonomy conventions and declared skills), and Semantic (arranged by embedding meaning, with dashed strands for connections you never wrote). The search combines instant matches, hybrid recall, and a local search copilot you can chat with to deepen a search — grounded in your notes, powered by the same local Ollama model as doc2query, nothing leaves the machine. An opt-in live mode shows new memories as supernovas and reads/changes/deletes as typed notices, with a session history panel of everything that happened while you watched; nodes carry an emotion-colored valence glow and a usage-heat core. An areas manager creates, renames and deletes top-level areas right in the browser (trash, never hard-delete), and care flags mark memories for a cleanup session right from the map. Off by default; bastra map offers to enable it (ui.enabled).
Full details: Vault Map (wiki).
Vault care — flag it now, groom it later
Memories age: titles go stale, duplicates creep in, ghosts point at notes you never wrote. bastra-recall turns tending the vault into a two-step loop instead of a chore. From any node's inspector on the vault map you flag a memory — delete, edit, write (for ghosts), or note — and the flags land as checkbox lines in an open vault-care.md at the vault root. Your next AI session sees the open flags automatically (session hook) and offers to work the list off with you: one guided cleanup pass, your call on every item. No hidden state, no separate app — a markdown checklist any editor can open.
Onboarding — five minutes to a warm start
A fresh vault offers to seed itself. Pick what your memory will mainly hold — code & projects, company & decisions, life & knowledge, or a mix — and answer a handful of persona-aware questions; every answer becomes a profile memory your AI recalls from day one. Three surfaces, one interview: the vault map auto-opens it on a fresh vault, bastra onboard runs it in the terminal, and your AI session offers it conversationally — the most adaptive of the three, it follows up where an answer is thin. Skippable everywhere, never asked twice.
Importing memories — skip the cold start
Your other AI tools already know you — bastra import brings that head start along instead of starting cold. Three paths, one gate: candidates land as checkbox lines in import-review.md at the vault root, and your next AI session distills accepted ones with you — proper type, concrete triggers, deduped against what the vault already holds. Nothing is saved without your accept.
bastra import memories.txt # a memory list: ChatGPT / Claude / Gemini export, free text — or paste via `bastra import -`
bastra import conversations.json # a full data export (ChatGPT / Claude) — queued for chunk-wise mining
bastra import rules # local rules files: CLAUDE.md, AGENTS.md, .cursorrules, .cursor/rules/, ~/.claude/CLAUDE.md
bastra import vault <dir> # a whole folder of memory files (e.g. a Claude Code memory dir) — no review needed
A conversations.json never stages raw chat history: only your own messages are kept (assistant turns dropped), queued locally under ~/.bastra/ — it never leaves the machine, is deleted when mining completes, and bastra import clear discards it anytime. Your AI session combs the queue chunk-wise (bastra import mine) and stages candidate lessons, decisions and preferences for your review. The vault map carries a visual import dialog (topbar ↓) for the paste path and the folder path.
import vault is the fourth path and skips the gate on purpose: a folder of already-structured memory files (Claude Code's name/description/type frontmatter — both its variants — or plain markdown notes) carries every field a memory needs, so it maps deterministically. The set lands isolated under memories/imported/<label>/ with its own scope and namespaced ids — nothing existing is read or modified, re-import is idempotent, and deleting that one folder removes the whole set.
Link targets that live on another surface (say, your Claude Code skills) can be declared once with bastra skills add <id> — declared ids render as solid nodes in the map's own skills ring instead of "unwritten" ghosts, and the curator stops reporting them as dangling links. No path, no folder scan, no sync: the id is the whole declaration (also available on any ghost node in the map — "Mark as skill").
Feedback
bastra feedback bug / bastra feedback idea opens a prefilled GitHub issue form in your browser. The bug form carries a sanitized diagnostics block — version, OS, Node, embedding mode, vault size; never file paths, never vault content — and you review and submit it yourself. The vault map links both forms in its sidebar.
Claude Desktop — autonomous memory without hooks
Claude Desktop has no hook system, so bastra makes memory autonomous through the MCP layer itself: the forwarder ships server instructions (the official session-start channel in Claude Code's engine), marks the read tools with read-only annotations (bulk-approvable in Desktop's permission UI), and appends the session context — pinned memories, durable preferences, conventions, open care/import/onboarding state — to the first tool result of every Desktop session, the same context the SessionStart hook injects in Claude Code. One-time setup on your side (tool access "Always available", "Allow always", a short memory prompt in your personal preferences) is printed by bastra install claude-desktop and documented in Claude Desktop (wiki). Prefer zero CLI? The .mcpb Desktop Extension installs with a double-click — vault-folder picker included, Bastra logo and all — grab it from the latest release. The Desktop app's Code tab shares Claude Code's configuration — hooks, skill and CLAUDE.md apply there unchanged.
Updating
bastra update pulls the latest release (npm or Homebrew), re-registers every surface, and restarts the daemon. Opt into hands-off updates with bastra config set update.mode auto — bastra then stages a new version at session start without disrupting a running session. Running bastra with no arguments shows version, update status, daemon health, and vault size.
Full details: Updating & settings (wiki).
REST API (for non-MCP clients)
The daemon exposes a REST API on http://127.0.0.1:6723/api/v1/ covering every tool the MCP server offers. This is the integration point for clients that can't speak stdio-MCP — most notably ChatGPT Custom GPT Actions, which call HTTPS endpoints with an OpenAPI schema.
Endpoints (all POST, JSON body):
| Endpoint | Tool |
|---|---|
/api/v1/recall |
recall |
/api/v1/load_memory |
load_memory |
/api/v1/save_memory |
save_memory |
/api/v1/find_document / read_document / open_document |
document search |
/api/v1/save_document / recategorize_document / move_document |
document write (Pro) |
/api/v1/save_product_doc |
product docs |
In addition, GET/POST /settings/docs reads/writes the product-docs settings ({mode, language}) — loopback-only like /hook/*, intended for local UIs such as the Bastra Mac app's options pane.
Auth and CORS:
- Token:
bastra tokenprints the daemon's API token, minting one on first use (bastra token rotateissues a fresh one;bastra token clearremoves it, locking out browser/REST clients). It's stored incli-settings.json; the daemon reads it at startup, so restart after issuing, rotating, or clearing.bastra(the status panel) andbastra statusshow whether a token is set, without printing it.BASTRA_API_TOKENoverrides it. - Local tools (CLI, MCP-forwarder — no
Originheader) reach/api/v1/*over loopback without a token. SetBASTRA_AUTH_LOOPBACK_SKIP=0to require the token even for them. - Browser clients (any request with an
Originheader) must always present the token and be on the CORS allowlist — even over loopback, since the user's browser shares127.0.0.1with the daemon and only theOriginheader tells a real site from a stray one. - CORS is deny-by-default: with
BASTRA_CORS_ORIGINunset, no browser origin is allowed. For a hosted web app, set an allowlist:BASTRA_CORS_ORIGIN=https://your.host(comma-separated for several) — the daemon then reflects only listed origins and a browser blocks the rest.BASTRA_CORS_ORIGIN=*remains available as an explicit tunnel/dev opt-in (the daemon logs a warning when combined with a minted token). - DNS rebinding is blocked: the token-less loopback endpoints (
/health,/hook/*,/vault/count) only answer requests whoseHostheader is loopback (127.0.0.1/localhost/[::1])./api/v1/*is unaffected (the token protects it). Tunnel setups that need more than/api/v1/*can allowlist hosts viaBASTRA_ALLOWED_HOSTS(comma-separated).
To reach this daemon from a hosted web app (e.g. a site's admin talking to the user's local vault from the browser), set BASTRA_CORS_ORIGIN to the site origin, run bastra token, and paste the token into the site. When that site is served over HTTPS (e.g. https://bastra.io), Chrome sends a Private Network Access preflight for the public-origin → localhost call; the daemon answers it automatically with Access-Control-Allow-Private-Network: true for allowed origins — no extra config. For a server-side client like ChatGPT, point a tunnel (Cloudflare Tunnel / ngrok / your own reverse proxy) at 127.0.0.1:6723 and configure it with the tunnel URL + your token. An OpenAPI 3.0 starter spec lives in docs/openapi.yaml.
Status: the ChatGPT Custom GPT Actions path does not work end-to-end yet. The REST API and the OpenAPI spec are in place, but the Custom GPT integration is still being worked out — see the roadmap below.
Roadmap
Milestone-based, not phase-based. Each gate is a hard pass/fail.
| Milestone | Scope | Status |
|---|---|---|
| M0 | Recall-quality eval on real vault | ✅ Done — Recall@1 98.3%, Recall@3 100%, MRR 0.992 across 59 memories (own-trigger baseline). BM25 + recall_when-boost is sufficient; embeddings deferred. |
| M1 | Daemon + read path (recall, load_memory) |
✅ Done — MCP server live, watcher works on cloud-storage mounts. |
| M2 | Save path + autonomous-save triggers | 🟡 Functional — save_memory MCP tool live with force-reindex. Trigger discipline shipped as a Skill. False-save / missed-save metrics not yet collected. |
| M0.5 | Stress-test recall (paraphrased / cross-memory / anti-hallucination) | ⏳ Open — see issues. |
| M3 | Reflex layer: hooks for SessionStart / UserPromptSubmit / PreToolUse / PostToolUse plus Stop |
🟡 Functional — seven quiet Claude Code hooks are installed by default; the Stop save-eval can be opted out with --no-stop-hook. |
| Distribution | Homebrew tap, bastra CLI, Install Bastra.command, npm package |
🟢 npm live — published to npm: npx bastra-recall install all / npm i -g bastra-recall work today; releases auto-publish on GitHub Release via OIDC trusted publishing. bastra CLI ships adapters for every surface. Homebrew tap n0mad-ai/tap is live (formula tracks the latest release) and the .command asset ships with each GitHub release. |
| Multi-surface | One install per AI client (MCP + Skill + Hooks where applicable) + REST gateway for non-MCP clients | 🟡 Functional — bastra install covers Claude Code (MCP + Skill + Hooks), Claude Desktop (MCP + Skill), Cursor (MCP). REST /api/v1/* exposes every tool over HTTPS + tunnel for non-MCP clients. Open: ChatGPT Custom GPT Actions (not working end-to-end yet), Claude.ai web Custom Connector registration (#7). |
Out of v0: multi-device sync. See PLAN.md.
Multi-device today works via the OS-level sync of the vault folder (iCloud / Google Drive / Dropbox / Git) — the file watcher's polling mode handles the latency. A browser-based UI is not planned — Obsidian already provides a great Markdown editor for the vault.
Bastra Mac App
A native macOS app is being built on top of bastra-recall — same vault, same daemon, just a graphical interface for people who don't want to live in the terminal. In development; a dedicated page with screenshots and updates will follow.
License
MIT — see LICENSE.
Public docs and code on this branch are published under the open license; private notes (in private/, gitignored) are not.
The statusline (packages/statusline/) bundles owloops/claude-powerline (MIT, © 2025 Owloops) as its rendering engine, with the bastra-status segment built in; the upstream license is retained in packages/statusline/LICENSE.
Status & contact
Early beta. See PLAN.md. Issues and discussions welcome — early feedback shapes the design. Please report security issues privately via SECURITY.md.
Built by @n0mad-ai.
🇩🇪 Deutsch
Was es ist — Ein Langzeit-Gedächtnis für jeden AI-Assistenten oder Agent: Claude (Code, Desktop, Web), ChatGPT (via Custom GPT Actions), Cursor und alles andere, was MCP oder HTTP spricht. Sobald du etwas korrigierst, eine Regel aufstellst oder eine Entscheidung triffst, wird das als kleine Notiz gespeichert. In der nächsten Sitzung — Tage oder Wochen später, in jedem Tool — holt die AI diese Notizen automatisch wieder hervor. Schluss mit ewigem Wiederholen. Alles bleibt lokal auf deinem Mac als reine Markdown-Dateien (Obsidian-kompatibel). Alle deine AI-Tools teilen sich dasselbe Gedächtnis gleichzeitig.
Status — 🟢 Frühe Beta. M0 (Eval) und M1 (Read-Path) fertig, M2 (Save-Path) funktional, und der Claude-Code-Reflex-Layer liefert Hooks für SessionStart, UserPromptSubmit, PreToolUse (Datei-Edits / Todos / Bash-Safety), PostToolUse (Bash Act-Signal + Fehler-Recall) plus optionalen Stop Save-Eval. Distribution und Multi-Surface-Hardening laufen. Siehe PLAN.md.
Warum
Wenn du Monate mit einem AI-Assistenten arbeitest, erklärst du dieselben Dinge immer wieder. Stolperfallen, die er in einem Projekt schon mal gelernt hat, kommen im nächsten zurück. Stabile Vorlieben ("gib mir eine Empfehlung, kein 5-Optionen-Menü") sind zwischen Sitzungen vergessen. Projekt-spezifische Fakten werden jedes Mal neu entdeckt.
Die meisten AI-Tools haben zwar Memory-Features, aber die sind passiv: bestenfalls eine statische Index-Datei, kein proaktives Erinnern, keine Kontinuität über verschiedene Oberflächen hinweg.
Der Preis ist nicht nur Frust — sondern dass am Ende der User für die AI mitdenkt. "Moment, das hatten wir doch letzte Woche schon gelöst?" Genau das ist der Bug.
Was bastra-recall macht
Eine persistente Gedächtnis-Schicht, die:
- Autonom speichert — wenn etwas gelernt wird (Frust, wiederholte Korrektur, dauerhafte Vorliebe, finale Entscheidung), schreibt die AI das ungefragt in den Vault. Die Trigger-Disziplin wird als Claude Code Skill ausgeliefert; andere Clients werden über ihren System-Prompt oder Custom-GPT-Instructions konditioniert.
- Vor dem Handeln erinnert — nicht erst auf User-Anfrage. Die AI wird angewiesen, den Vault vor dem Code-Schreiben, vor Plänen und beim Sitzungsstart abzufragen. Das höchstgewichtete Suchfeld ist
recall_when, das beim Speichern deklariert wird. - Über alle Oberflächen hinweg funktioniert — ein lokaler Daemon bedient alle deine AI-Tools gleichzeitig: Claude Code (via MCP), Claude Desktop (via MCP), ChatGPT (via Custom GPT Actions über HTTP), Cursor und alles weitere, was MCP oder HTTP spricht.
- Reines Markdown, Obsidian-kompatibel — der Vault ist ein Ordner mit
.md-Dateien und YAML-Frontmatter. Bearbeitbar in Obsidian, durch die AI oder per Hand. Vaults auf Google Drive / iCloud / Dropbox werden über den automatischen Polling-Modus des File-Watchers unterstützt.
Der einzige Erfolgs-Maßstab
Der User muss nicht mehr für die AI mitdenken.
Wenn wiederkehrende Fehler weiter auftreten, wenn der User in jeder Sitzung dieselben Vorlieben wiederholen muss — dann ist das Projekt gescheitert, egal wie sauber die Architektur ist.
Wie es funktioniert
Vault (konfigurierbar, reines Markdown + YAML-Frontmatter, Obsidian-kompatibel)
│ chokidar (Auto-Polling auf Cloud-Storage-Mounts)
▼
bastra-recall Daemon (TypeScript / Node 22+, ein lokaler Prozess)
- In-Memory BM25-Index (MiniSearch) — recall_when×5, title×4, tags×3, doc2query×2
- Hybrid Recall: BM25 + Embeddings (Ollama oder OpenAI) via RRF-Fusion
- doc2query (#117): offline Ollama paraphrasiert Trigger zur Schreibzeit → far
Recall, Query-Pfad unverändert (aus via BASTRA_TRIGGER_EXPAND=0)
- Tools: recall, load_memory, save_memory, find/read/save_document,
save_product_doc
- Save-Path: validiert Frontmatter → schreibt Datei → erzwingt Reindex
(sodass save und recall im selben Turn konsistent sind)
- Transport: stdio-MCP + HTTP-REST (für Nicht-MCP-Clients)
│
▼
Ein Daemon ↔ viele AI-Clients
- Claude Code / Desktop / Cursor → über dünnen MCP-Forwarder (stdio → HTTP)
- ChatGPT Custom GPT, Web-Apps, eigene Skripte → über REST /api/v1/*
- Alle Clients teilen denselben Vault, Index und Telemetry-Stream
Der Claude-Code-Reflex-Layer installiert standardmäßig sieben ruhige Hooks, die den lokalen HTTP-Endpoint des Daemons nutzen:
PreToolUse(bastra-recall-hook) — feuert vor jedemWrite/Edit/MultiEdit/NotebookEdit. Erkennt das Thema aus dem Tool-Aufruf und injiziert<recall-hints>alsadditionalContext.SessionStart(bastra-recall-session-hook) — feuert beistartup/resume/clear/compact. Lädt Top-User-Präferenzen + projektübergreifende Regeln + projekt-spezifische Memories als<session-context>vor, damit die AI ab dem ersten Prompt weiß: wer, was, und was-nicht.UserPromptSubmit,TodoWrite, Bash-Safety und Bash-Failure decken Lookup-Prompts, Topology-Recall vor Plänen, Safety bei riskanten Shell-Befehlen und Lesson-Recall bei fehlgeschlagenen Commands ab.
Der Stop Save-Eval-Hook ist standardmäßig an: seit dem #48-Redesign ist er
still — Vorschläge landen in einer Datei, die die nächste Session liest, ohne
Chat-Rauschen. Abwählen mit bastra install claude-code --no-stop-hook. Die Telemetrie (scripts/stats.ts)
misst pro Hook Latenz, Hint-Qualität und Follow-Through (hat die AI nach einem
Hint wirklich load_memory gemacht).
Details: docs/architecture.md, docs/memory-schema.md, docs/triggers.md.
Aufbau einer Memory
Jede Memory ist eine Markdown-Datei mit strukturiertem Frontmatter:
---
id: css-input-focus-ring-stacking
title: "Don't stack focus styles on inputs"
type: lesson
summary: "Stacking ring + outline + custom :focus on nested inputs causes double focus rings. Use single :focus-visible."
topic_path: [css, input, focus]
tags: [css, input, focus-ring, ui-bug]
scope: all-projects
recall_when:
- creating new input component
- writing input or form css
- focus or accessibility styling
related: [css-effects-stacking-antipattern]
source: "carnexus, recurring lesson"
confidence: 0.95
---
Das recall_when-Feld ist die Brücke zwischen Save und Recall: beim Speichern deklariert die AI die Kontexte, in denen die spätere Sitzung daran erinnert werden soll. Siehe docs/memory-schema.md für die vollständige Feld-Semantik und sechs Beispiel-Memories für lesson, preference, project-fact, meta-working, decision, workflow.
Selbstlernende Taxonomie
Der Vault baut sich seine Struktur selbst. Wenn jüngste Memories wiederholt dasselbe Ad-hoc-Cluster bilden (Personen, Orte, Tools, …), ohne dass es eine Heimat hat, schlägt der Stop-Hook vor, eine Konvention festzuhalten — ein Memory im reservierten Scope taxonomy, das Ordner, topic_path-Form und Tags des Clusters festlegt. Aktive Konventionen werden bei Session-Start injiziert und sind für künftige Saves bindend. save_memory nimmt ein folder-Argument, damit Cluster-Mitglieder einen echten Ordner bekommen (z.B. memories/people/); ein erneutes Speichern mit geändertem Ordner verschiebt die Datei (die alte Kopie landet recoverbar im Vault-Trash). Alles lebt pro Vault auf den freien Achsen — das type-Schema bleibt fix. Details: [docs/taxonomy.md](https://github
No comments yet
Be the first to share your take.