Docs navigation
Reference

Exit codes

Every command reports its outcome through the process exit code, so a script or CI job can act on it without parsing output. Test zero against non-zero rather than for 1 specifically — 1 is the failure code for almost everything, but not for all of it.

CodeMeaning
0The command did what you asked, or there was nothing to do.
1The command did not do what you asked. The reason is printed on the terminal.
2, 127, or your command's own codeOnly from brainbase run, which reports your command's outcome rather than its own. See below.
130brainbase login, interrupted with Ctrl-C — 128 + SIGINT, the conventional shell code.
bash
brainbase agent push --yes || exit 1

if ! brainbase skill publish --name acme/thing --skill-version 1.2.0 --yes; then
  echo "publish failed" >&2
  exit 1
fi

brainbase run passes its command's code through

brainbase run <command> runs your command with the secrets from .brainbase/secrets.env loaded, so the code you get back is your command's, not the CLI's. If the command dies on a signal, brainbase run re-raises it so your shell sees the real cause.

CodeMeaning
2No command was given — a usage error, printed to stderr.
127The command was not found on PATH.
1The command could not be started for some other reason.
anything elseWhatever your command exited with, forwarded unchanged.

So under brainbase run, test for non-zero rather than for 1, and read 2 and 127 as the CLI's own failures rather than your command's.

"Nothing to do" still exits 0

A command that had no work to do succeeded. brainbase agent push with no local changes prints Nothing to push — local is in sync with the cloud. and exits 0; brainbase sync with nothing new to bring in does the same. These print an informational line, not an error.

Declining an interactive confirmation is the same: nothing happened because you said so, not because the command failed.

Removing something that is not there counts as nothing to do. brainbase template remove and brainbase skill remove print that they found no installation and exit 0, so running either twice does not fail the second time and a teardown script can remove unconditionally. This matches apt, npm and kubectl.

skill update prints the same sentence and exits 1
brainbase skill update <slug> on a skill that is not installed reports No skill named <slug> found. — the same wording as skill remove — but exits 1. The difference is the verb, not the message: removing an absent skill is the state you asked for, updating one is not, and the skill is still missing afterwards. Branch on the exit code rather than on the text.

A precondition the command cannot meet is a failure

"This folder is not linked to any agent", "no brainbase.agent.yaml here", "no skill named that is installed to update" — the command could not start, so it did not do what you asked and the code is 1. These print as warnings rather than errors, because nothing is broken and the fix is on your side, but a script should treat them as failures. The remove verbs are the exception, for the reason given above.

CommandPrecondition
agent push, agent unpackA brainbase.agent.yaml that exists and carries an id.
agent status, syncThe folder is linked to an agent.
agent createThe folder does not already belong to an agent.
orchestration push, orchestration status, orchestration add-agentThe folder is linked to an orchestration.
orchestration pullA link, or an orchestration id as an argument.
orchestration createA brainbase-orchestration.yaml, and no existing link.
skill updateA skill installed under that name. skill remove and template remove exit 0 here instead — see above.

Partial outcomes

Some commands do more than one thing and can partly succeed. A partial result is not a success, so these exit 1 — but the output names what did land as well as what did not, so a non-zero code does not mean nothing happened.

CommandPartial outcomeWhat you see
template publishThe template publishes, but a skill inside it does not reach the registry and stays inline.The skills that shipped inline are named, and the run closes on PUBLISHED (PARTIAL).
orchestration pullSome members materialise and others do not.How many of how many landed, the missing members by name, and a note that orchestration push will refuse until they are pulled.
agent createThe agent is created and the folder linked, but its local content does not upload.CREATED (NO CONTENT), with the retry command to run.

The work that succeeded is kept, not rolled back — which is why the message tells you which command to run next. It is not always the one you just ran: after a partial agent create the retry is brainbase agent push, because the agent already exists and creating it again would be refused.

team list reports a partial read at exit 0
brainbase team list reports the organizations it could read and marks the ones it could not with an error field in the --json payload, writing the reason to stderr. If your pipeline needs every organization to have loaded, check that field rather than the exit code.

With --json

--json changes the shape of the output, not the outcome reported. stdout stays either valid JSON or empty on failure, so piping it into a parser is safe either way, and --json never turns a failure into a success.

One command's two paths do not yet agree. agent status --json exits 1 when it cannot reach the control plane, where the human-readable path prints the error and exits 0. The --json path is the stricter of the two, so a script branching on it is already correct.

Branch on the exit code, not on the output. Where the reason lands is not uniform. Many commands put a plain message on stderr and leave stdout empty. Others exit non-zero and still print their normal payload, leaving a field in it to carry the answer — agent status --json on an unlinked folder, and whoami --json with no credential, both do this. Some answer with {"error": "…"} instead, and mcp check does either depending on whether it could run at all. Each command's own reference page documents its shape, so read the exit code first and the payload second.

bash
# Reliable for every command: test the exit code, then look at the output.
if ! out=$(brainbase agent list --json); then
  echo "agent list failed" >&2
  exit 1
fi
# `agent list --json` is a bare array, so count it directly.
echo "$out" | jq 'length'
One exception worth knowing
brainbase mcp check reports unreachable servers in its payload and still exits 0 — it tells you the state of your MCP servers rather than passing or failing. Read check_status and the per-server entries.
Non-interactive runs
In CI, set BRAINBASE_NON_INTERACTIVE=1 so prompts resolve instead of waiting for input — see Environment variables.