JBrain keeps what your agents learn as plain Markdown in a Git repo, and lets every agent read and write it over MCP, HTTP or the CLI. No embeddings. No model server. No API key.
./setup.sh
Detects Docker, falls back to a native build, writes your .env and prints the line that connects Claude Code.
One service holds the knowledge. Agents read and write it; you can read, diff and take it with you, because it is just files in Git.
Plain files
Each note is a Markdown file with YAML frontmatter in the Open Knowledge Format. IDs are paths like projects/jbrain. Unknown frontmatter is preserved.
Many agents, no collisions
Writes carry the revision the agent read. A stale write is refused with a clear conflict, never silently merged. Retrying with the same request ID is safe.
Search
BM25 over title, description, tags, aliases and body, with question filler ignored. No embeddings and no API key.
Links
Markdown links between notes become a graph: outgoing links, backlinks and bounded neighbours.
History in Git
Every write is a commit carrying the request ID and the actor. On by default, with a durable write journal behind it.
GitHub sync
Optionally push every commit to your own repo in the background. A failed push never blocks a write; it retries and reports in /health.
Any client
MCP over HTTP (12 tools), a plain HTTP API and a CLI. A stdio proxy covers clients that need it.
Crash safe
Atomic file writes, a journal replayed at startup, and tests that kill the process at each step.
Optional answers
brain_ask plans, reads and verifies an answer with a remote model. Everything else works without one.
Easy to run
One installer, a non-root Docker image with a health check, and about 20 MiB of memory.
Not here yet
Per-agent permissions: one shared token today (#1).
Pulling changes back from GitHub: sync is push-only (#7).
Paraphrase search: no embeddings, so questions that share no words with a note can miss (#3).
A web UI, prebuilt binaries and a published Docker image (#17, #10).
Set it up in four steps.
p. 003
You need git and either Docker or Rust 1.89+. The installer checks both and chooses for you.
Get the code
git clone https://github.com/Jayesh1512/jbrain
cd jbrain
Run the installer
./setup.sh
It uses Docker when a daemon and docker compose are available, and a native build otherwise. It asks for:
a port (default 7331);
optionally, a GitHub repo to sync to (see below);
Then it generates an access token into a private .env, builds, starts, waits until the service is healthy, and prints your connect command. Run it again any time: it offers to keep your .env and to change the sync settings.
Then ask your agent to search or write a note. The first write creates the knowledge repo and its first commit.
Sync every update to GitHub (optional)
Make a repo
Create an empty GitHub repository, private if the notes are not public.
A repo whose main already has other history rejects the push; JBrain never force-pushes.
Make a token
A fine-grained token limited to that repo, with Contents set to read and write.
Docker cannot see the credentials saved on your machine, so it needs this.
Tell setup
Run ./setup.sh and paste owner/repo at the sync prompt, then the token (hidden).
It checks it can reach the repo and offers to create it with gh.
Confirm
Say yes to the welcome note. The installer writes it and waits until it appears on GitHub.
Afterwards /health shows sync.pushedCommit and any error.
Only the Markdown knowledge is pushed, not the search index or the journal. Pushes are one way: GitHub edits do not come back yet.
Without the installer
# Docker
cp .env.example .env # set JBRAIN_TOKEN to a long random string
docker compose up -d --build
# Native (Rust 1.89+)
cargo build --release --locked
JBRAIN_TOKEN=change-me ./target/release/jbrain serve
Settings
Variable
Default
What it does
JBRAIN_TOKEN
unset
Bearer token for HTTP and MCP. Required whenever the service listens beyond localhost, which Docker always does.
JBRAIN_PORT
7331
HTTP port.
JBRAIN_DATA_DIR
.jbrain
Where the notes, search index and journal live (/data in Docker).
JBRAIN_HISTORY
git
Set off to skip the Git history.
JBRAIN_GIT_REMOTE
unset
Push every commit to this repo.
JBRAIN_GIT_TOKEN
unset
Token for an https remote. Sent only as a header when pushing; never written into the Git repo or logs.
JBRAIN_MODEL OPENAI_API_KEY
unset
Only for the optional brain_ask.
Every write is checked, filed and witnessed.
p. 004
Agents never open the database or touch the files. They ask one service, and every write takes the same six steps.
Agent sends the write
brain_write with actor, request ID, action, concept ID, expected revision and the full Markdown.
Retrying with the same ID and payload is safe and returns the original result.
Revision check
The service compares the revision you read with the file on disk.
A stale writer gets 409 REVISION_CONFLICT, then reads, merges and retries with a new ID.
File replaced
The concept file is written atomically and synced to disk.
Readers see the old version or the new one, never half of each.
Git commit
One commit per write in knowledge/.git, carrying the request ID and actor.
History, diffs and restore for every note. On by default.
Index published
Search rows, links and metadata update in one SQLite transaction.
A successful write is searchable immediately.
Optional push
A background thread pushes main to a GitHub repo you choose.
Never blocks a write. Retries with backoff, status in /health.
A crash between any two steps is repaired at startup from the journal. The test suite kills the process at each boundary and checks that nothing is lost.
Then every agent works the same way.
p. 005
Agents talk to the service; they never touch the files. Tell them to send two to five distinctive keywords, search once per fact, and read a note before updating it.
Clients that only speak stdio can run jbrain mcp as a proxy.
Real output from a test brain holding six sample notes, searching with a plain question: