Brainy Brainy
Docs Brainy

The brainy CLI

In this section

npx brainy execs one of two bundled Rust binaries, resolved from optional npm packages — the native server (brainy-serve: every engine door over HTTP, SSE, WebSockets, gRPC and MCP) and the embedding + rerank service (brawn, a separate project this CLI resolves and execs the same way it always has — see @soulcraft/brawn). Every one of these doors is optional: nothing about them is required to run @soulcraft/brainy, and a customer who installs neither package loses nothing except these doors — every other engine capability runs in-process.

command

what it does

optional package

npx brainy (bare)

The starter — serves ./brain on a free loopback port with every wire including MCP, and prints the client connect snippet. No configuration.

@soulcraft/brainy-serve-linux-x64-gnu

npx brainy serve [OPTIONS]

Bind the listeners yourself — full detail at brainy serve

@soulcraft/brainy-serve-linux-x64-gnu

npx brainy mcp [OPTIONS]

Speak MCP over stdio — full detail at MCP

@soulcraft/brainy-serve-linux-x64-gnu

npx brainy embed-service [OPTIONS]

Run the bundled embedding + rerank service on a box of your own

@soulcraft/brawn-linux-x64-gnu

npx brainy bundle --out <DIR>

Build an air-gapped install kit from every optional package this install pins

none — builds a kit covering whichever of the above ARE pinned

This page covers the CLI shims — install lines, resolution, refusals. The native server's own doors, tools and protocol are documented in full at brainy serve and MCP; nothing about them is restated here.

Models

Three models ship inside @soulcraft/brainy itself (~305 MB together, every platform, zero configuration): the embedder (all-MiniLM-L6-v2), the default rerank cross-encoder (ms-marco-MiniLM-L6-v2), and the late-interaction encoder (answerai-colbert-small-v1). One model is optional — the 12-layer cross-encoder, @soulcraft/brainy-model-ms-marco-minilm-l12-v2, packaged the same way as the two binaries above:

npm install @soulcraft/brainy-model-ms-marco-minilm-l12-v2BASH

See the rerank stage for what it's for and how it's loaded. Installing none of these three optional packages — this model, brainy-serve, brawn — costs you nothing except the doors and checkpoints they carry; every other engine capability runs in-process with what already shipped.

Air-gapped hosts: npx brainy bundle --out <dir> builds a local install kit carrying every optional package above this install pins — see npx brainy bundle below.

npx brainy — the starter, serve, mcp

npm install @soulcraft/brainy-serve-linux-x64-gnuBASH

Linux x64 (glibc) is the only platform packaged in this release; on any other platform, or with the package not installed, every one of these three commands refuses by name — the bare starter, serve, and mcp alike:

[brainy] REFUSED — the @soulcraft/brainy-serve-linux-x64-gnu optional package is not installed.
[brainy] THE CURE — npm install @soulcraft/brainy-serve-linux-x64-gnu

Once installed:

npx brainy                                    # the starter — zero configuration
npx brainy serve --listen 127.0.0.1:8300      # bind the listeners yourself
npx brainy mcp                                # speak MCP over stdioBASH

serve and mcp pass every flag straight through to the brainy-serve binary, unvalidated — this CLI carries no copy of its grammar (--listen, --brain, --keys, ...) and no defaults of its own. Run the resolved binary's own --help (or see brainy serve) for the exact options. $BRAINY_KEY — the principal mcp's stdio transport runs as, since stdio carries no header to put a credential on — is read from the environment, never an argument, and reaches the binary because this shim never touches the environment; it only execs.

The bare starter takes no arguments at all: brainy-serve with zero arguments is its own distinct, deliberate mode (open ./brain, pick a free port, mint a key on first run, print the connect snippet), not serve with defaults filled in. Want --help? npx brainy --help (or -h, or help) prints this CLI's own usage — the one keystroke that stays available.

npx brainy embed-service — the embedding + rerank service

Embedding on a CPU costs tens of milliseconds per row. A GPU does thousands of rows a second. npx brainy embed-service puts the engine's own embedder — served by brawn, the model runner (@soulcraft/brawn, a separate package since 12.0) — on a GPU (or CPU) box of your own, so every other box running @soulcraft/brainy can reach it over your private network — with zero configuration on the engines that use it.

Install

npm install @soulcraft/brawn-linux-x64-gnuBASH

That is the whole install for a CPU service. Linux x64 (glibc) is the only platform packaged today; running the command on any other platform refuses by name — there is no install line that would fix it yet.

