Docs

Getting started

Two ways to run the same brain: hosted at brainz.brownmatter.ai (free, remote MCP over HTTP) or local-first from a folder of markdown (open source CLI, MCP over stdio). Both expose the identical vault toolset, so your orchestrator doesn't care which one it's talking to.

Connect from Claude or ChatGPT

Claude and ChatGPT connect to Brainz with OAuth: you add one URL, sign in to Brainz in your browser and pick a vault. There's no API key to copy. You need a free Brainz account with at least one vault. The server URL is the same for everyone:

https://brainz.brownmatter.ai/mcp

Connect from Claude

In claude.ai or Claude Desktop:

  1. Open Customize › Connectors and choose Add custom connector.
  2. Name it Brainz, paste https://brainz.brownmatter.ai/mcp as the URL, and click Add.
  3. Click Connect. Claude opens brainz.brownmatter.ai: sign in with a magic link or GitHub if you aren't signed in already.
  4. The consent screen names the client and what it is granted. Tick the vaults it may use (or All my vaults) and click Approve. You're returned to Claude, connected.

Once Brainz is listed in the Claude connectors directory you can find it by name there instead of adding the URL by hand.

In Claude Code, add the server without a header and sign in from the /mcp menu:

claude mcp add --transport http brainz https://brainz.brownmatter.ai/mcp
# then, inside Claude Code:
/mcp    # pick brainz → Authenticate

Your browser opens the same sign-in and consent screen, and the token is stored by Claude Code. (Prefer a vault API key? See Hosted below.)

Connect from ChatGPT

  1. Open Settings › Apps & Connectors. While Brainz isn't listed in the ChatGPT directory, turn on Developer mode under Advanced settings so you can add your own connector.
  2. Create a connector named Brainz with the URL https://brainz.brownmatter.ai/mcp and authentication set to OAuth.
  3. Click Connect, sign in to Brainz, tick the vaults ChatGPT may use on the consent screen and click Approve.
  4. Start a new chat, turn Brainz on for it, and ask about your vault.

What a connection can do

  • One connection, the vaults you tick. The client reaches only the vaults you tick on the consent screen, or every vault you belong to if you choose All my vaults, including ones I create or join later. With more than one vault, every tool takes a vault argument (a slug or id) and list_vaults lists them. To change the set, connect again.
  • Your role decides the tools, on every call. Owners and editors get sixteen tools: every vault tool in the table below except session_hook. Viewers get six read tools (search_concepts, get_concept, get_related, get_context, list_concepts, vault_stats), so a viewer's connection is read-only. If an owner changes your role or removes you from the vault, the connection follows straight away.
  • Reads and writes are labelled. Read tools change nothing. Tools that can overwrite or delete are marked destructive, so the client asks before running them.
  • Brainz sees tool calls, not your chat. It receives each tool call's arguments, never the conversation, and it can't read your repository or files.

Disconnect

Remove the Brainz connector in Claude or ChatGPT (in Claude Code, claude mcp remove brainz). The client discards its tokens; access tokens expire within an hour and unused refresh tokens after 30 days. Removing a member from a vault cuts off every connection they made to it.

Hosted: remote MCP in two minutes

  1. Sign up — it's free — and create a vault.
  2. In the vault's settings, create an API key. Keys look like bz_…, are scoped to that one vault, and are shown exactly once — store it like a secret.
  3. Add the server to your MCP client. In a project's .mcp.json:
{
  "mcpServers": {
    "brainz": {
      "type": "http",
      "url": "https://brainz.brownmatter.ai/mcp",
      "headers": { "Authorization": "Bearer bz_..." }
    }
  }
}

Or with the Claude Code CLI:

claude mcp add --transport http brainz https://brainz.brownmatter.ai/mcp \
  --header "Authorization: Bearer bz_..."

That's the whole integration. Your orchestrator can now call vault_stats to orient itself, search_concepts to explore, and get_context to brief subagents. Clients that support MCP discovery can also find the server themselves via /.well-known/mcp.json (registry name ai.brownmatter/brainz).

Agent-driven signup: human in the loop, not in the way

