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 belong to the deployed workspace image. stackbone dev serves a lighter GET /api/health instead, which answers { "status": "ok" } as soon as the emulator is up.

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 client.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, since 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