The CUDA package ships on brawn's own cadence, separate from this engine's — see @soulcraft/brawn's own release notes for whether it has shipped yet. The CUDA package, @soulcraft/brawn-linux-x64-gnu-cuda, carries ONE BINARY PER COMPUTE CAPABILITY — bin/brawn-sm89 (Ada: L4, 4090 class) and bin/brawn-sm120 (Blackwell) — plus the two ONNX Runtime execution-provider shared objects the CUDA provider needs beside them (bin/libonnxruntime_providers_cuda.so, bin/libonnxruntime_providers_shared.so), and a CAPS.txt recording what each binary was actually compiled for. There is no single binary that serves both capabilities — no PTX is embedded in either build, so an sm_89 binary refuses an sm_120 host and vice versa.

npm install @soulcraft/brawn-linux-x64-gnu-cudaBASH

The package is not a dependency of @soulcraft/brainy — it is an optionalDependency, so npm install skips it on a platform that does not declare it, automatically.

Run

npx brainy embed-service --bind 127.0.0.1:8200BASH

--bind is required and has no default — a default is how something ends up listening on an interface nobody meant to expose. 0.0.0.0 and :: are refused, and so is any address outside the private ranges. For a GPU box of your own serving OTHER boxes on your network, bind its private LAN address:

npx brainy embed-service --bind 10.0.0.5:8200BASH

The chooser — how npx brainy embed-service picks a binary

The resolver reads this host's own CUDA compute capability with nvidia-smi --query-gpu=compute_cap --format=csv,noheader (probed in a separate subprocess — never by loading CUDA inside the CLI's own process, which has segfaulted on a cardless box in this fleet's own runtimes before), and follows one rule above everything else: once the CUDA package is installed, it either serves or refuses by name — it never silently falls back to the CPU package, even when the CPU package is also installed. A host that installed the CUDA package wants GPU service; silently handing it CPU service instead would hide exactly the failure an operator needs to fix.

this host

CUDA package installed?

what happens

no GPU

no

the CPU package serves — the steady state

no GPU

yes

refused by name — no NVIDIA driver found; the CPU package is named as the one that serves this host

a GPU, cap 8.9 or 12.0

yes, carries that cap's binary

that cap's binary serves, with the package's bin/ directory on LD_LIBRARY_PATH so the two provider libraries load

a GPU, any other cap

yes

refused by name — the host's own cap is named alongside the caps the installed package actually carries

a GPU

no

refused by name — a GPU is present but the CUDA package is not installed; the exact install line is named

Every refusal in the last three rows names what was checked and what the cure is, on stderr, before any GPU is touched:

[brainy] REFUSED — a GPU is present on this host (CUDA compute capability 8.9) but @soulcraft/brawn-linux-x64-gnu-cuda is not installed.
[brainy] THE CURE — npm install @soulcraft/brawn-linux-x64-gnu-cuda
[brainy] REFUSED — this host reports CUDA compute capability 7.5, which the installed @soulcraft/brawn-linux-x64-gnu-cuda package carries no binary for (it carries: sm89, sm120).
[brainy] There is no install line that fixes this in the current release.

Before brawn's CUDA package has shipped, a GPU host sees the "not installed" refusal above even though the install line it names is not yet resolvable — there is no CUDA package on the registry until brawn publishes one (see "Install" above). This is deliberate: a GPU host that goes unnoticed and quietly serves at CPU speed is a worse outcome than a refusal that says exactly what is missing and exactly what to install once it exists.

USAGE
  npx brainy embed-service --bind <ADDRESS:PORT> [OPTIONS]

