Skip to main content
sb is the official StefanBrain command line. It wraps the TypeScript SDK and is designed for humans or coding agents running work from a shell. It requires Node.js 20.9 or later.

Install and sign in

sb login signs you in through your browser with OAuth and PKCE. It receives the result on the loopback address 127.0.0.1, so the browser must run on the same machine. The stored credential uses the member’s plan usage and refreshes itself. The CLI stores the login in $XDG_CONFIG_HOME/stefanbrain/credentials.json, or in ~/.config/stefanbrain/credentials.json when XDG_CONFIG_HOME is unset. The path is the same on every operating system, and the file has mode 0600. sb logout revokes the stored login and removes it from the file. For containers, continuous integration, SSH servers, or another headless environment, set an API key instead:
The environment key takes precedence over a stored login and uses the prepaid API wallet. sb whoami prints the active credential, the account behind it, and why that credential won. The CLI has no credential flag because command-line arguments can be retained in shell history and process listings.

Run common workflows

sb jobs submit static_ad runs the create_images tool. Put its arguments in payload.json:
To edit an image, run sb tools invoke edit_image --input edit.json. Job identifiers from submit tools are UUIDs. The acceptance on stdout carries the job_id and chat, and stderr prints the exact sb jobs wait command to run next. JSON payloads come from --input file.json or --input - for standard input. The CLI does not accept an inline JSON payload in command-line arguments.

Command reference

  • The job verbs find a job through its chat. Pass the acceptance’s --chat, or the same --project and --session you submitted with.
  • sb tools invoke on an asynchronous submit tool prints the same tool_job acceptance as sb jobs submit.
  • --input on sb runs start reads message and output_config. Pass every other option as a flag.
  • --sync prints the finished run, or the 202 acceptance with next: sb runs events <run_id> on stderr. Both exit 0, so check .status.
  • --follow prints one compact JSON line per event, then the finished run as one more compact line. Since CLI 0.4.0, --timeout bounds it: past the deadline the run keeps going, and the command exits 4 with a Resume: command on stderr.
  • sb runs events prints one JSON line per event until the run ends. --once prints a single page. Pass its next_after value to --after to read the next page.
  • sb ask waits up to 600 seconds for a long turn. If the wait ends first, it exits 4 and prints a Resume: command on stderr. Since CLI 0.4.0, that command carries the turn’s --chat, even after --chat new. Before 0.4.0, add the same --project and --session you asked with.
  • sb files list prints a chat’s workspace files, each with its path, id, and download_url. sb files download fetches one of them by --chat and --path, by --chat and the file’s id, or by its download_url, and writes it to --out. Both need CLI 0.4.0 or later.
  • sb jobs artifacts downloads the files the job’s result names, from the listing of the job’s chat.
  • Since CLI 0.5.0, sb feedback send tells the StefanBrain team where the API got in your way and prints the receipt, with the report’s fb_ id. --input reads the whole report, with the REST field names, from a JSON file or from standard input with -, and flags override its fields. sb feedback list and sb feedback get print your reports with the team’s replies. See Agent feedback.

Set global flags

Without --timeout, these deadlines apply: Every Developer API request carries User-Agent: stefanbrain-cli/<version> and the x-stefanbrain-client-name and x-stefanbrain-client-version headers. When CLAUDECODE, CURSOR_AGENT, CODEX_CI, CODEX_SANDBOX, or AGENT is set, the CLI also sends x-stefanbrain-agent-env with the coding agent it detected.

Script the output contract

  • stdout contains result data only: the API JSON envelope, newline-delimited stream events, or a cli_* receipt for CLI-owned operations.
  • The receipts are cli_login, cli_logout, cli_whoami, cli_version, cli_init, cli_artifacts, and cli_file_download.
  • A tool error, a failed or cancelled job, and a busy chat on sb ask also print their envelope or receipt on stdout, even though the command exits with a nonzero code.
  • stderr contains progress, warnings, and next: command suggestions.
  • The CLI never prompts, opens a pager, prints a spinner, or adds ANSI styling to machine output.
Use --pretty only for human-readable rendering. JSON is the default.

Handle exit codes

An unknown family on sb jobs status, result, cancel, wait, or artifacts returns 400 unknown_job_family and exits 1. When sb runs start, sb jobs submit, sb tools invoke on a submit tool, or sb ask exits 4 after a 5xx, a network error, or --timeout, the server may already have accepted the work. Re-run it only with the same --idempotency-key. Without a key, check sb runs get, sb jobs status, or the chat first. Since CLI 0.4.0, stderr says which applies. Before 0.4.0, it called every re-run safe, so follow this rule even when it says so. When 4 follows a wait timeout, the work is still running: run the printed Resume: command. sb feedback send takes no key. If it fails after a 5xx, a network error, or --timeout, the report may already be filed, and stderr says to check sb feedback list before re-running it.

Make retries safe

Pass --idempotency-key on sb runs start, sb ask, sb jobs submit, and sb tools invoke for an asynchronous submit tool. The server then returns the original accepted work rather than creating a duplicate.
A key is 1–128 characters from A–Z, a–z, 0–9, _, ., :, or -. The CLI drops an empty key. Any other key outside that format returns 400 invalid_idempotency_key. Keys on sb runs start, sb ask, and every asynchronous submit tool except research_shortform last for the rest of the same UTC day. A reused key returns the original work even when the input changed, so use a new key for new work. research_shortform is not idempotent. Keep the same chat, project, session, and input when retrying. Do not pass a key to other tools. The server ignores it there, but the CLI still retries the request automatically, which can repeat a side effect such as send_email.

Work across parallel sessions

sb init writes .mcp.json in the current directory for Claude Code. It adds a stefanbrain server entry with the x-stefanbrain-project header pinned and keeps every other entry in the file. --print shows the result without writing it. --force replaces a different existing stefanbrain entry. The entry’s Authorization header is Bearer ${STEFANBRAIN_API_KEY}. Claude Code expands the variable when it connects, so the key never lands on disk. Export STEFANBRAIN_API_KEY before you start the agent; a stored sb login does not supply it. Session labels remain per-call arguments; there is no session header. Run sb --help for the full current command and flag contract. Run sb version to compare the installed CLI version with the server’s specification version.