Running the runtime

What an orchestrator probes to decide the container is alive, what the runtime puts in the environment for your code, and how the same contract behaves under a local run.

Health and liveness

The workspace splits liveness from health:

Route Behaviour
GET /live Instant 200 { status: "ok" }. No probes, no awaits: the platform liveness signal.
GET /health Runs every subsystem probe in parallel. 200 { status: "ok", checks } or 503 { status: "degraded", checks }.

The deep /health reports the subsystems your workspace depends on. Each check is { "status": "ok" }, or { "status": "error", "detail": "…" } with the reason it failed:

{
  "status": "ok",
  "checks": {
    "database": { "status": "ok" },
    "redis": { "status": "ok" },
  },
}

A single failing subsystem degrades the whole response to 503. The platform uses /live for the liveness probe so a slow subsystem never gets the container recycled by mistake.

Both routes answer on a deployed container and under stackbone dev. A host that declares no subsystem answers 200 { "status": "ok", "checks": {} }, which is what a local run gives you. Read the empty set as "this host reports on nothing". It does not prove the host is healthy: a local run does not own its Postgres or Redis, so it has nothing to report on.

A third route, GET /api/health, is the cheap read that names the host rather than probing it:

{ "status": "ok", "host": "dev", "emulator": "stackbone-dev", "agent": { "slug": "support" } }

host is dev under stackbone dev and image on a deployed container. The emulator marker is present on a local run only, so a tool can tell a local workspace from a deployed one on the same port.

Runtime environment

The runtime injects these into the container as a behavioural contract. You read them, you never set them:

Variable What it is
STACKBONE_INSTALLATION_ID the install this container serves
STACKBONE_API_URL the control-plane URL the SDK talks to
DATABASE_URL the per-install Postgres connection (the agents' + workflows' data plane)
WORKFLOW_REDIS_URL the per-install Redis backing durable workflow runs
MODEL_PROVIDER_API_KEY / MODEL_PROVIDER_BASE_URL the model gateway credentials an agent reads
STACKBONE_SECRET_KEY the per-agent key every stored secret is encrypted with
STACKBONE_S3_* endpoint, keys, bucket and region of the object store stackbone.storage writes to

STACKBONE_S3_FORCE_PATH_STYLE sits in that last group and decides how the bucket is addressed. It defaults to true, which puts the bucket in the path (https://host/bucket/key). Set it to false for a backend that only answers to the bucket-as-subdomain form, such as AWS S3 or Railway Buckets.

Most code never reads these: the ambient stackbone client (stackbone.database, .secrets, .config, …) wires them for you.

The image binds 8080, or PORT when the host sets one, so a platform that assigns the port needs no extra configuration. A PORT that is not a usable port number fails the boot instead of falling back. Binding 8080 anyway would leave the platform health-checking a port nothing listens on. See What you set on the deployed container.

The runtime also serves GET /api/contract, the Stackbone Agent Protocol handshake that advertises the agent-facing stackbone.* capabilities (database, storage, rag, secrets, …). That is the SDK capability handshake; it is distinct from the HTTP endpoints above that you drive (chat, workflows, runs, hooks).

Local development

stackbone dev brings up the same contract on http://127.0.0.1:4242: the chat endpoints and the workflow start/chat routes, all agents running in-process behind one server. The local stack is Postgres + Redis + MinIO. There is nothing to install or sign by hand, and the emulator accepts any non-empty bearer key.

See Local development for the local loop and Getting started to scaffold a workspace.

BUILT WITH ❤️ FROM CANADA AND SPAIN