OPTIONS
  --model <DIR>   Use a specific model assets directory instead of the
                  bundled one (passed through as the binary's own --assets).
  -h, --help      Usage text.

Every other flag the service binary itself accepts (--data-dir, --batch-max,
--queue-cap, --vram-budget-bytes, --nice) passes straight through — run the
resolved binary with its own --help for the exact grammar.

License

Running the service requires a Brainy license carrying the services add-on capability — a claim on the same offline key the engine already verifies (see License Artifacts). A license without it is refused here, by name, before any package is resolved or any GPU is touched:

[brainy] REFUSED — the "services" capability is not on this license.
[brainy]   your license does not carry the "services" capability.
[brainy]   your key: tier pro, fingerprint 9f2c1a7b3e4d5680
[brainy] THE CURE — get or upgrade a license that carries "services" at https://soulcraft.com/account

This is a separate, additive claim from your license's tier — tiers price the scale a brain runs at and never gate a capability; services is the one deliberate exception, gating this one optional door.

Zero-config discovery — nothing to configure on the engines that use it

Once the service is running, every @soulcraft/brainy engine on the same network finds it by convention, with no configuration:

  • Inside your own environment, point your DNS or hosts file at the conventional name brainy-embed, on the conventional port 8200 — e.g. 10.0.0.5 brainy-embed. An engine opening anywhere on that network resolves brainy-embed:8200, runs the identity handshake (GET /health) and an equivalence gate against a small sample, and starts routing bulk embedding work to it automatically. No answer is not an error — the store is served by the local CPU leg exactly as before, narrated once.

  • BRAINY_EMBED_ENDPOINT is the last escape hatch, never the first configuration step: set it to override discovery entirely — a bare host, a host:port, or a full http://host:port URL. Useful for a laptop pointing at a box, a staging endpoint, or any shape the conventional name can't express. It has one other recognized value, local (BRAINY_EMBED_ENDPOINT=local) — the explicit opt-out: discovery does not run at all, no name is resolved and no endpoint is dialed even if one answers on the network, and the store is embedded by the local leg on purpose. This is the one door back to local embedding for an operator who wants it despite a service being present.

  • BRAINY_EMBED_ENDPOINTS (plural) names an ORDERED, comma-separated list of endpoints for more than one GPU box — BRAINY_EMBED_ENDPOINT keeps working as its one-element case.

  • BRAINY_EMBED_TOKEN carries the bearer token an engine authenticates with. On first start, a service with no fleet secret configured mints its own token, writes it to its data directory (mode 0600), and prints it ONCE — copy it into BRAINY_EMBED_TOKEN on every box that should reach this service. An engine that finds the service but has no token REFUSES BY NAME rather than silently falling back to the CPU: on the first bulk embed call since — addMany()/import()'s bulk door, or the re-embed ceremony — it throws EmbedServiceNotAdmittedError, naming the endpoint, the status (401/403) and this variable, and nothing is embedded, locally or remotely, before it does. "I found a service but can't authenticate" and "there is no service here" are different facts, and only one of them is yours to fix with one environment variable — or, if local embedding is what you actually want, with BRAINY_EMBED_ENDPOINT=local above. (A single add() and the per-row deferred-embed drain stay on the query path — local by default regardless of this — so this refusal is a bulk-work fact, not one every write hits.)

An endpoint is never trusted on its name alone. Every engine that discovers one runs an identity handshake (comparing model id, width and weights digest) and an equivalence gate (embedding a small sample through both the local and the remote embedder and requiring near-identical vectors) before routing a single row to it — a service serving the wrong model, or one whose weights were corrupted, is refused by name and the store keeps being served locally.

What this door does not change

The query path — the vectors your searches compare against — stays local by default; only bulk embedding work (writes, the re-embed ceremony) routes to the service automatically. And running no brawn at all is a fully supported, permanent configuration: the engine's in-process CPU embedder is always there, on every platform, with or without this package installed.

npx brainy bundle — an air-gapped install kit

Every door above resolves an optional package by installing it with npm install — which needs The Source reachable. npx brainy bundle is for a host that will never be able to reach it: it builds a local install kit, once, from a machine that CAN reach The Source, for installing somewhere that cannot.

npx brainy bundle --out ./brainy-bundleBASH

This resolves the CURRENT install's own @soulcraft/brainy version and every optionalDependencies pin it carries (any of the three packages above that this install has pinned), fetches each one's EXACT tarball, and writes:

./brainy-bundle/packages/*.tgz    every tarball (the engine + each optional package)
./brainy-bundle/MANIFEST.sha256   every tarball's digest
./brainy-bundle/install.sh        the offline install
./brainy-bundle/README.md         sizes, versions, the air-gap steps

--dry-run prints the plan (what would be fetched, and from which registry) without touching the network or the filesystem.

A pin this install carries that The Source does not have at that EXACT version is a hard refusal, named by package — this never substitutes "latest" or a nearest match.

Copy ./brainy-bundle to the disconnected host and run its own install.sh there:

sha256sum -c MANIFEST.sha256   # verify before trusting
./install.shBASH

Scope, stated honestly: this bundles the engine and its optionalDependencies pins ONLY. @soulcraft/brainy's ordinary dependencies (third-party packages from the public npm registry) are not vendored by this bundle — install.sh still needs those resolvable from npm's local cache or a reachable registry. "Air-gapped" names what this removes: ever needing The Source reachable again, not needing any registry reachable for anything.