Every command shipped today, grouped by purpose. Each entry documents the synopsis, flags, the human-mode output, the --json shape and the exit codes that may be raised.

The canonical reference is stackbone docs cli (no network, no fetch). When this page and the binary disagree, the binary wins.

Conventions

What a Stackbone project is

A project is a workspace: one or more agents and a set of durable workflows, discovered by convention from the files on disk. You do not maintain a registry, the workspace is read straight from two folders:

  • Agents: every folder under deep-agents/ that contains an index.ts entry file. The folder name is both the agent's identity and the model a client selects to talk to it.
  • Workflows: every workflows/<name>.workflow.ts. The workflow name is the file basename without the .workflow.ts suffix, and the file exports a <camelCase(name)>Workflow function (e.g. qualify-lead.workflow.ts exports qualifyLeadWorkflow).

stackbone dev and stackbone publish both read this same convention. An optional stackbone.config.ts (default-exporting defineWorkspace({ workflows })) is an override for workflows only: when it exists it wins over the convention scan for workflows; agents are always discovered from deep-agents/. Most projects need no stackbone.config.ts at all.

If you are new to these concepts, read Agents, Workflows and Stackbone Connect first, this page only documents the commands.

Authentication

stackbone login

Authenticate the CLI via the device-code flow (RFC 8628). Stores the session in ~/.stackbone/credentials.json (chmod 600).

Flag Type Description
--no-browser boolean Print the verification URL + code instead of opening the browser. Auto-detected when CI, SSH_CLIENT, or SSH_TTY is set.

JSON payload

{
  "schema_version": 1,
  "user": { "id": "...", "email": "..." },
  "control_plane_url": "https://api.stackbone.ai",
  "expires_at": "2026-...",
}

Exit codes: 0 ok, 2 auth, 1 generic.

stackbone logout

Revoke the active session and drop it from disk. No flags.

JSON payload

{
  "schema_version": 1,
  "control_plane_url": "https://api.stackbone.ai",
  "previous_user": { "id": "...", "email": "..." } /* or null */,
}

Inspection

stackbone whoami

Show the active user and organization.

JSON payload

{
  "schema_version": 1,
  "user": { "id": "...", "email": "..." },
  "organization": { "id": "...", "slug": "...", "name": "..." },
  "control_plane_url": "https://api.stackbone.ai",
}

Exit codes: 0 ok, 2 auth.

stackbone current

Print the slug of the organization currently linked to this session. Newline-delimited <slug>\t<name> in human mode.

stackbone list

List the organizations you belong to. Tab-separated table in human mode (SLUG\tNAME\tID).

stackbone organization use [slug]

Choose which organization the CLI acts as. When you belong to more than one organization, this sets the active organization for the current control plane, the one stackbone init, stackbone link and stackbone dev use when they create or resolve a workspace. The choice is stored per environment in ~/.stackbone/credentials.json, so logging into a different control plane keeps its own selection.

stackbone publish is not affected by this setting: it always publishes to the organization recorded in that project's .stackbone/project.json. So the way to publish into a specific organization is to switch first, then create the project there:

stackbone organization use            # interactive picker (TTY)
stackbone organization use acme       # switch straight to a slug

# Publish into a chosen org:
stackbone organization use acme        # 1. make "acme" active
stackbone init my-app --with agent     # 2. the new workspace is registered in "acme"
stackbone publish                      # 3. publishes to "acme" (from project.json)
  • With a slug argument it switches directly (works in CI and --json).
  • With no argument and a TTY it shows a picker of the organizations you belong to, marking the current one. If you belong to only one, it just confirms that one.
  • In non-interactive mode (no TTY, --json, or -y) with several organizations and no slug, it exits asking you to pass the slug.

JSON payload

{
  "schema_version": 1,
  "organization": { "id": "...", "slug": "...", "name": "..." },
}

