Run your own AI brain on your own server. It remembers your documents (RAG over Postgres/pgvector), talks to whatever models you choose (local Ollama or your own API keys), and keeps everything on your box — no vendor sees your data, nothing phones home. It's for anyone who wants a private, personal AI with real memory instead of a chat box that forgets.
Governance, an append-only audit log, and optional federation with other brains are built in too — but you don't need any of that to run it. Start with the Quickstart; the deeper model is in Trust model below.
The names, once: BrainFoundry is the product · a single install is a brain · nous is our live public brain — a real running node you can talk to, not a canned demo · BrainKernel is the governance kernel (called
nodeosin the containers and env vars) · BrainFoundryOS is the federation protocol brains speak to each other. More in docs/NAMING.md. Part of hbar.systems — personalized intelligence.
ℏ, not HBAR: the name derives from ℏ (the reduced Planck constant) — unrelated to Hedera or the HBAR cryptocurrency. More: hbar.systems/hbar.
See a brain live right now: nous.brainfoundry.ai — a demo GIF lands here shortly.
One command on a fresh Linux box with Docker. It generates dev secrets into
.env, builds the stack, pulls the local model, and waits until the brain
answers — no cloud key required:
git clone https://github.com/hbar-systems/brainfoundry-nous.git my-brain
cd my-brain
./scripts/start_docker.shThen open the console at http://localhost:3010 and start chatting — it replies
from a local Ollama model with no API key set. Ingest your own documents with
python scripts/ingest_folder.py /path/to/docs.
Prefer to configure by hand first? Copy
.env.exampleto.envand set the four secrets (openssl rand -hex 32each →BRAIN_API_KEY,BRAIN_IDENTITY_SECRET,NODEOS_SIGNING_SECRET,NODEOS_INTERNAL_KEY), then run the same script — it leaves an existing.envuntouched. Full walk-through (including the persona file that makes the brain yours) is in Spin up your own brain below.
Links: brainfoundry.ai · hbar.systems · live public brain: nous.brainfoundry.ai — a real running node you can talk to, not a canned demo.
A full-stack AI brain you run on your own server. It connects to the models you
choose, stores your knowledge, and answers with memory of it. You own it. Nobody
else has access. (Product name: BrainFoundry; the governance kernel is
BrainKernel, named nodeos in the container and env vars — see
docs/NAMING.md.)
This repo is the reference implementation, not a polished appliance.
BrainKernel is the governance kernel (named nodeos in the container and env vars).
BrainFoundryOS is the overall platform and federation protocol; each node runs a
BrainKernel (internally nodeos) that handles persona, memory routing, and decision-making.
The guarantees it gives you today are:
- You are the only tenant. Designed for single-owner, self-hosted use. Not multi-tenant. Not a hosted service.
- BrainKernel gates the chat loop with caller-bound permits. Every
/chat/completionsand/chat/ragrequest must present both a validpermit_idand its HMAC-signedpermit_token. The token is issued once, fromPOST /v1/loops/request, and is bound to the agent that requested it — a leakedpermit_idcannot be replayed without the token. - Brain-layer mutations go through NodeOS.
remember,forget, andaudit.clearare routed through a propose → approve → execute flow against the NodeOS authority kernel before any database write or audit wipe lands. Fail-closed if NodeOS is unreachable. - BrainKernel is internal-only. NodeOS binds to
127.0.0.1:8001, has no browser proxy, and requiresX-Internal-Keyon all state-mutating routes. - External actions are preview-then-execute.
git_pushand similar side-effects go through a strict branch allowlist and a preview step before anything lands. - Append-only audit log. Every kernel command and every model call is recorded.
Known scope limits (v0.9): context.set / context.clear mutate an in-process
dict that resets on container restart and is not yet routed through NodeOS.
Bulk offline ingestion via scripts/ingest_folder.py writes directly to the
database for the single-owner bootstrap case. See SECURITY.md and Section
8 of docs/SELF_HOSTING_GUIDE.md for the full honest scope.
- FastAPI — chat, RAG, embeddings, identity
- BrainKernel — governance kernel (loop permits, mutation gate, append-only audit)
- PostgreSQL + pgvector — vector memory
- Ollama — local model fallback (always available, no API key needed)
- Next.js — console UI (dashboard, chat, knowledge, kernel)
- Redis — rate limiting
- Docker Compose — everything runs in containers
Connect your world (Integrations tab): read-only, untrusted-by-default, mostly
no-OAuth — email (IMAP app password), calendar (iCal link), Telegram
(chat your brain from your phone), Deep Research (cited multi-source web
synthesis), Tasks/reminders (due → Telegram ping), MCP servers (any tool),
and Drive (OAuth). Setup steps in docs/INTEGRATIONS.md.
Configure any combination. Only providers with a key set appear in the model selector. Ollama is always available with no key required.
| Provider | Key | Example models |
|---|---|---|
| Anthropic | ANTHROPIC_API_KEY |
claude-sonnet-4-6, claude-opus-4-6 |
| OpenAI | OPENAI_API_KEY |
gpt-4o, gpt-4o-mini, o3-mini |
GOOGLE_API_KEY |
gemini-2.0-flash, gemini-1.5-pro | |
| xAI | XAI_API_KEY |
grok-2, grok-beta |
| Groq | GROQ_API_KEY |
llama-3.3-70b, mixtral-8x7b (free tier) |
| OpenRouter | OPENROUTER_API_KEY |
deepseek, qwen, mistral, and more |
| Ollama (local) | none | mistral:7b, llama3.2, qwen2.5, phi3 |
- A Linux server (Hetzner CAX21 recommended — ~€7/mo)
- Docker + Docker Compose
- A domain (optional but recommended)
- At least one API key, or Ollama for fully local
git clone https://github.com/hbar-systems/brainfoundry-nous.git my-brain
cd my-braincp .env.example .env
nano .envFill in at minimum:
BRAIN_ID— unique name (e.g.alice-brain-01)BRAIN_NAME— display name (e.g.Alice's Brain)BRAIN_SYMBOL— a Unicode symbol shown in the nav (pick anything)BRAIN_OWNER— your name- At least one API key, or leave all empty to use Ollama only
- All secret fields — generate each with
openssl rand -hex 32
The tracked template is api/brain_persona.template.md. Copy it to the
gitignored api/brain_persona.local.md — the runtime prefers that file, and it
survives git pull / git reset --hard upgrades untouched:
cp api/brain_persona.template.md api/brain_persona.local.md
nano api/brain_persona.local.mdReplace the [CONFIGURE: ...] placeholders with who you are, what you work on,
your projects, your thinking style. This is what makes the brain yours.
The recommended baseline section at the bottom is advisory — delete it if you want.
(You can also edit the persona later from the console UI.)
docker compose up -ddocker compose exec ollama ollama pull mistral:7b
# also available: llama3.2, qwen2.5:7b, phi3, deepseek-r1:7bOrganize documents into folders and ingest:
python scripts/ingest_folder.py /path/to/your/docsThis is what makes the brain know you. The more you ingest, the more personal it becomes.
RAG tier folders (optional): The brain prioritizes documents from certain folders during search. Default folder names (configurable via env vars):
| Folder | Env var | Priority | Purpose |
|---|---|---|---|
identity/ |
RAG_TIER1 |
Highest (always 2) | Who you are, core context |
thinking/ |
RAG_TIER2A |
High (always 1) | Notes, active reasoning |
projects/ |
RAG_TIER2B |
High (always 1) | Current work, in-progress |
writing/ |
RAG_TIER2C |
High (always 1) | Essays, published work |
| everything else | — | Similarity search | General corpus |
You can use any folder names — set RAG_TIER1, RAG_TIER2A/B/C in .env.
Or skip the structure entirely and let the similarity search find everything.
- Console UI:
http://your-server:3010 - API:
http://your-server:8010(OpenAPI docs disabled — seedocs/DEPLOYMENT.md)
Security note: Port 3010 proxies the API server-side using your
BRAIN_API_KEY. Do not expose it to the public internet without a firewall rule, VPN, or reverse proxy with authentication. Anyone who can reach port 3010 can use the brain.
Add a domain with Caddy for HTTPS — see docs/DEPLOYMENT.md.
Before exposing your brain to the internet:
# 1. Generate all secrets (run once, save output to .env)
openssl rand -hex 32 # → BRAIN_API_KEY
openssl rand -hex 32 # → BRAIN_IDENTITY_SECRET
openssl rand -hex 32 # → NODEOS_SIGNING_SECRET
openssl rand -hex 32 # → NODEOS_INTERNAL_KEY (service-to-service auth between api ↔ nodeos)
# 2. Generate federation keypair (required for /identity endpoint)
python scripts/generate_keypair.py
# Copy BRAIN_PRIVATE_KEY and BRAIN_PUBLIC_KEY output into .env
# 3. Set non-default postgres credentials in .env
POSTGRES_USER=your_db_user
POSTGRES_PASSWORD=your_strong_password
# 4. Set BRAIN_ENV=prod in .env — enables startup secret enforcement
# 5. Build and start
docker compose up -d --buildSecurity notes:
- PostgreSQL binds to
127.0.0.1only — never exposed to the public internet - Never commit
.env— it is gitignored - The
GITHUB_TOKENapproach (git credentials in container) is for development convenience only; for production use SSH deploy keys instead
If your brain is a public-facing node (e.g. nous.brainfoundry.ai) and you
want strangers to be able to chat with it without exposing the operator
console, deploy the split-surface layout. The repo ships a minimal Next.js
chat app at apps/public-chat/ (port 3020) and a brain endpoint
POST /v1/public/chat that takes no API key.
https://your-domain/ → :3020 (public chat, no auth, IP rate-limited)
https://console.your-domain/ → :3010 (operator console, basicauth)
https://api.your-domain/ → :8010 (brain API, X-API-Key)
The console and api subdomains keep their existing auth — only the bare
domain is publicly reachable. The Caddyfile blocks for the public-facing
vhosts must include trusted_proxies private_ranges so Caddy overwrites
client-supplied X-Forwarded-For with the real client IP. The brain reads
the last hop of XFF for per-IP rate limiting; without trusted_proxies,
strangers can rotate fake XFF values to defeat the limit.
/v1/public/chat hard-codes layers=["public"]. Only documents tagged
metadata.layer = "public" are visible — every other document is
default-deny. Seed the public corpus by uploading docs to the brain with
metadata.layer="public" set; the operator console upload UI does not
expose this layer (intentional — out of scope for v0). Recommended seed
docs ship in docs/public/.
Defaults: 10 requests / 60 seconds / IP. Configure via env:
PUBLIC_RATE_LIMIT_MAX=10
PUBLIC_RATE_LIMIT_WINDOW=60
The limiter is Redis-backed and fail-closed (Redis down → 429, not 200).
The public chat path does not use BRAIN_API_KEY. Auth is rate-limit-only.
The relay (apps/public-chat/pages/api/chat.js) does not forward any
Authorization header. The endpoint is intentionally unauthenticated and
intentionally read-only — no permits, no DB writes, no session persistence.
Operator console and the rest of the brain API still require X-API-Key
exactly as before.
Public chat injects api/brain_persona_nous.md as its system prompt instead
of api/brain_persona.md (the operator's personal persona). The personal
persona must never leak onto a public surface — the two are deliberately
separate files.
If you're running the brain at a domain that previously exposed the API on
the bare hostname, switching to the three-vhost layout is a breaking
change: any CLI tool whose config still points at the bare domain will
hit the public chat app and 404 on /v1/* paths. Move CLI defaults to
api.your-domain before flipping the Caddyfile.
Your brain is a git clone of this repo. There is no vendor upgrade channel,
no forced updates, no telemetry. You choose when to pull and what to pull.
Track main (latest stable):
ssh <you>@<your-brain-host>
cd /path/to/your/brain # wherever you cloned it
git pull origin main
docker compose up -d --build api uiPin to a specific commit (reproducible, audit-friendly):
git fetch
git checkout <commit-sha>
docker compose up -d --build api uiFork and run your own changes: also fine. It's your brain. The only
contract that must stay compatible across forks is the federation protocol
(/identity + POST /v1/federation/assertion) so other brains can still
verify you.
This means three populations run this repo side-by-side and all three work:
- BrainFoundry-provisioned customers — default, track
main. - Self-hosters —
git clone+docker compose upon any VPS. - Forkers — diverge however you want.
Backwards-incompatible changes are always called out in CHANGELOG.md with
an upgrade note. See ROADMAP.md for what's coming and what's deferred.
White-glove personal service:
Email hello@hbar.systems — subject line brainfoundry.
BrainFoundry reviews your request and crafts your brain personally.
A federating peer cannot accept assertions from this brain until the brain's substrate-depth signal clears the configured thresholds. The substrate floor is a federation-membership precondition — it does not gate ingestion, only cross-brain trust. Design rationale: discussions/2026-05-01_federation-trust-mechanisms.md.
Endpoints:
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET |
/v1/federation/substrate-depth |
none | Public signed depth signal (5-min cache). |
POST |
/v1/federation/assertion |
pinned-peer ED25519 | Adds a substrate-floor gate after sig + replay checks. |
Default thresholds (env-tunable):
| Env var | Default | Meaning |
|---|---|---|
FEDERATION_SUBSTRATE_MIN_ARTIFACTS |
50 | Minimum total attestation rows. |
FEDERATION_SUBSTRATE_MIN_FIRST_PERSON |
25 | Minimum non-derived rows. |
FEDERATION_SUBSTRATE_MIN_DIVERSITY |
2 | Minimum distinct source_type values. |
FEDERATION_SUBSTRATE_MIN_AGE_DAYS |
7 | Minimum (now − oldest_artifact_ts).days. |
SUBSTRATE_DEPTH_CACHE_SECONDS |
300 | Server-side cache of the signed payload. |
SUBSTRATE_PEER_CACHE_SECONDS |
300 | Per-peer fetch+gate cache. |
FEDERATION_SUBSTRATE_GATE |
on | Set off to disable the gate (endpoint still served). |
These are the prompt's starting points, untested. Operators may need to seed test brains rather than weaken the floor — see the discussions doc.
Backfill: brains with pre-existing RAG corpus need attestations generated
for the historical chunks. Use scripts/substrate_backfill.py (DRY-RUN
default, pass --commit to apply). Read the script docstring before running.
Failure response shape (HTTP 403):
{
"ok": false,
"code": "substrate_floor_not_met",
"details": {
"artifact_count": { "got": 12, "required": 50 },
"first_person_count": { "got": 4, "required": 25 }
}
}Other codes: signature_invalid, substrate_depth_unreachable. Tests:
pytest tests/test_substrate.py -v.
This node implements the BrainFoundryOS node contract.
See docs/brainfoundry/NODE_CONTRACT.md for the full spec.
The protocol is open. The brain is yours.
AGPL-3.0 — see LICENSE.
Run it, modify it, self-host it freely. If you run a modified version as a service, you must release your modifications under the same license.