REF · STACKBONE / WIKI · v0.9.4 stackbone

Configuration reference

Global flags, environment variables, on-disk state and the JSON output contract.

Global flags, environment variables, persistent state on disk, the --json envelope and the semantic exit codes. Everything you need to drive the CLI from a script — or from a coding agent inside an IDE — without parsing prose.

Canonical ADR: 2026-04-28-patrones-cli-token-efficient.

Global flags

Every command accepts these. Their effective values are read from process.argv before subcommand parsing, so they propagate transparently.

Flag Env equivalent Default Description
--json STACKBONE_JSON=1 off Emit machine-readable JSON wrapped in { "schema_version": 1, ... }. Errors get error + exit_code keys.
--api-url <url> STACKBONE_API_URL global config Override the control plane URL. Falls back to the project config and then to the global config.
-y, --yes (none) off Skip every confirmation prompt. Required in CI / non-TTY contexts.
--no-auto-login STACKBONE_AUTO_LOGIN=0 off When a protected command finds no valid session, fail fast with exit code 2 instead of triggering the device-code flow inline.

Environment variables

The CLI reads these from the parent shell:

Variable Effect
STACKBONE_JSON =1 ⇒ same as --json.
STACKBONE_API_URL Override the control plane URL (same as --api-url).
STACKBONE_AUTO_LOGIN =0 ⇒ same as --no-auto-login.
STACKBONE_LOG_LEVEL Pino logger level (debug, info, warn, error). Defaults to info.
STACKBONE_CLOUDFLARED_BIN Absolute path to a cloudflared binary. Used by stackbone dev.
STACKBONE_CORS_ALLOW_ORIGINS CSV of origins added to the stackbone dev Studio CORS allowlist.

The CLI also injects env vars into the agent process when running stackbone dev. See SDK integration → env table.

State on disk

Per-machine (global)

Lives under ~/.stackbone/:

Path What it stores Permissions
~/.stackbone/credentials.json Map keyed by control-plane URL → SessionInfo. Lets one user stay logged into local + staging + prod simultaneously; only one is active at a time. 0600 (owner read/write).
~/.stackbone/config.json Global preferences — defaultApiUrl, telemetry (opt-in PostHog, default false until V1). 0644.

Per-machine (cache)

Path What it stores
~/.cache/stackbone/bin/ Auto-downloaded binaries (today: cloudflared).

Per-project

Lives at the project root:

Path Tracked? What it stores
.stackbone/project.json No (gitignored by stackbone init) { schemaVersion, workspaceId, agentId, controlPlaneUrl }. Identifies which agent in which workspace this directory points at.
stackbone.config.json Yes { studio: { corsOrigins } } and other team-shared knobs. Reviewable in PRs.
agent.yaml Yes Manifest. See agent.yaml reference — TODO.
.claude/skills/stackbone/SKILL.md Yes Auto-generated skill bundle for Claude Code / coding agents. See Claude skill.

Output contract

Human mode (default)

Free-form text on stdout. May span multiple lines, may include @clack/prompts chrome and ANSI colour codes. Never parse this. Logging (debug, trace, deprecation warnings) goes to stderr through Pino regardless of mode.

JSON mode

Triggered by --json or STACKBONE_JSON=1. Every command emits a single JSON line on stdout wrapped in:

// success
{ "schema_version": 1, ...payload }

Errors go on stderr and include the original exit code:

{
  "schema_version": 1,
  "error": {
    "code": "auth",
    "message": "No active session for https://api.stackbone.dev",
    "suggestion": "Run `stackbone login`",
  },
  "exit_code": 2,
}

schema_version is an integer that only bumps on backward-incompatible shape changes. If a coding agent sees a value greater than the one it was written against, it should refuse to parse and surface the version mismatch.

See apps/cli/src/core/output.ts for the implementation.

Exit codes

Code Name When
0 ok Command succeeded.
1 generic Catch-all error. Anything that isn't auth / project / not-found / permission.
2 auth Not logged in, session expired, or --no-auto-login refused login.
3 no project The cwd has no .stackbone/project.json and the command needs one.
4 not found Workspace, agent or deployment does not exist.
5 permission denied Caller is authenticated but unauthorised for the resource.

These map 1:1 from error.code in the JSON envelope, so a coding agent can branch on either without parsing the message:

# In a shell script
if ! out=$(stackbone whoami --json 2>err); then
  case "$(jq -r '.error.code' < err)" in
    auth)       stackbone login ;;
    not_found)  echo "stale session" ;;
    *)          echo "unexpected: $out" ; exit 1 ;;
  esac
fi

The full constants live in apps/cli/src/core/errors.ts.

Multi-environment workflows

The credentials.json schema is keyed by control-plane URL, so a single machine can be logged into multiple environments:

# Default (production)
stackbone login

# Staging
STACKBONE_API_URL=https://staging.stackbone.dev stackbone login

# Switch back without re-logging in
STACKBONE_API_URL=https://staging.stackbone.dev stackbone whoami

The "active" environment is whichever URL is selected via --api-url / STACKBONE_API_URL — falling back to the project's controlPlaneUrl and then to the global default (https://api.stackbone.dev). Run stackbone whoami to confirm which one the CLI is talking to.

Putting it together

A coding-agent-friendly invocation looks like:

STACKBONE_JSON=1 stackbone metadata

…and produces a single line that fully describes the workspace state. That's the pattern this whole CLI is optimised for.