Exit codes: 0 ok, 2 auth (not logged in), 4 not found (a slug you don't belong to, or no organization at all), 1 generic (several organizations and no slug in non-interactive mode).

stackbone metadata

One-shot agent-friendly overview. Replaces whoami + current + list for callers that want a single payload to plan from. Today it returns organization, user and an empty agents / publications / channels array, the shape is stable across releases so coding agents can rely on it.

{
  "schema_version": 1,
  "cli_version": "0.1.0-alpha.7",
  "control_plane_url": "https://api.stackbone.ai",
  "user": { "id": "...", "email": "..." } /* or null */,
  "organization": { "id": "...", "slug": "...", "name": "..." } /* or null */,
  "agents": [],
  "publications": [],
  "channels": [],
  "runtime": {
    "local": { "running": false },
    "remote": null,
  },
}

stackbone connectors

List the available connectors (the curated catalog, every connector with its auth kind and the ids of the actions and triggers it exposes) and the connections that exist for the current organization, nested under the connector they target.

This is the discovery step before you call a connector from your code. Copy a connection's id or unique name and reach it through the ambient client's stackbone.connection(id) accessor (or callConnector(...) from @stackbone/sdk/connect) inside an agent tool or a workflow 'use step':

// inside a tool or a workflow step
import { stackbone } from '@stackbone/sdk';

const result = await stackbone.connection('support-telegram').sendMessage({
  chatId: input.chatId,
  text: 'On it.',
});

These calls go through the Stackbone Connect broker, which holds the credentials in the customer's own cloud, your code never sees a token. Always reach a connection through stackbone.connection(id).

Read-only and authenticated. Listing connections needs the owner/admin connections:manage capability; without it the command still prints the catalog and adds a connections_unavailable note instead of failing, so the catalog stays useful.

stackbone connectors          # human table: connectors + nested connections
stackbone connectors --json   # machine-readable catalog + connections

JSON payload

{
  "schema_version": 1,
  "connectors": [
    {
      "id": "telegram",
      "displayName": "Telegram",
      "authKind": "api_key" /* or "oauth2" */,
      "actions": ["send-message", "send-photo"],
      "triggers": ["message-received"],
      "connections": [{ "id": "conn_...", "name": "Support bot", "healthStatus": "active" }],
    },
  ],
  "connections_unavailable": "..." /* only present when you lack connections:manage */,
}

healthStatus is one of active | expiring | error | revoked. The connection id is printed in full (human and --json mode) so it can be copied straight into a stackbone.connection(id) call.

Exit codes: 0 ok (including the no-connections:manage case), 2 auth (not logged in), 1 generic.

Project lifecycle

stackbone init [dir] [--with empty|agent|workflow|workflow-agent]

Scaffold a new workspace. init is workspace-first and links the workspace to your organization: it registers the workspace's identity in the control plane and writes a .stackbone/project.json (so dev, publish and the management commands know which org to talk to). You must be signed in (stackbone login) first, there is no offline init. Alongside the link it writes the workspace shell.

The shell is a multi-piece project:

  • a deep-agents/ folder (one agent per subfolder);
  • a workflows/ folder (one durable workflow per file);
  • package.json, tsconfig.json;
  • an .npmrc (a hoisted node_modules layout so the runtime resolves one copy of each shared dependency);
  • a .gitignore, a README;
  • the Stackbone agent skills for every coding agent it can detect, installed best-effort.

--with chooses an optional first piece scaffolded on top of the shell:

--with value What it adds
empty The shell only.
agent One agent under deep-agents/<name>/.
workflow One durable workflow at workflows/<name>.workflow.ts.
workflow-agent An agent and a workflow already wired to call it.

Every kind links the workspace, so all of them need you to be signed in, there is no offline init. The --with value only changes which first piece (if any) is scaffolded on top of the shell.

Flag Type Default Description
[dir] positional string . Target subdirectory for the workspace. Omit to scaffold into the current dir.
--with string empty First piece to scaffold: empty, agent, workflow, or workflow-agent.
--name string derived Workspace name (and the default name of the first piece).
--yes / -y boolean false Skip interactive prompts.
--json boolean false Emit the structured JSON envelope instead of the pretty UI.
--force boolean false Overwrite existing files in the target directory.

Starters are gone from init. Passing --starter or --template now prints a migration message and exits non-zero. Templates moved to a per-piece flag on add (stackbone add workflow <name> --template <t>).

Interactive prompts: when stdin is a TTY and neither -y nor --json are set and you did not pass --with, init shows a picker of the --with kinds (empty, agent, workflow, workflow-agent) and prompts for the missing name.

JSON payload

{
  "schema_version": 1,
  "workspace": { "name": "acme", "dir": "/abs/path" },
  "with": "agent", // the --with value
  "files_written": [
    /* every file written, sorted alphabetically */
  ],
  "agent": { "id": "...", "slug": "...", "name": "..." }, // the workspace's own control-plane identity
  "local_dev_installation": { "id": "...", "organization_slug": "..." },
  "skills_install": {
    "ok": true,
    "steps": {
      "stackboneRegistry": "ok",
      "findSkills": "ok",
      "gitignore": "ok",
    },
  },
}

agent and local_dev_installation describe the workspace's own control-plane registration (the identity every --with kind shares), not a per-piece record.

Exit codes: 0 ok, 2 auth (not signed in), 1 generic (a file collision without --force, an unknown --with value, or a removed --starter / --template flag).

stackbone add agent|workflow|workflow-agent <name>

Add one new piece to an existing workspace. add only writes new files, it never edits your existing TypeScript and never edits stackbone.config.ts. A name collision fails with a clear error; re-run with --force to overwrite. You must run add inside a workspace. Every kind is fully offline: a piece you add is a member of the workspace init already linked, not a separate control-plane registration, so no login is required.

stackbone add agent support
stackbone add workflow nightly-digest
stackbone add workflow qualify-lead --calls lead-qualifier
stackbone add workflow-agent lead-qualifier

stackbone add agent <name> (alias of add deep-agent) scaffolds one agent under deep-agents/<name>/index.ts. Agents carry no per-piece manifest: their runtime dependencies (the agent-authoring library and its model provider packages) merge into the workspace root package.json, adding only the ones not already pinned there.

Flag Type Description
--yes boolean Skip interactive prompts.
--json boolean Emit the structured JSON envelope.
--force boolean Overwrite files on a name collision.
{
  "schema_version": 1,
  "kind": "deep-agent",
  "name": "support",
  "target_dir": "/abs/path", // the workspace root
  "files_written": [
    /* the new files, RELATIVE to the workspace root, sorted (e.g. "deep-agents/support/index.ts") */
  ],
  "registered_in_config": false,
  "deps_added": [
    /* runtime deps newly merged into the workspace root package.json, if any */
  ],
  "control_plane_agent": null,
}

stackbone add workflow <name> adds one durable workflow file at workflows/<name>.workflow.ts. It never touches the control plane (durable workflows are dev-only today). --calls <agent> wires a step inside the workflow that delegates a turn to that agent (the workflow → agent hybrid).

Flag Type Description
--template string Template to scaffold the workflow from.
--calls string Agent name to delegate a turn to from the workflow.
--yes boolean Skip interactive prompts.
--json boolean Emit the structured JSON envelope.
--force boolean Overwrite files on a name collision.
{
  "schema_version": 1,
  "kind": "workflow",
  "name": "nightly-digest",
  "target_dir": "/abs/path", // the workspace root
  "files_written": ["workflows/nightly-digest.workflow.ts"],
  "registered_in_config": false,
  "control_plane_agent": null,
}

stackbone add workflow-agent <name> is the composed template: it scaffolds an agent and a workflow already wired to call it (the qualify-leadlead-qualifier pattern). It merges the same runtime deps as add agent, and the JSON kind is "workflow-agent".

Exit codes (all three): 0 ok, 3 no project (add run outside a workspace), 1 generic (a name collision without --force, or an unknown --template).

Link the current directory to an existing organization + agent. Writes .stackbone/project.json, patches .gitignore and re-runs the Stackbone agent skills install (same best-effort step init performs). Does not scaffold starter files, use init for that.

Flag Type Description
--agent string Agent slug to link to. Required in non-interactive mode (CI, --json, -y).
--force boolean Overwrite an existing .stackbone/project.json.

JSON payload

{
  "schema_version": 1,
  "agent": { "id": "...", "slug": "...", "name": "..." },
  "organization_id": "...",
  "local_dev_installation": { "id": "...", "organization_slug": "..." },
  "target_dir": "/abs/path",
  "files_written": [".stackbone/project.json", ".gitignore"],
  "skills_install": {
    "ok": true,
    "steps": {
      "stackboneRegistry": "ok",
      "findSkills": "ok",
      "gitignore": "ok",
    },
  },
}

Local development

stackbone dev

Boot the full local runtime for the project and open a secure tunnel through Stackbone's frpc relay (*.tun.stackbone.ai) so cloud-hosted Studio can reach it. The emulator API listens on http://127.0.0.1:4242 by default. The tunnel is mandatory, it is what makes the local_tunnel_url field on the installation row meaningful and yields the Studio deeplink.

The project is a workspace: every deep-agents/<name>/index.ts, plus every workflows/<name>.workflow.ts, discovered by convention (with an explicit stackbone.config.ts override for workflows). Boot:

  • compiles every agent and every durable workflow on your machine, in-process (no ports, no child processes);
  • stands up Postgres + Redis + MinIO (Postgres holds your data, Redis is the durable backend the workflow runtime replays from, MinIO is S3-compatible storage);
  • applies the platform migrations and your own migrations under .stackbone/migrations;
  • seeds the system secrets the runtime injects (including your organization's OpenRouter key);
  • generates the editor type files under .stackbone/ (agents.d.ts, connect.d.ts, config.d.ts) so your IDE knows the agent, connection and config shapes;
  • serves the chat endpoints (POST /openai/v1/chat/completions, POST /anthropic/v1/messages) and the durable workflow routes (POST /api/workflows/:name/start, /chat).

Full reference: Local development.

Flag Type Default Description
--port string 4242 Emulator API port. Coerced to an integer in the range 1–65535; invalid values exit with error.code = "generic".
--listen boolean false Bind the HTTP server to 0.0.0.0 (LAN-reachable). Default binds to 127.0.0.1 only.
--print-contract boolean false Print the JSON contract this CLI advertises (same payload as the emulator's /api/contract) and exit without booting.
--verbose boolean false Global flag (available on every command). Streams every log line and container output; the default UI uses per-stage spinners, --verbose is the raw firehose.

JSON payload (printed once when the runtime is fully up)

{
  "schema_version": 1,
  "emulator_url": "http://127.0.0.1:4242",
  "agents": ["support", "billing"] /* every discovered agent name */,
  "public_url": "https://<subdomain>.tun.stackbone.ai" /* or null */,
  "deeplink": "https://app.stackbone.ai/app/<orgSlug>/installations/<id>?stackbone-dev=..." /* or null when the tunnel handshake failed */,
  "local_dev_installation_id": "...",
  "services": {
    "postgres_url": "postgres://...",
    "s3_endpoint": "http://127.0.0.1:9004",
    "s3_bucket": "stackbone-dev",
  },
}

Exit codes: 0 ok (graceful Ctrl-C), 3 no project (cwd has no .stackbone/project.json), 4 not found (linked agent disappeared upstream), 1 generic (Docker missing, port busy, …).

Durable workflows & runs

These commands operate against a running installation (the durable runtime stackbone dev boots, or a cloud install) and form the core of the runtime: list and inspect the workflows an installation exposes, control the durable runs they produce, and clear the human-in-the-loop approvals inbox.

They all take --agent <installationId>, defaulting to the local-dev installation linked to the current project.

The workflows, runs and hitl surfaces are served by the durable runtime that stackbone dev boots today. A cloud installation may still answer 404 on these routes until the cloud port lands, develop against stackbone dev in the meantime.

stackbone workflows list

List the durable workflows the installation exposes. Each row shows whether the workflow declares input/output schema ( = has schema, = none) and its trigger.

Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.

Human mode prints ◆ onboarding schedule; an empty list prints No workflows exposed by this installation.

JSON payload

{
  "schema_version": 1,
  "items": [{ "name": "onboarding", "hasSchema": true, "trigger": "schedule" }],
}

stackbone workflows schema <name>

Print one workflow's input/output JSON Schema (derived from the sibling inputSchema / outputSchema Zod exports next to the workflow). Use it to drive a typed start payload.

stackbone workflows schema onboarding
stackbone workflows schema onboarding --json

A workflow with no schemas prints Workflow "<name>" declares no input/output schema (the Playground falls back to a raw JSON field).

JSON payload

{
  "schema_version": 1,
  "schema": {
    "input": {
      /* JSON Schema or null */
    },
    "output": {
      /* JSON Schema or null */
    },
  },
}

stackbone workflows start <name>

Start a durable run of a workflow by name, the external trigger path. The name resolves on the runtime, so the workflow does not have to be bundled into the CLI; you can start any workflow the installation exposes. The input comes from one of two flags (else {}), and it is validated against the workflow's declared inputSchema server-side before any run is created.

Flag Type Description
--input string Inline JSON object passed as the workflow input. Wins over --input-file.
--input-file string Path to a JSON file with the workflow input.
--agent string Installation id to target. Defaults to the local-dev install.
stackbone workflows start onboarding --input '{"userId":"u_123","plan":"pro"}'
stackbone workflows start onboarding --input-file ./payload.json

start is not gated by --yes, it begins a run, not a destructive op. Invalid JSON or an unreadable file is reported before anything is enqueued, and an unknown name fails with "workflow not found". The receipt is the new run; track it with stackbone runs get <id> and stackbone logs tail --run <id>. To trigger a workflow from inside another workflow instead, use stackbone.workflows.start(name, input) / stackbone.workflows.startAndWait(name, input) from the ambient stackbone client (see Workflows).

JSON payload

{
  "schema_version": 1,
  "workflowName": "onboarding",
  "runId": "run_...",
  "worldRunId": "...",
  "trigger": "api",
}

stackbone runs list

List recent durable runs for the installation (workflow runs and agent turns). Cursor-paginated.

Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.
--status string Filter by status: running, done, failed, interrupted.
--cursor string Opaque cursor from a previous page (nextCursor / prevCursor).
--limit string Maximum number of runs to return (1–100).

Human mode prints one row per run: run_... done schedule run created-at.

JSON payload

{
  "schema_version": 1,
  "items": [{ "id": "run_...", "status": "done", "trigger": "schedule", "createdAt": "2026-..." }],
  "nextCursor": "..." /* or null */,
  "prevCursor": "..." /* or null */,
}

stackbone runs get <id>

Inspect a single run by id, status, trigger and timing.

{
  "schema_version": 1,
  "run": {
    "id": "run_...",
    "status": "done",
    "trigger": "schedule",
    "createdAt": "2026-...",
    "startedAt": "2026-...",
    "finishedAt": "2026-...",
    "durationMs": 1234,
  },
}

To follow a run's logs live, use stackbone logs tail --run <id> (see Agent-runtime CLI commands).

stackbone runs retry <id> · stackbone runs cancel <id>

retry starts a fresh run from the original input; cancel interrupts a running run. Both are destructive and require --yes.

stackbone runs retry run_... --yes
stackbone runs cancel run_... --yes

retry returns the new run (Retried run <id> → new run <newId> (running).); cancel returns the cancelled run marked interrupted.

stackbone hitl list

The human-in-the-loop approvals inbox: the return path for requestApproval() (and defineHook) calls made from your workflows, plus any tool call an agent paused for a human decision. Each pending entry is a step waiting on a human decision.

Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.
--status string Filter by status: pending, approved, rejected, timed_out, cancelled.
--cursor string Opaque page cursor (nextCursor / prevCursor).
--limit string Maximum number of approvals to return.

Human mode prints apr_... pending refund created-at.

JSON payload

{
  "schema_version": 1,
  "items": [{ "id": "apr_...", "status": "pending", "topic": "refund", "createdAt": "2026-..." }],
  "nextCursor": "..." /* or null */,
  "prevCursor": "..." /* or null */,
}

stackbone hitl get <id>

Read one approval, including its audit trail of past decisions.

{
  "schema_version": 1,
  "approval": {
    "id": "apr_...",
    "status": "pending",
    "topic": "refund",
    "runId": "run_..." /* or null */,
    "createdAt": "2026-...",
    "timeoutAt": "2026-..." /* or null */,
    "decidedAt": null,
    "decisions": [],
  },
}

stackbone hitl approve <id> · stackbone hitl reject <id>

Decide a pending approval, resuming (or aborting) the durable workflow or agent turn that is parked on it. Both are destructive and require --yes. --reason attaches an optional comment.

stackbone hitl approve apr_... --yes
stackbone hitl reject apr_...  --yes --reason "Out of policy"

Database operations

The stackbone db ... family applies the same migration engine that stackbone dev runs on boot, exposed for you to drive directly at the shell. migrate up is advisory-locked and atomic per file (a failed file rolls back on its own and leaves the journal at the last good entry), and the journal records every applied tag.

By default the schema lives at src/schema.ts and migrations under .stackbone/migrations, a workspace's agents and workflows all talk to the one install Postgres, so they share this root schema. An optional root agent.yaml can override either path, see Project manifests. The verbs that talk to the database (migrate up and migrate status) read the connection string from STACKBONE_POSTGRES_URL when it is set. If it is not set, they automatically discover it from a running stackbone dev session for this project, dev records its database connection while it runs, so you do not have to export the variable in a separate shell. With neither the variable set nor a live dev session the command exits 3 (no project). The read-only Explorer verbs (db query, db schemas, db table) target a running installation instead, see Agent-runtime commands → db.

stackbone db migrate up

Apply every pending migration under .stackbone/migrations against the workspace database. Uses an advisory lock so concurrent invocations are safe, and the journal records each applied tag.

Flag Type Description
--target string Stop after applying the migration with this tag (inclusive). Useful for staged rollouts.

JSON payload

{
  "schema_version": 1,
  "applied": [{ "tag": "0001_init", "appliedAt": "2026-05-16T10:00:00Z" }],
  "skipped": [{ "tag": "0000_bootstrap", "appliedAt": "2026-05-15T09:00:00Z" }],
}

Exit codes: 0 ok, 3 no project (no database connection, STACKBONE_POSTGRES_URL unset and no running stackbone dev session to discover it from), 1 generic (migration failure, atomic per-file rollback already ran).

stackbone db migrate create <name>

Generate a new SQL migration by diffing src/schema.ts against the migrations journal. Wraps drizzle-kit generate with an in-memory config so you do not need a drizzle.config.ts in the project.

The name positional becomes the migration filename suffix. Must match ^[a-z0-9]+(?:_[a-z0-9]+)*$ (lowercase letters, digits and single underscores, e.g. add_users, add_users_email).

Renames need an interactive terminal. When a change looks like a rename, a table or column removed and another added, the migration engine can't tell a rename from a drop-and-create on its own and has to ask you to confirm. Run stackbone db migrate create directly in your terminal (not with --json) so you can answer that prompt. In --json mode, in CI, or under the stackbone dev auto-migrate watcher there is no one to answer, so the command fails with a message telling you to re-run it in your terminal rather than silently writing no migration.

JSON payload

{
  "schema_version": 1,
  "migration_file": ".stackbone/migrations/0002_add_users.sql",
}

Exit codes: 0 ok, 3 no project, 1 generic (invalid name, schema parse error, drizzle-kit failure).

stackbone db migrate status

Classify each migration as applied, pending or drifted (informational only, never throws on drift, just reports it).

JSON payload

{
  "schema_version": 1,
  "entries": [
    { "tag": "0000_bootstrap", "state": "applied", "appliedAt": "2026-05-15T09:00:00Z" },
    { "tag": "0001_init", "state": "pending" },
  ],
}

Exit codes: 0 ok (regardless of drift), 3 no project, 1 generic (cannot reach the DB).

Cloud publish

stackbone publish

Package the project into a publishable artifact. publish reads the workspace by convention, every deep-agents/<name>/index.ts (or an explicit stackbone.config.ts override for workflows), and compiles every agent and every durable workflow into a verifiable tar at dist/stackbone/workspace-bundle.tar.

Native dependencies (.node add-ons) are rejected up front, the runtime image is pure-JS, so a native bundle would crash at boot.

Flag Type Default Description
--json boolean false Emit structured JSON envelopes instead of the pretty UI.

Run stackbone publish --help for the full reference.

Workspace (discovered by convention)

Compiles every agent and every durable workflow on your machine and packs them into a tar so cold boot only extracts, it never recompiles. In order:

  1. Load the workspace and its agents + workflows.
  2. Native-deps gate, per agent: a .node add-on aborts with the offending package name.
  3. Compile each agent to a prebuilt ESM module, keeping the agent-authoring library and its model provider packages external so one copy of each resolves from the runtime image at boot.
  4. SDK-external guardrail, per agent: an agent that inlined @stackbone/sdk aborts (a second copy of the SDK would break per-run logging).
  5. Compile the workflows.
  6. Derive the .well-known/workspace.json manifest, pack the tar and compute its SHA-256 digest.

The artifacts land in your project under dist/stackbone/: workspace-bundle.tar (the bundle) and workspace-bundle.json (a pointer with the digest, size, and the agent + workflow names). The control-plane upload is handled by provisioning when you ship the install, publish produces and verifies the bundle.

JSON payload (workspace)

{
  "schema_version": 1,
  "kind": "workspace",
  "digest": "<sha256>",
  "sizeBytes": 1234567,
  "agents": ["support", "billing"],
  "workflows": ["onboarding"],
  "tar": "dist/stackbone/workspace-bundle.tar",
}

Inline help

stackbone docs [topic]

Print Stackbone documentation inline (no browser, no fetch). Useful when a coding agent wants to look up the contract without burning tokens on a network round-trip.

Topics mirror the pages of this wiki: every documented page becomes a <section>/<slug> topic, plus a top-level <section> index that lists the pages with their descriptions. Run stackbone docs to see the live list.

stackbone docs                       # list every topic, grouped by section
stackbone docs cli                   # auto-generated CLI section index
stackbone docs cli/getting-started   # body of the matching wiki page
stackbone docs sdk                   # auto-generated SDK section index
stackbone docs sdk/overview          # body of the matching wiki page

Agent-runtime commands

The commands above are the project, dev-loop and durable-runtime surface. A further group operates against a running agent installation, agents, logs, the read-only db Explorer, storage, rag, secrets, config, prompts and openrouter. They take --agent <installationId> (defaulting to the local-dev installation linked to the current project) and are documented in full at Agent-runtime CLI commands.

stackbone contract

Print the agent's declared schema, if it has one. Workspace agents declare their input/output contracts per workflow, so the durable-workflow surface is the canonical view: use stackbone workflows schema <name> to read one workflow's input/output JSON Schema, and stackbone workflows list to see which workflows declare a schema at all.

The platform for agent developers.Build, ship and observe agentsthat survive prod.

© 2026 · STACKBONEBUILT WITH ❤️ FROM CANADA AND SPAIN