An orchestrator doesn't need a pre-made account. Point it at https://brainz.brownmatter.ai/mcp/agent without an Authorization header and it gets a public MCP server exposing two tools — signup and sign_in (the vault tools stay behind authentication). The key it gets works on https://brainz.brownmatter.ai/mcp too. https://brainz.brownmatter.ai/mcp itself never hands out keys: there, clients such as Claude and ChatGPT sign in with OAuth (Connect from Claude or ChatGPT).

# 1. connect UNAUTHENTICATED to https://brainz.brownmatter.ai/mcp/agent — no Authorization header
#    initialize → tools/list shows two public tools: signup and sign_in

# 2. provision a workspace — no email, no human action required
→ tools/call signup { "vaultName": "Acme brain" }

# 3. the result is everything the agent needs — and no URL of any kind
← {
    "apiKey":         "bz_…",              // works immediately — keep it secret
    "vaultSlug":      "acme-brain",
    "expiresAt":      "2026-07-18T…",      // workspace expires in 7 days unless claimed
    "claimEmailSent": false
  }

# 4. keep it: the claim tool (authenticated) emails YOUR HUMAN an approval link
→ tools/call claim { "email": "you@company.com" }
← { "status": "sent", "expiresAt": "…" }   // link goes to the inbox, never to the agent

The apiKey works immediately — the agent reconnects to the same endpoint with Authorization: Bearer bz_… and can start seeding the vault right away. The workspace is provisional: it expires in 7 days unless a human claims it. To keep it, the agent calls the claim tool with its human's email — the approval link is emailed to the human and never returned to the agent, so an agent can never see, open, or leak it. Passing email to signup fires the same claim request in one call. Returning humans use the sign_in tool instead: a one-time magic sign-in link lands in their inbox — no password to choose, ever (Brainz is passwordless). Signups are rate-limited to 5 per hour per IP.

Bring your team

A vault isn't a solo brain. From the vault's settings, owners invite teammates by email — each invite is a single-use link that expires in 14 days — and assign a role: owner (everything, including keys, members, and invites), editor (read and write concepts and tasks), or viewer (read-only). Roles are enforced on every REST route and MCP call, so a colleague in the dashboard and an agent holding an API key play by the same rules. Humans and agents share one brain.

Onboard your product

A fresh vault is an empty brain. The onboard tool fixes that without you writing a single note: your orchestrator calls onboard with {"action": "start"} and receives a playbook — fan subagents out over the codebase, distill what they find into the product ontology, and write it back with upsert_concept.

The ontology is eleven concept types, and five of them carry the structure: domain (high-level product areas — the top of the graph), feature (concrete capabilities, part_of a domain), story (user stories, realized_by the features that deliver them), spec (the rules that govern features and stories), and workflow (multi-step journeys across features) — plus task (a unit of work not yet in the codebase, claimed off a real-time Kanban board via take_task) and the classics: concept, decision, constraint, pattern, glossary. Every concept can carry code_areas — rough paths or globs pointing at where that knowledge lives in the codebase — so a subagent briefed by get_context learns the rules and where to apply them.

Onboarding is a loop, not a one-shot: the agent indexes an area of the codebase, calls onboard with {"action": "status", "areaList"} to see which areas are covered and which aren't, and keeps going until coverage is broad — expect hundreds of concepts on a real codebase, not dozens. {"action": "complete", "summary", "areaList"} is coverage-gated: it rejects if too many areas are still uncovered. Until it succeeds, search_concepts and get_context responses carry a one-line reminder — a nudge, never a wall. Local vaults get the same flow via brainz onboard.

Local-first: a vault is just a folder

The open-source CLI runs the same engine against a directory of markdown. Notes are plain files with YAML frontmatter; the search index is derived SQLite in .brainz/ — gitignored, safe to delete, rebuilt from your files.

# scaffold a vault (config + concepts/ + a sample note)
npx brainz init my-vault

# add concepts and link them
npx brainz add "Billing Engine" --vault my-vault --type feature --body "Handles invoicing."
npx brainz add "Ledger" --vault my-vault --body "Double-entry ledger."
npx brainz link billing-engine ledger --relation depends_on --vault my-vault

