Every command on this page targets a running agent installation, not the agent template. An installation is a workspace: one or more durable deep agents plus the durable workflows you ship alongside them. These verbs inspect and operate that running workspace — its agents, its workflows, the durable runs they produce, and the agent-local stores (database, storage, RAG, secrets, config, prompts) each agent reaches through the ambient
stackboneclient.By default the CLI resolves the target to the local-dev installation linked to the current project (served by a running
stackbone dev); pass--agent <installationId>on any verb to point at a different installation. The one exception isstackbone agents, which is how you discover the installation ids in the first place — it never takes--agent.
Conventions
These hold for every group below, so they are stated once here instead of on each verb.
- Target resolution. A verb with no
--agentruns against the local-dev installation linked to the current project, talking to it directly — sostackbone devmust be running. If it is not, the verb fails fast with thedev_not_runningerror (exit code3) telling you to start it. Pass--agent <installationId>to target a cloud installation instead, which does not needstackbone dev. With no project and no--agent, the verb cannot guess a target and likewise fails with exit code3(no project). See Configuration → exit codes. - JSON output. Every verb accepts
--json(orSTACKBONE_JSON=1) and then emits a single{ "schema_version": 1, ... }line on stdout. The per-verb payloads below show the inner fields. See Configuration → output contract. - Pagination. Every
list-style verb takes--limit <n>and--cursor <opaque>, and its JSON payload carriesitemsplusnextCursor/prevCursor(either may benull). Pass the previous page'snextCursorback as--cursorto walk forward. Some lists add domain-specific fields alongsideitems. - Destructive verbs need
--yes. Any verb that mutates or deletes (retry,cancel,discard,purge,push,remove,rollback,approve,reject) refuses to run without--yesand exits5(permission denied) until you pass it. See Configuration → global flags. - Secrets are never revealed. Neither
stackbone secretsnorstackbone openrouterever prints a plaintext secret or key — reading a raw value is a human-only action in Studio behind a re-auth challenge.
stackbone agents
Discover the agent installations in your organization. Use the ids and
slugs it lists as the --agent target for every other group. Read-only;
takes no --agent.
| Command | Purpose |
|---|---|
stackbone agents list |
List every agent installation in your organization (incl. local-dev). |
stackbone agents get <slug> |
Read one installation by its slug (id, version, status, tunnel). |
kind is cloud for a deployed installation or local for the local-dev
install that exists while stackbone dev is running for this project.
JSON payload
// agents list
{ "schema_version": 1, "items": [
{ "id": "inst_123", "agentSlug": "hello-world", "status": "running", "kind": "cloud" }
] }
// agents get <slug>
{ "schema_version": 1, "agent": {
"id": "inst_123", "agentSlug": "hello-world", "agentVersion": "1.2.0",
"status": "running", "kind": "cloud", "templateName": "Hello World",
"templateOwnerOrgSlug": "acme", "localTunnelUrl": null,
"createdAt": "2026-05-01T10:00:00Z", "updatedAt": "2026-06-01T10:00:00Z" } }Exit codes: 0 ok · 2 auth · 4 not found (unknown slug) ·
1 generic. Full table: Configuration → exit codes.
stackbone workflows
Inspect the durable workflows the targeted
installation's workspace exposes, and the input/output JSON Schema each one
declares. Both verbs are read-only; no --yes gate.
A workflow declares its IO by exporting sibling inputSchema / outputSchema
Zod objects next to the 'use workflow' function. workflows schema is how you
read a workflow's per-call contract. When a workflow declares neither, the schema
reads { input: null, output: null } and callers fall back to a raw JSON field.
| Command | Purpose |
|---|---|
stackbone workflows list |
List the workflows the workspace exposes. Each row shows the workflow name and its trigger; ◆ marks one that declares an input/output schema (◇ if it does not). |
stackbone workflows schema <name> |
Print one workflow's input/output JSON Schema. Falls back to a message when the workflow declares no schema. |
JSON payload
// workflows list — one entry per workflow, each with its trigger and hasSchema flag
{ "schema_version": 1, "items": [
{ "name": "onboarding", "trigger": "POST /api/workflows/onboarding/start", "hasSchema": true },
{ "name": "reconcile", "trigger": "POST /api/workflows/reconcile/start", "hasSchema": false }
] }
// workflows schema <name> — each half is null when undeclared
{ "schema_version": 1, "schema": {
"input": { "type": "object", "properties": { "orderId": { "type": "string" } } },
"output": { "type": "object", "properties": { "refunded": { "type": "boolean" } } } } }The trigger is the HTTP entry point that starts a fresh durable run of the
workflow (a POST /api/workflows/:name/start). The result is a durable run you
inspect with stackbone runs.
The stackbone dev runtime serves the workflow routes for a local install. A
cloud installation's workflow routes are the same model, served by the deployed
runtime.
Exit codes: 0 ok · 4 not found (unknown workflow) · 1 generic.
stackbone runs
Inspect and control the durable execution runs of the targeted installation. A run is one durable invocation — a workflow run started from a trigger, or an agent chat turn — executed on the durable engine so it can pause and resume across processes. See Workflows → durable runs.
| Command | Purpose |
|---|---|
stackbone runs list |
List recent runs. Filters: --status <running|done|failed|interrupted>, plus --limit/--cursor. |
stackbone runs get <id> |
Inspect a single run (status, trigger, timing). |
stackbone runs retry <id> |
Start a fresh durable run from a run's original input. Requires --yes. |
stackbone runs cancel <id> |
Cancel a running run (marks it interrupted). Requires --yes. |
A run's status is running, done, failed, or interrupted.
interrupted covers both a run you cancelled and a durable run that is
parked awaiting a human decision — a workflow that called
requestApproval() and is waiting on the approvals inbox.
retry does not resume a run in place; it starts a brand-new durable run from
the original input, which is why it is destructive.
JSON payload
// runs list — paginated
{ "schema_version": 1,
"items": [{ "id": "run_1", "status": "done", "trigger": "workflow", "createdAt": "2026-06-01T10:00:00Z" }],
"nextCursor": "eyJ...", "prevCursor": null }
// runs retry <id> — the freshly-started run
{ "schema_version": 1, "run": { "id": "run_2", "status": "running" } }A run's trigger tells you what produced it — e.g. workflow (a durable
workflow run) or chat (an agent chat turn).
Exit codes: 0 ok · 4 not found (unknown run) · 5 permission
(retry/cancel without --yes) · 1 generic (e.g. invalid --status).
stackbone hitl
Human-in-the-loop approvals for the targeted installation. This inbox is the
return path for a parked durable run: when a workflow step calls
requestApproval() (from @stackbone/sdk/workflow, see
Workflows → human-in-the-loop), the run pauses and
the pending approval surfaces here. Deciding it — approve or reject —
resumes the parked run with your decision. An approval's run field links back
to the run you can follow with stackbone runs get.
--reason <text> is recorded as the decision comment. (Editing an approval
payload is a Studio-only action.)
| Command | Purpose |
|---|---|
stackbone hitl list |
List approvals. Filters: --status <pending|approved|rejected|timed_out|cancelled>, --limit/--cursor. |
stackbone hitl get <id> |
Inspect one approval (topic, run, timeout, and its audit trail of past decisions). |
stackbone hitl approve <id> |
Approve a pending approval (--reason), resuming the parked run. Requires --yes. |
stackbone hitl reject <id> |
Reject a pending approval (--reason), resuming the parked run. Requires --yes. |
An approval that no one decides before its timeout elapses ends as
timed_out, and the workflow continues with the fallback decision the step
declared.
JSON payload
// hitl list — paginated
{
"schema_version": 1,
"items": [
{ "id": "appr_1", "status": "pending", "topic": "refund", "createdAt": "2026-06-01T10:00:00Z" },
],
"nextCursor": null,
"prevCursor": null,
}hitl get adds the run the approval belongs to and the parked run's
timeout.
Exit codes: 0 ok · 4 not found (unknown approval) · 5 permission
(approve/reject without --yes) · 1 generic.
stackbone logs
Live-tail the targeted installation's logs over a server-sent stream.
| Command | Purpose |
|---|---|
stackbone logs tail |
Stream log lines. Server-side filters: --run <id>, --level <info|warn|error…>, --q <text>, --trace-id <id>. Client-side: --since, --until, --limit, --follow. |
--level, --q and --trace-id are applied by the server. --since and
--until (a duration like 15m/2h or an ISO timestamp) and --limit
(default 100) are applied locally as lines arrive — this stream has no
server-side time range or pagination. Without --follow the tail stops
once --limit lines have printed; with --follow it streams until you hit
Ctrl-C.
When a durable run or one of its steps fails, the runtime logs it at error
with the real error message and stack, so
stackbone logs tail --level error surfaces every crash. Scope the tail to a
single run with --run <id> to read just that run's lifecycle — the same id
you see in stackbone runs list. Caller mistakes log at
warn: triggering a workflow with input that fails its declared schema is
logged as workflow_input_invalid, so a bad payload is visible in the stream
rather than silently dropped.
JSON payload — one envelope per line (not a paged list):
{ "schema_version": 1, "time": 1717236000000, "line": "agent booted", "level": "info" }Exit codes: 0 ok (including a clean Ctrl-C stop) · 3 no project ·
1 generic (e.g. invalid --limit/--since).
stackbone db
Database operations for the targeted installation. The migrate group
runs the same migration engine stackbone dev uses on boot, against
your local dev database; the read-only Explorer verbs (query,
schemas, table) talk to the targeted installation over the control
plane.
- The
migrateverbs read the connection string fromSTACKBONE_POSTGRES_URLwhen it is set. If it is not,migrate upandmigrate statusautomatically discover it from a runningstackbone devsession for this project, so you do not have to export the variable in a separate shell. With neither the variable set nor a livedevsession the command exits3(no project). They resolve the schema + migrations directory fromagent.yaml(database.schema, defaultsrc/schema.ts;database.migrations, default.stackbone/migrations). - The Explorer verbs accept
--agentlike the rest of this page.
| Command | Purpose |
|---|---|
stackbone db migrate up |
Apply every pending migration (advisory-locked, atomic per file). Supports --target <tag>. |
stackbone db migrate create <name> |
Generate a new SQL migration by diffing src/schema.ts against the journal. |
stackbone db migrate status |
Classify each migration as applied, pending or drifted (informational). |
stackbone db query [sql] |
Run one read-only SELECT against the installation. SQL from the positional, --file <path> or stdin. |
stackbone db schemas |
List the schemas and tables visible to the installation, with row estimates. |
stackbone db table <schema> <table> |
Browse rows of one table with cursor pagination (--limit, --cursor, --order asc|desc). |
The migration verbs' flags and JSON payloads are documented in full at Commands → Database operations. The Explorer verbs return:
// db query / db table
{
"schema_version": 1,
"columns": [{ "name": "id" }, { "name": "email" }],
"rows": [{ "id": 1, "email": "a@b.com" }],
"truncated": false,
"duration_ms": 12,
}The control plane enforces "a single SELECT" on db query; anything else
is rejected server-side. Results are capped (truncated at 1000 rows for
query; cursor-paged for table).
Exit codes: 0 ok · 3 no project (missing agent.yaml, or no
database connection — STACKBONE_POSTGRES_URL unset and no running
stackbone dev session to discover it from) · 1 generic (migration
failure, invalid migration name, bad identifier, non-SELECT SQL).
stackbone storage
Operate the S3-style object store bound to the targeted installation.
--bucket <name> is required on every object verb (an install can expose
more than one bucket).
| Command | Purpose |
|---|---|
stackbone storage buckets |
List the buckets the installation exposes. |
stackbone storage list |
List objects in --bucket, optionally under --prefix. Supports --limit/--cursor. |
stackbone storage get <key> |
Download an object to stdout (or --out <path>) via a short-lived presigned URL. |
stackbone storage put <key> |
Upload a local --file <path> under the key. |
stackbone storage presign <key> |
Print a short-lived presigned download URL for the object. |
stackbone storage remove <key> |
Delete an object. Requires --yes. |
JSON payload
// storage list — paginated, plus folder prefixes
{ "schema_version": 1,
"items": [{ "key": "uploads/foo.txt", "size": 1024, "last_modified": "2026-06-01T10:00:00Z" }],
"common_prefixes": ["uploads/"], "nextCursor": null, "prevCursor": null }
// storage presign <key>
{ "schema_version": 1, "url": "https://…", "expires_at": "2026-06-01T10:05:00Z" }The reserved rag/ key prefix is managed by stackbone rag — the backend
rejects put/remove under it.
Exit codes: 0 ok · 4 not found (unknown bucket/key) · 5 permission
(remove without --yes) · 1 generic (missing --bucket/--file).
stackbone rag
Operate the managed retrieval index bound to the targeted installation.
The document, query and job verbs require --collection <name>.
| Command | Purpose |
|---|---|
stackbone rag collections list |
List collections with per-collection document and chunk counts. |
stackbone rag collections create <name> |
Create an empty collection. |
stackbone rag collections remove <name> |
Delete a collection and every document under it. Requires --yes. |
stackbone rag list |
List documents in --collection. Supports --limit/--cursor. |
stackbone rag get <docId> |
Download a document original to stdout (or --out <path>). |
stackbone rag ingest <path> |
Upload a local .txt/.md/.pdf (≤ 25 MiB) into --collection, staging an async job. |
stackbone rag query <text> |
Run a similarity query over --collection. Supports --topk, --model. |
stackbone rag remove <docId> |
Delete a document (cascades to its chunks). Requires --yes. |
stackbone rag jobs |
List async ingest jobs, optionally filtered by --collection. |
stackbone rag retry <jobId> |
Re-enqueue a failed ingest job. Requires --yes. |
stackbone rag cancel <jobId> |
Cancel a non-terminal ingest job. Requires --yes. |
JSON payload
// rag ingest
{ "schema_version": 1, "job_id": "job_1", "status": "queued" }
// rag query
{ "schema_version": 1,
"items": [{ "id": "doc_1", "chunk_idx": 0, "score": 0.83, "content": "…" }],
"dimensions": 1536, "embedded_with": "text-embedding-3-small" }rag query <text> embeds the query text server-side with your
organization key and runs the similarity search against --collection,
returning the ranked chunks. The response reports the vector dimensions and
the model it embedded with (embedded_with).
Exit codes: 0 ok · 4 not found (unknown collection/doc/job) ·
5 permission (destructive verb without --yes) · 1 generic (missing
--collection, unsupported file type).
stackbone secrets
Manage environment-scoped secrets bound to the targeted installation.
There is deliberately no reveal verb — the CLI never prints a plaintext
value. set is idempotent on the name (create and rotate are the same call).
| Command | Purpose |
|---|---|
stackbone secrets list |
List secret names (values always masked) and their last-rotated time. |
stackbone secrets set <name> |
Create or rotate a secret. Value from --value <v> or stdin; --description. |
stackbone secrets remove <name> |
Delete a secret. Requires --yes. |
JSON payload
// secrets list — value_preview is a mask, never the plaintext
{
"schema_version": 1,
"items": [
{
"name": "OPENAI_API_KEY",
"value_preview": "••••",
"last_rotated_at": "2026-06-01T10:00:00Z",
},
],
}Exit codes: 0 ok · 4 not found (unknown secret) · 5 permission
(remove without --yes) · 1 generic (empty value).
stackbone config
Manage the agent's AGENT_CONFIG document on the targeted installation.
The control plane models config as one versioned JSON document, not a
bag of keys: every write appends a new version, the highest is active, and
a rollback copies a prior version forward.
| Command | Purpose |
|---|---|
stackbone config get |
Print the active config document (value, version, author). |
stackbone config set |
Persist a new version. Reads a JSON object from --file <path> or stdin. |
stackbone config versions |
List recent versions (newest first, up to 100). |
stackbone config rollback --version <n> |
Roll the active config back to a prior version. Requires --yes. |
JSON payload
// config get
{ "schema_version": 1, "version": 4, "value": { "feature": { "newFlow": true } },
"updatedAt": "2026-06-01T10:00:00Z", "updatedBy": "a@b.com" }
// config set
{ "schema_version": 1, "unchanged": false, "config": { "version": 5 } }The config value must be a JSON object (never a primitive or array) — anything else fails before the network call.
Exit codes: 0 ok · 4 not found (unknown version) · 5 permission
(rollback without --yes) · 1 generic (input not a JSON object).
stackbone prompts
Manage the versioned, named-by-key prompt catalog on the targeted
installation. Each key holds an append-only chain of versions: the highest
is the live head, writes never edit history (update appends a version when
content changes; rollback copies an older version forward to a new head).
| Command | Purpose |
|---|---|
stackbone prompts list |
List every prompt at its current version. |
stackbone prompts get <key> |
Print a prompt (current version, or a pinned --version <n>). |
stackbone prompts create <key> |
Register a prompt at version 1. Content via --template, --file or stdin; --name required. |
stackbone prompts update <key> |
Append a version and/or patch the head (--template/--file, --name, --description, --metadata). |
stackbone prompts remove <key> |
Soft-delete a prompt. Requires --yes. |
stackbone prompts versions <key> |
List a prompt's version history (newest first, up to 200). |
stackbone prompts rollback <key> --version <n> |
Promote a prior version to the live head. Requires --yes. |
stackbone prompts preview <key> |
Server-side compile the prompt against a --vars <file.json>; reports a missing {{var}} cleanly. |
JSON payload
// prompts list
{ "schema_version": 1, "items": [{ "key": "welcome_email", "currentVersion": 3, "name": "Welcome email" }] }
// prompts preview — ok:false is a clean 200 (a missing variable), not an error
{ "schema_version": 1, "ok": true, "version": 3, "output": "Hi Ada" }--template and --file are mutually exclusive. On update, at least one
field is required.
Exit codes: 0 ok · 4 not found (unknown key/version) · 5 permission
(remove/rollback without --yes) · 1 generic (missing --name/content,
bad --metadata JSON).
stackbone contract
Inspect the Stackbone Agent Protocol contract the targeted installation advertises, and validate the local project against it. All verbs are read-only.
| Command | Purpose |
|---|---|
stackbone contract show |
Print the full contract (version, build, runtime URL, capabilities). |
stackbone contract capabilities |
List the capabilities the installation reports (e.g. queues.jobs, storage.s3). |
stackbone contract validate |
Validate the local agent.yaml against the target's contract (or the local emulator contract when no installation is linked). Run before a publish. |
capabilities is derived from the same handshake show reads — there is no
separate endpoint. validate fails (exit 1) when the contract version is
unsupported or a declared capability is not advertised; the publish it precedes
ships a workspace bundle (the workspace's agents and workflows).
For a per-call input/output contract, workflows declare their own schema — use
stackbone workflows schema <name>.
JSON payload
// contract validate
{
"schema_version": 1,
"ok": true,
"violations": [],
"deviations": [],
"contractVersion": 1,
"source": "install",
}Exit codes: 0 ok · 3 no project (validate with no agent.yaml) ·
1 generic (validation failed, contract incompatible).
stackbone openrouter
Inspect the OpenRouter wiring of the targeted installation. Both verbs are read-only and the secret key value is never returned.
| Command | Purpose |
|---|---|
stackbone openrouter get |
Read the install's key info: mode (managed sub-key vs your own env key), public id, monthly spend cap, status. |
stackbone openrouter models |
List the OpenRouter model catalogue with per-million-token input/output pricing. |
JSON payload
// openrouter get — no bearer value, ever
{
"schema_version": 1,
"key": {
"configured": true,
"mode": "managed",
"base_url": "https://openrouter.ai/api/v1",
"public_id": "or-pub-…",
"status": "active",
"spend_limit_usd": 50,
},
}Exit codes: 0 ok · 2 auth · 1 generic.