Connect your terminal
In this section
The fastest way to reach brainy from a terminal is not a config file — it is one plugin, and every brainy door hands it out. .claude-plugin/plugin.json, a .mcp.json pointer, and eleven skills (recall, remember, briefs, the Accords board, the working method) ship together, versioned with the engine itself, and are always current because the door that installs them is the door you are about to talk to.
The two-word install
Tell your terminal:
join brainy.soulcraft.comor, for a door you run yourself:
join https://<your-door>Either phrase is an instruction to fetch that door's own GET / (or GET /join) page and follow it. The page is agent-readable on purpose — markdown by default, a minimal HTML page for a browser — and names exactly two commands:
claude plugin marketplace add https://<your-door>/plugin/marketplace.json
claude plugin install brainy@brainyThen restart: claude --continue. That is the whole install, for any door, hosted or self-hosted — the page always names ITS OWN URL, never a fixed address, so the same two-word phrase works against any brainy instance.
The three paths
1. Hosted — brainy.soulcraft.com
Nothing to run. Add the marketplace and install as above (door defaults to https://brainy.soulcraft.com), then either:
Sign in. When the hosted door offers it, the first tool call opens your browser, you log in, and the harness stores the token — nothing copied, nothing typed. This is the MCP authorization flow the harness itself implements: the door answers an unauthenticated
POST /mcpwith a401naming its own/.well-known/oauth-protected-resourcedocument, the harness reads it, and the sign-in runs.A suite key. Set
BRAINY_API_KEYto a key your account issues. Only needed when the door does not offer sign-in.
2. Self-hosted — your own brainy host
Run brainy host --brains-dir <dir> --listen <host:port> --keys <file> --public-url <https://your-door>. That same process now serves the plugin too — GET /plugin/marketplace.json and GET /plugin/brainy-<version>.zip — with .mcp.json baked to point at ITSELF, so a plugin installed from your door always talks back to your door, never brainy.soulcraft.com.
Two ways a caller gets a credential at your door:
Offer sign-in. Start the host with
--auth-server <url>naming your authorization server. An unauthenticated/mcprequest then answers401with the same RFC 9728 discovery document the hosted door uses, and the tokens that server mints are thebk1tokens this host already verifies against your issuers file — nothing else changes. The served plugin's.mcp.jsonOMITS theAuthorizationheader entirely in this mode, so the harness's own sign-in flow runs instead of sending an unset environment variable literally.Issue keys yourself.
POST /v1/keyswith the service key mints a static key for a person, business or service principal. Hand it out, and each holder setsBRAINY_API_KEY. The served plugin's.mcp.jsoncarries the ordinaryAuthorization: Bearer ${BRAINY_API_KEY}header in this mode.
3. Package holders — offline install
Already have @soulcraft/brainy installed? No door needs to be running yet:
npx brainy plugin install --door <https://your-door>This copies the package's own bundled plugin to ~/.config/soulcraft/brainy-plugin/<version>/ (a stable path, never node_modules), bakes --door into its .mcp.json, and runs the harness's own claude plugin marketplace add / claude plugin install commands against it. It never writes or asks for a key — it prints the same guidance as above: set BRAINY_API_KEY, or sign in if the door offers it.
Local zero-config — when the store and the terminal are on the SAME machine and you own both ends: npx brainy plugin install --local <brains-dir> --door <url> --keys <file> (the same --keys file your brainy host was started with) mints a per-install key, writes it to ~/.config/soulcraft/brainy-plugin/key (mode 0600), and sets BRAINY_API_KEY in your harness settings (~/.claude/settings.json's env block) — nothing to type, nothing to copy. This is the one case this CLI ever writes a credential; every remote door still gets sign-in or an admin-issued key.
npx brainy plugin url [--door <url>] prints a door's served marketplace URL, for scripting.
Embedded in an application
There is no terminal door here unless the embedding application ALSO runs brainy host — the plugin is a terminal-facing artifact; an application that links @soulcraft/brainy directly uses the in-process API (docs/overview.md) and never needs it.
Environment variables
Variable | What it does |
|---|---|
| The door the plugin's |
| The bearer credential, read by |
| The |
What the plugin contains
The pointer.
.mcp.jsonnames one door, over Streamable HTTP — nothing else runs locally.The hooks, ported to plain Node (no
bunrequired — this package already requires Node ≥ 22) and audited one by one for what a plugin every brainy user installs may do. Five of the six are thin door calls — read the harness's own hook stdin, redact it at the client's fixed denylist,POSTit, answer per the door's shape — and every one fails the same way when the door cannot answer: one named line on stderr, never a blocked session.policy-check(PreToolUse) — callspolicy_checkat the door before a tool runs (seedocs/policy-door.md). Fails OPEN, loudly, when the door is unreachable — a default-shipped hook must never turn a network blip into a blocked session; only a realrefuse/askverdict blocks.session-start(SessionStart→POST /v1/session/start) — hands the door your session's identity and gets back markdown context for the session that is beginning, printed verbatim.session-capture(PostToolUse→POST /v1/session/capture) — hands the door the tool call you just made; when the answer carries adoorbellpointer (a board write that named parties who should hear about it now), relays the ring instruction as context.session-save(StopandPreCompact→POST /v1/session/save) — saves the session so far, on a stop or ahead of a compaction.session-wrap(SessionEnd→POST /v1/session/wrap) — wraps the session as it ends.
Every door answers
{ served: true, … }or{ served: false, reason }— a self-hosted door that has not composed sessions yet says so by name, never a silent no-op and never a stub. Every request is bounded at 262,144 bytes (256 KiB) — over it, the door refusesSessionPayloadTooLargeErrorrather than reading an unbounded body, sincesession-capturenow fires on every tool call.The skills —
memory-keeper(the recall → cite → remember loop) plus ten method skills (brief,counsel,design-craft,diagnose,home,oracle,panel,table-voice,verify,wrap) carrying a working method onto every machine that installs this plugin.
One client-side redaction pass, nothing semantic. Before any hook payload leaves the terminal, a FIXED denylist strips five machine-shaped secrets — this plugin's own key files under ~/.config/soulcraft/, an Authorization: Bearer … value, a SOULCRAFT_SERVICE_SECRET=… assignment, any *_API_KEY=… assignment, and a PEM-armored block — replacing each with a [REDACTED:<kind>] marker; nothing else is touched, because a pattern that guesses at "sensitive-looking" prose is a pattern that mangles ordinary conversation.
No secrets. The shipped archive's own build pins two things: its entry list matches an explicit allow-list (no file outside it ever ships), and no entry's text matches a bearer value, an sk--prefixed key, a minted brainy credential, or a JWT — the only Bearer the archive ever carries is the literal ${BRAINY_API_KEY} placeholder.
What an expired plan changes
A minted key can carry an optional entitlement claim — "suite" or "expired" — the bearer's plan, as its issuer wrote it. Most keys carry no claim at all, and nothing here applies to them: absence is today's law, unchanged, never read as expired.
When a key's plan reads "expired", every door that writes refuses by name (EntitlementExpiredError) — the five hooks' own session doors included, since a session door writes no entity but wants the same write posture as one that does. Reading never stops. find, get, counts and every other read door keep answering, export keeps answering, and session-start's own context read keeps composing — an expired plan narrows what a bearer may CHANGE, never what it may SEE. Renewing the plan is the only cure; nothing about the key itself changed, so no new key is needed once it is renewed.
The claim is per BRAIN, not per credential: a key minted for someone other than the brain's own owner (a grant) carries the OWNER's own plan, set by the issuer at mint time, never the guest's — a guest of a suite owner writes freely, and a guest of an expired owner is refused the same way the owner themselves would be.