Central Brain
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Central Brainwhat's my active goal and any decisions I should know about?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Central Brain
Persistent, goal-oriented memory and work ledger for Claude Code.
Claude sessions forget everything when they end. Central Brain gives them one durable memory that every session, in every project, reads and writes:
Goals, not tasks. Each piece of work is a goal with a locked contract: objective, scope, constraints and success criteria.
Evidence, not claims. A goal completes only when each criterion has verified evidence and the converge report is clean.
Memory that compounds. Decisions, failures and their fixes, learnings and project knowledge are stored, searched and reused.
It is a local SQLite database (~/.central-brain/brain.db) with a CLI, an MCP server for Claude Code, and session hooks that inject context automatically. There are no external services: search is hybrid full-text plus local ONNX embeddings.
The full design is in ARCHITECTURE.md, and the agent operating rules are in CLAUDE.md.
Quickstart
Requirements: Node.js 20+, Claude Code, and jq and sqlite3 on PATH (used by the prompt hook).
git clone https://github.com/localhost-anon/central-brain.git ~/Projects/central-brain
cd ~/Projects/central-brain
npm install
npm run build
npm link # optional: puts `brain` on your PATH
brain init # creates ~/.central-brain/brain.db and applies migrationsThe hook scripts assume the repo lives at ~/Projects/central-brain. If you clone it somewhere else, edit the paths in hooks/ and bin/brain-claude.
Register the MCP server so Claude Code can call the brain_* tools in every project:
claude mcp add --scope user central-brain -- node ~/Projects/central-brain/dist/mcp/server.jsWire the hooks in ~/.claude/settings.json:
Event | Script | What it does |
|
| Injects |
|
| Reminds the session to consult Brain first and names the active goal |
|
| Reminds the session to persist decisions, learnings and verification |
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "~/Projects/central-brain/hooks/session-start.sh" }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "~/Projects/central-brain/hooks/user-prompt.sh" }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "~/Projects/central-brain/hooks/stop.sh" }] }],
"PreCompact": [{ "hooks": [{ "type": "command", "command": "~/Projects/central-brain/hooks/stop.sh" }] }]
}
}Optionally, register your projects with brain project scan ~/Projects, and run brain embed reindex to enable semantic search. The first run downloads a small embedding model to ~/.central-brain/models.
Related MCP server: waypath
How a goal flows
create → intake → lock → plan (work units) → start → work → verify → converge → completeCreate. Run
brain goal create "<title>" -o "<objective>".Intake. Run
brain goal intake <id>. It surfaces related memory and contract gaps, and asks two standing questions:review:behaviour: which user-visible choices does this involve?review:coverage: which areas still need contract lines? The areas are behaviour, data, failure modes, edge cases, non-functional, integration and completion.
Sessions may add at most 5 material questions of their own, each with a recommended answer. Ask them in one batch.
Lock. Run
brain goal lock <id>. Lock refuses unless:the contract is complete;
every required success criterion states one claim and has a verify method (
test | command | api | inspection | manual);every applicable principle is acknowledged (see Principles below).
Plan and start. Create work units with
--serves <criterion ids>.brain goal startrefuses while any required criterion has no work unit serving it.Verify. For each criterion, run
brain verify add … --verdict verified|partial|failedwith the real observed output.partialnever counts as passing, and averifiedverdict needs actual output plus a verification type that matches the criterion's verify method.Converge. Run
brain goal converge <id>. It lists typed findings:missing, partial or contradicting evidence;
stale evidence (recorded before later work finished);
unfinished work;
open failures;
uncovered criteria.
Fix them until it reports converged.
Complete.
brain goal complete <id>refuses while CRITICAL or HIGH findings remain.--forceneeds--reason; the reason is recorded as a decision and the goal is permanently marked as force-completed. A goal that was never locked cannot complete without force.
Failures resolve only with a solution that has --verdict verified and a --reproduction note saying how the original symptom was re-checked. Passing tests alone count as partial.
Principles are durable rules stored as knowledge with category principle, scoped either GLOBAL or to a project (for example "sandbox first"). Link a goal to its project with brain goal link-project. Then acknowledge each principle with brain principle ack, either as honoured or as an exception with a reason; an exception is recorded as a decision.
Rules versions. Goals locked before these rules shipped stay on rules_version 0 and keep the original, simpler completion check. Every goal locked afterwards gets rules_version 1.
Staleness. Open goals with no activity for BRAIN_STALE_DAYS (default 7) are skipped by brain goal current and listed at session start. Close them with goal complete, or retire them with brain goal cancel <id> <reason>.
Command reference
brain <group> --help shows every option. Every command prints JSON.
Group | Commands |
Setup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The MCP server exposes the same operations as brain_* tools. Examples include brain_goal_intake, brain_goal_converge, brain_principle_ack and brain_failure_solution_add. Their descriptions carry the rules above, so sessions learn them from the tool list.
Web UI and phone access
brain ui starts a web UI. It lists goals, shows each goal's contract and live timeline, lets you answer worker questions and approve actions, and launches a headless Claude worker per goal.
Projects. The sidebar groups goals by project. On a phone, the ☰ button opens it as a drawer. A goal's project is set in these ways:
A goal that you create through MCP or
brain goal createlinks to the registered project that contains the current folder.--project <name>overrides it.You can change the project with the picker on the goal page, or with
brain goal set-project <id> <project|none>.brain project infer-goals [--dry-run]links existing goals once. It uses paths in the contract, project-scoped records, the worker's folder, or a project name in the title. It never changes an existing link, and it leaves unclear goals in "Unassigned".
The UI listens on 127.0.0.1:4410. It also listens on the Mac's Tailscale IP, 100.92.71.97 by default, while that address exists on a local interface (Tailscale is up). It never listens on 0.0.0.0.
Reach it from a phone. Turn Tailscale on in the phone and open http://100.92.71.97:4410. Use the IP: the Host check accepts IP addresses only, not the MagicDNS name. The phone connects to the Mac directly over the tailnet, with no subnet router in the path, so it works on any network.
Source-IP allowlist. Only these addresses can connect:
Address | Device |
| localhost |
| the Mac itself |
| the phone ( |
Every other address gets 403, and ~/.central-brain/logs/ui.log records it as refused <ip> …. To add another device, pass its tailnet IP (tailscale status) with --allow-ip. --allow-ip replaces the default list, so repeat it for every device you want to keep.
Configure it with --host <ip|none>, --port <n> and --allow-ip <ip> (repeatable), or with the env vars BRAIN_UI_HOST, BRAIN_UI_PORT and BRAIN_UI_ALLOW_IPS.
No login. Anything that can connect from an allowed address can launch auto-mode Claude workers on the Mac. The allowlist is the only gate. A Tailscale ACL that lets only the phone reach
100.92.71.97:4410adds a second gate.
Keep it running. brain ui install-agent installs a launchd agent that starts brain ui at login and restarts it if it stops. The agent runs under caffeinate -s, so the Mac does not sleep while on AC power. Check it with brain ui agent-status, and remove it with brain ui uninstall-agent.
Install the agent from the checkout you run day to day, because the plist stores absolute paths to node and dist/. Run install-agent again after you upgrade Node or change any flag.
A MacBook still sleeps when you close the lid. To keep it awake with the lid closed, run sudo pmset -a disablesleep 1 yourself, and use sudo pmset -a disablesleep 0 to undo it. Brain never runs sudo.
Phone pushes (ntfy). brain ui sends a push to a self-hosted ntfy server when:
Event | Priority |
A worker waits for your answers or an approval | high |
A worker finished | normal |
A worker failed | high |
A goal completed (also from terminal sessions) | normal |
A push shows the project, the goal title and the reason. It never shows question text, paths or logs. Tap it to open the goal. State that exists when the UI starts sends nothing, and a stopped worker sends nothing.
The notifier reads ~/.central-brain/ntfy.json (keep it mode 600; it holds the token):
{ "url": "http://100.95.99.70:2586", "topic": "brain", "token": "tk_…", "uiUrl": "http://100.92.71.97:4410" }Without the file, the notifier is off and ui.log says notifier off. If ntfy is unreachable, the UI keeps running and logs push failed. There are no retries. Restart the agent after you change the file (brain ui install-agent).
Chat with a worker. Each goal page has a message box under the thread. Type a message and tap Send (Cmd/Ctrl+Enter on a keyboard). Messages are 1 to 4000 characters.
Worker state | What happens to your message |
Live, between turns | The worker gets it at once. |
Mid-turn (working or waiting for an approval) | The worker gets it when the current turn ends. It goes before the automatic "continue" nudge. |
Stopped, finished or failed | Brain resumes the last worker session with your message as the first input. |
Never started | Brain starts a worker with the goal brief plus your message. |
The thread shows your messages as "You", the worker's full text replies, and tool calls as one-line events. It covers every run of the goal. A message sends no push.
Your messages and worker replies render basic markdown: bold, italic, inline code, code blocks, bullet and numbered lists, links, and headings (as bold lines). Pipe tables stay as monospace text. Only http, https and mailto links are clickable, and they open in a new tab. All message text is HTML-escaped first, so a message cannot inject markup. Brain stores the original text unchanged. When a message cannot reach the worker (the process is gone, or it is still shutting down), the UI shows the error and Brain stores nothing.
On the phone, install the ntfy app, add the server URL, log in, and subscribe to the topic. The server in this setup is on the tailnet only, so pushes arrive while Tailscale is on.
Data and safety
Location. The database is at
~/.central-brain/brain.db. Override it withBRAIN_DB. The database never lives in the repo.No secrets. Do not store secrets in Brain. Reference environment variable or credential names instead.
No auto-migration. Sessions never migrate the live database. After pulling schema changes, run
brain migrate, which snapshots first. Until then,context getreturns a "schema update pending" notice.Check migrations on a copy.
npx tsx scripts/check-migration-on-copy.tsmigrates a copy of your database and confirms all goals are unchanged.
Development
npm test # vitest (in-memory and temp-file databases only)
npx tsc --noEmit # type check
npm run build # compile to dist/
npm run db:generate # generate a drizzle migration after editing src/db/schema.tsThe code is organised as follows:
src/services/: one module per concern.src/services/contract-rules.ts: every gate rule, as pure functions.src/cli/andsrc/mcp/: thin wrappers over the services.drizzle/: migrations. They must be additive.
Contributing
main is protected. All changes, including the owner's, go through a pull request, and every PR needs the code owner's approval before it merges. Open a branch, keep npm test and npx tsc --noEmit green, and describe the outcome in the PR.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent cross-session memory shared by Codex, Claude Code, ChatGPT, and other AI agents.
The project brain for AI coding agents — memory, decisions, sprints, knowledge base via MCP.
- SeturosOAuthcom.seturos
Shared work memory for Claude Code, Codex, Cursor and chat, scoped to each repository.
A second brain for Claude: remembers your work, plans your day, encrypted under a key only you hold.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceLocal-first persistent memory layer for AI agents. Provides hybrid search (FTS5 keyword + vector embeddings) over 223K+ knowledge chunks via MCP. Tools: brain_search, brain_store, brain_entity, brain_subscribe. Features pub/sub with stable agent identity, delivery tracking, and Claude --channels integration. SQLite + BrainBar Swift daemon on Unix socket.1,992 PyPI9Apache 2.0
- AlicenseAqualityCmaintenanceLocal-first external brain for Claude Code, Codex, and any MCP client. Stores decisions, entities, and session artifacts in one SQLite file and exposes MCP tools for recall, page, promote, review, graph-query, and source-status.114 npm6MIT
- AlicenseBqualityDmaintenanceProvides persistent memory, skill tracking, failure indexing, and context sharing for Claude Code using SQLite with FTS5 full-text search.2315 npm1MIT
- AlicenseNot gradedqualityDmaintenanceProvides persistent, searchable memory for Claude Code using local SQLite, semantic embeddings, and full-text search, enabling Claude to recall and retrieve context across sessions and projects without external services.8 npm4MIT