# query it
npx brainz search "billing" --vault my-vault
npx brainz context --query "billing" --budget 800 --vault my-vault

Serve the vault to your agents over stdio MCP:

{
  "mcpServers": {
    "brainz": {
      "command": "npx",
      "args": ["brainz", "mcp", "--vault", "/absolute/path/to/my-vault"]
    }
  }
}

(Running the brainz-mcp binary directly? It can take the vault directory from the BRAINZ_VAULT environment variable instead of a flag.) Search is hybrid (full-text + embeddings, fused by reciprocal rank); if an embedding provider isn't configured or available, it degrades gracefully to keyword-only.

The seventeen MCP tools

These names and descriptions are the exact text your orchestrator sees — lifted from the tool registry that both the hosted and local servers register from, so they never drift.

ToolDescription
search_concepts
Search concepts
Search the product knowledge vault by free-text query. Useful when you need product knowledge but don't yet know which concept ids exist. Returns ranked hits (id, title, type, score, snippet) only; get_concept returns one full note and get_context an assembled briefing. An empty hit list means nothing matched.
get_concept
Get concept
Fetch one concept by exact id: full markdown body, metadata, and its direct graph neighbors (each with the relation that connects it). Use after search_concepts or when another note wiki-links an id you need in full. The neighbors list tells you what to fetch next. If you don't know the id, use search_concepts instead.
get_related
Get related concepts
Walk the knowledge graph outward from a concept and return everything within `depth` hops, with distance and the edge path that reached it. Use to map the blast radius before changing a feature (what depends on it, what constrains it, which decisions apply) or to discover structure that keyword search misses. Filter by relation names (e.g. depends_on) to follow only one kind of edge.
get_context
Assemble context bundle
Assemble a markdown briefing of the concepts most relevant to a query and/or explicit ids, expanded through the graph and trimmed to a token budget. The briefing is self-contained, so it can be handed to another agent or pasted into a prompt as-is. The final JSON line reports which concept ids were included, whether the bundle was truncated, and its approximate token count. Provide at least one of `query` or `ids`.
upsert_concept
Create or update concept
Write a concept note into the vault (creates or overwrites the markdown file, then reindexes it). Use to capture new product knowledge discovered during a task — a decision made, a constraint hit, a pattern adopted — so future agents can find it. Omit `id` to derive a slug from the title; pass an existing id to update that note. Body is markdown; [[wiki-links]] to other concept ids create graph edges. Returns the saved concept's metadata.
delete_concept
Delete concept
Remove a concept from the vault and all of its outgoing edges. Use to clear a note that is wrong, obsolete, or junk (e.g. a probe or test node that shouldn't be in the graph). Idempotent: deleting an id that doesn't exist is a no-op success (deleted:false), not an error. Deletion is permanent — prefer upsert_concept to correct a note you want to keep. Returns { deleted, id }.
link_concepts
Link concepts
Add a typed, directed edge between two existing concepts by editing the `from` note's frontmatter (e.g. lead-scoring depends_on contact-model). Use when you notice a relationship the vault is missing. Both concepts should already exist; use upsert_concept first if not.
list_concepts
List concepts
Enumerate concept metadata (no bodies), optionally filtered by product, type, or a single tag. Use to get the lay of the land in an unfamiliar vault, to audit what exists (e.g. all decisions for a product), or when search vocabulary isn't matching. For content, follow up with get_concept or get_context.
vault_stats
Vault stats
Summarize the vault: counts of concepts and edges, the products and tags in use, a breakdown by concept type, and whether semantic search is available. Useful for gauging how much knowledge is here and which product/tag filters exist.
onboard
Onboard this vault
Index an existing product's codebase into this vault. {action: "start"} returns the onboarding playbook: a method for surveying the codebase and recording its product knowledge (domains, features, stories, specs, workflows, decisions, constraints) as concepts via upsert_concept, each anchored to the code with codeAreas. {action: "status", areaList} reports onboarded state, concept counts and, given your repo's source areas (Brainz can't read the repo), which areas are covered or uncovered. {action: "complete", summary, areaList} marks the vault onboarded and stores the summary; it is rejected while too many areas are uncovered. Until onboarding completes, search_concepts and get_context results include a one-line note saying so.
sync
Sync this vault to the current code
Re-index an onboarded vault after the code changes (drift). {action: "start"} returns the sync playbook: the vault's last_synced_at, a coverage map over the concepts' code_areas, and a method for re-indexing only what changed (you run git — Brainz can't read the repo — and pass back changedPaths + areaList): update stale concepts in place, add concepts or tasks for new work, and report coverage gaps. {action: "status", areaList} reports onboarded state, last sync time, staleness, concept counts and coverage. {action: "complete", summary, areaList} stamps last_synced_at and appends the summary to the product-onboarding-summary concept (a running sync log). After ~14 days without a sync, get_context and search results include a one-line note saying so.
list_tasks
List tasks
List the vault's work pile: `task`-type concepts with their lifecycle (open/taken/done), oldest first, including who has taken each one (takenBy). Filter by taskStatus or by the domain the tasks are part_of. Read-only; take_task is what claims a task.
take_task
Take a task off the pile
Claim a task and get its briefing in one call. Pass an `id` to claim a specific task, or omit it to claim the next open task (oldest open by createdAt then id). Atomically flips the task to "taken" and records takenBy/takenAt; errors if it's already taken or done. Returns the task and a get_context-style briefing for its part_of domain plus the concepts it realizes / is governed_by (with code_areas). complete_task marks it done.
complete_task
Complete a task
Mark a task done. Sets taskStatus=done + doneAt and appends `outcome` to the task body as an Outcome section. The result notes that upsert_concept can record what changed.
session_hook
Install the Brainz session hook
Return setup steps for adding a Brainz primer to a repository's agent configuration: the primer text plus the edits that install it, as a Claude Code SessionStart hook in .claude/settings.json or as a marked block in AGENTS.md / another rules file. Brainz can't write to the repo; the steps are for you to apply when your user wants that setup. Re-applying them replaces the previous primer rather than duplicating it.
dream
Dream (nightly consolidation)
Dreaming: a scheduled consolidation sweep over this vault. Light stages what changed since the last dream (near-duplicate concepts, finished task outcomes, hygiene counts); REM asks an LLM for proposals; deep applies the ones that pass threshold gates: merges duplicates (edges redirected, the other tombstoned), promotes outcome knowledge into concepts, adds missing links, and files a task for each contradiction. A sweep that would touch too much of the vault is rejected; every applied dream keeps preimages and can be reverted. {action: "status"} shows schedule + last dream; {action: "run"} dreams now; {action: "diary"} reads the Dream Diary; {action: "revert", id} undoes one dream; {action: "configure", enabled?, cadenceHours?} sets it up. Without an LLM only light runs.
create_task
Create a task
Turn a finding into first-class work: creates a `task`-type concept with taskStatus=open and the given relations — part_of a domain, `realizes` stories/features, `governed_by` specs — plus codeAreas pointing at where the work lands. Use when you discover work that isn't reflected in the codebase yet (a gap, a needed fix, a follow-up). The task then shows up in list_tasks / take_task and on the Kanban board.

One convention worth knowing: get_context responds with two text blocks — first the assembled markdown briefing (paste it straight into a subagent prompt), then a single-line JSON footer { included, truncated, approxTokens }. Every other tool responds with one JSON text block — except onboard {"action": "start"}, which returns the playbook as one markdown block.

Where to go next

  • Create a free vault and point an orchestrator at it — the fastest way to feel the get_context loop.
  • Or just tell your agent to set itself up: point it at https://brainz.brownmatter.ai/skill.md — one pasted prompt and it walks itself through signup, key configuration, claiming the workspace for you, and onboarding.
  • Onboard your product: point your orchestrator at the vault and have it call the onboard tool — it maps your codebase into domains, features, stories, specs, and workflows, each anchored to the code that implements it.
  • Tell your orchestrator (e.g. in CLAUDE.md) to call get_context before delegating, and upsert_concept when it learns something worth keeping.