On this page

Configuration

First-run config and deployment profiles

stado config init creates only a schema-versioned local queue profile: local compute, local primary and backup stores, one deployment identity, and a loopback dashboard. It contains no Wisent service routes, production clients, cloud locators, or credentials. Existing legacy files migrate explicitly with stado config migrate; the exact prior file is preserved beside the migrated document.

STADO_CONFIG selects the operator-owned deployment profile. Stado ships no company deployment profile: stado config init creates a neutral local profile, and an operator extends that file with provider order, explicit provider fences, storage, object/release/service verifiers, workload grants and service routes. Those decisions remain outside the public source tree and cloud CLI state. A selection is used or refused, never replaced: a STADO_CONFIG that names a file that does not exist stops every command that reads the profile with STADO_CONFIG names <path>, which does not exist, and one that is not text with STADO_CONFIG cannot be read: <error>, instead of running on another profile or on none. Only config init and the credential-store migration write the selected file before it exists.

config init writes to a nonempty STADO_CONFIG, expanding a leading ~ against HOME. Without that selector it writes ~/.stado/config.json. It refuses an existing destination with config file already exists: <path>; it does not overwrite that profile or fall back to the default destination; a selection that is not text is refused with STADO_CONFIG cannot be read: <error>.

STADO_CONFIG="$PROFILE" stado config init

The initial local registry is seeded under HOME/.stado/local-storage, and an existing registry is retained. Selecting a different profile filename alone does not isolate the local stores. A lifecycle test must also select its own home directory inside the checkout's ignored build directory:

HOME="$TEST_HOME" STADO_CONFIG="$TEST_PROFILE" stado config init

storage.backend selects the write authority and first read target: a self-hosted store (stado, alias self-hosted, or minio, garage, seaweedfs, ceph), a hosted one (gcs, azure, s3, cloudflare, backblaze, wasabi and the other providers storage providers lists), any other S3 API endpoint (s3-compatible), or local. Every S3 API store reads its bucket, region, account, endpoint and credential role from storage.s3_compatible, each only where its provider asks for it. storage.backup configures a disaster-recovery mirror: a primary mutation commits first and is mirrored afterwards. Ordinary storage clients may retry a failed primary read against that mirror; authority-sensitive readers, including the object API server, use primary-only mode instead. A successful primary answer that an object is absent never falls through to the backup. A null or empty storage.backup.backend disables the Stado-managed mirror. Changing the write authority still requires an explicit fenced migration or the fixed-root reconciliation described in disaster recovery; configuration and read fallback never promote the backup.

Only route-local or process-local values should be overridden:

Var Purpose
STADO_CONFIG Readable deployment profile path.
STADO_API_URL Operator-selected canonical HTTPS Stado origin, including /api/release/object; overrides api.url. Plain HTTP is accepted only on loopback.
STADO_RELEASE_ORIGIN Object-service origin used by the stado-landing gateway. Public callers still use STADO_API_URL; the gateway's upstream is selected independently.
STADO_API_TOKEN Dedicated caller token for its mapped object namespace.
STADO_MACHINE_API_TOKEN Machine submit/status/cancel token.
STADO_SERVICE_API_TOKEN Caller-specific deployer token; accepted only for mapped service names/actions.
STADO_REGISTRY_API_URL Desktop's local source and the endpoint assigned to its registry API credential.
STADO_REGISTRY_API_TOKEN_FILE Desktop's owner-only raw registry client bearer file; defaults to ~/.stado/registry-api-desktop-token.
WC_REGISTRY_API_CLIENTS Exact registry API client mapping; overrides registry_api.clients.
WC_SKARBIEC_URL Stado's Skarbiec service origin for credential CLI, coordinator and API field reads.
WC_SKARBIEC_CONSUMER Stado's Skarbiec consumer: stado.
WC_SKARBIEC_TOKEN_FILE Owner-only Stado bearer file, normally ~/.stado/stado-skarbiec-token.
STADO_RELEASE_VERSION Required exact immutable Stado runtime version.
STADO_RELEASE_PLATFORM Required exact Stado runtime platform for dispatched agents.
STADO_AGENT_POLL_SECONDS Required whole seconds a dispatched cloud worker (stado serve --standalone --worker --idle-shutdown) waits between queue polls that started nothing (config key agent.poll_seconds); dispatch refuses to create a machine without it.
STADO_SSH_KEEPALIVE_SECONDS, STADO_SSH_KEEPALIVE_COUNT_MAX How often an idle native SSH session asks the server whether it is still there, and how many unanswered asks end it (config keys ssh.keepalive_seconds, a whole number above zero, and ssh.keepalive_count_max). A command session runs without keepalive when neither is declared, as OpenSSH does by default. A reverse forward is long-lived and only keepalive tells it its peer is gone, so it is refused until both are declared: SSH keepalive is not declared: a reverse forward needs both ssh.keepalive_seconds (env STADO_SSH_KEEPALIVE_SECONDS) and ssh.keepalive_count_max (env STADO_SSH_KEEPALIVE_COUNT_MAX); declare them with stado config set. Declaring one without the other is refused the same way.
WC_EMAIL_TO, WC_ALERT_SKRZYNKA_MAILBOX, WC_ALERT_SKRZYNKA_ORGANIZATION The e-mail alert destination and the Skrzynka mailbox and organization the skrzynka channel sends from (config keys alerts.email_to, alerts.skrzynka_mailbox, alerts.skrzynka_organization); see How the operator is asked. Which channels page is the registry's operator_contact, set with stado alerts preferences set.
WC_BUCKET The queue bucket. The stado serve --watchdog role uploads its diagnostics there unless --watchdog-bucket names another; with neither, the role is refused with the watchdog has no bucket: pass --watchdog-bucket or declare WC_BUCKET.
STADO_HOST_HEALTH_API_URL Authenticated Stado host-health origin.
STADO_HOST_HEALTH_SKARBIEC_URL Skarbiec origin for the route-only host-health publisher.
STADO_HOST_HEALTH_SKARBIEC_CONSUMER Exactly stado-host-health-beacon.
STADO_HOST_HEALTH_SKARBIEC_TOKEN_FILE Owner-only grant scoped only to the item playing role host-health-api.
STADO_CREDENTIALS_STORE Requested credential backend (skarbiec, skarbiec://<https-origin>, or file://<absolute-path>). A value different from credentials.store is a pending migration.

What each bearer opens, and how every token is verified against its own Skarbiec item: security.

The public origin is independent of host-control routes and network providers. Changing the selected HTTPS endpoint does not require changing a release client. A gateway's upstream is selected by its deployment configuration, not by detecting a tunnel program.

Web products select their edge separately. A product with edge: "stado" requires web_api.edge with target, address and contact; stado web edge declare records that selection. Without a valid declaration, stado web status returns edge-unconfigured, the exact edge_error, and a non-zero exit code. It does not treat an unknown expected address as a healthy public connection.

Cloud-provider locators and credentials are not caller overrides. An enabled provider adapter receives its exact profile and provider-plugin identity; a workload-agent grant contains only the provider-neutral application roles in agent.skarbiec.roles. It must never contain cloud-gcp, cloud-azure, or cloud-aws, and no bootstrap, health, recovery, or release path invokes gcloud, gsutil, or az.

Product data enters through stado://<namespace>/<key> and the authenticated Stado object boundary. Immutable artifact manifests may additionally reference provider-native az://, gs://, and s3:// locations, plus hf:// and HTTPS; access still resolves through authenticated provider adapters, and embedded credentials or sensitive query parameters are rejected.

How the gateway resolves a namespace and authorizes each key and action: object store.

Optional alerts are disabled when alerts.channels is absent or empty. Enabling a channel authorizes only its own credential lookup and network route. The Pub/Sub topic and SendGrid recipient are inert unless their adapters are also enabled. An alert failure is isolated from scheduling, execution, health, and the other channels.

Mobile egress request boundary

The loopback proxy requires the deployment's header budget. It includes the request line, header fields and terminating blank line, not the request body or the bytes carried by a CONNECT tunnel.

stado egress mobile serve --interface "$INTERFACE" --port "$PORT" \
  --max-header-bytes "$HEADER_BYTES"

HEADER_BYTES must be a positive whole number chosen by the deployment. A missing, zero or invalid value is refused by the CLI before a listener starts. Managed service declarations must include both arguments --max-header-bytes and their value in the service's argument list. There is no built-in byte budget.

A header ending exactly at the declared boundary is accepted. A larger one closes the client connection before opening an upstream connection; the service log names --max-header-bytes, the declared limit and the observed byte count. EOF before the terminating blank line is reported as an incomplete request. Bodies and CONNECT payload bytes that arrive with the header are forwarded without truncation. Readiness reports the actual bound socket address.

The real qualification journey is node tests/egress/headers.mjs in the Stado checkout, with STADO_BIN naming the candidate executable, STADO_TEST_SOURCE_REVISION its exact committed source revision and STADO_EGRESS_TEST_INTERFACE a real interface with a non-loopback IPv4 address on the qualification host. It launches an isolated proxy and TCP receiver, checks a boundary-sized header with a body, oversized and incomplete refusals, and CONNECT payload preservation. It keeps binary and test hashes, commands, exit statuses, received bytes and the verdict under .build/egress-headers-*. Missing prerequisites do not pass.

API request boundaries

How an API listener bounds every request head, body, operator console request and fleet join report before reading it, and where those bounds are declared: API request boundaries.

The scan load ceiling

host.scan_load_ceiling (WC_HOST_SCAN_LOAD_CEILING for one process) is the one-minute load average above which the host process skips its scans of the host's own disk — a preview of the janitor's build-cache walk, the beacon's launchd event reads, the inventory walk of a space report on its own host — and publishes the skip in the beacon's scans block (Beacon). A janitor pass on a volume at the rule's full threshold walks the build caches whatever the load, at background priority, because that walk is what frees the disk; its reading is recorded as an admission:

stado config set host.scan_load_ceiling "$LOAD_CEILING"
stado config get host.scan_load_ceiling

The value is a load average: a number, not negative, not infinite; anything else refuses the scan with host.scan_load_ceiling = "<value>" is not a load average and the beacon carries the refusal. A host that declares nothing is bounded by its logical core count, measured by the process that scans, and the beacon names that source as measured_cores.

Machine source archive boundaries

machine.source_limits declares archive_bytes, extracted_bytes, members and trailing_bytes for machine submissions that carry a source archive. WC_MACHINE_SOURCE_LIMITS supplies the same document for one process. There is no built-in size or member budget; stado config validate checks a stored declaration, and source admission checks the effective declaration before reserving a request. CLI and Desktop configuration use the same key. See Source archive bounds for the command, refusal semantics and real qualification journey.

Credential store

Where Stado keeps and reads its credentials: Credential store.

Registry API access

Which clients may call the registry API, with which bearer and actions: Registry access and the registry document.

Registry

The registry document and how Stado reads it: Registry access and the registry document.

Logical services and local resolvers

How a logical service is declared and reached through a host's local resolver: Logical services and local resolvers.

Signed product release control

The optional top-level release_control object owns product release trust and desired state. trusted_keys contains Ed25519 public keys only. Each product binds one logical service, exact archive paths, schema versions, a blue-green policy, and registered host policy. desired and previous are written only by stado release promote|rollback; their platform references point beneath the same immutable stado://releases/<product>/<version>/<platform>/ coordinate.

Each target uses two private candidate ports and one loopback stable bind. Its state, runtime, log, and install roots are absolute. A legacy launchd label and plist are optional one-time migration inputs: the agent starts and proves the candidate before disabling the legacy service, then owns the stable port.

Registry validation rejects unknown products/services/targets, non-loopback stable binds, reused ports, unsafe paths, untrusted desired keys, incomplete platform sets, non-monotonic zero generations, and rollback windows shorter than drain.

A block that declares trusted_keys and an empty products map is accepted. It states what the document trusts and nothing about rollout, which is exactly what stado scratch create emits into a lease's registry: the fleet's schema_version, generation and trusted_keys, no products. A block that declares neither is the only one refused, as registry.release_control must declare trusted_keys or products.

Local inference

How a host's local inference is declared and served: Local inference.

Quotas

The provider-neutral config/quotas.json object contains reservation overlays, not invented capacity. A reservation subtracts operator-owned capacity from a live provider limit before dispatch. Missing or unreachable live quota data is reported as unavailable; Stado does not reinterpret it as zero usage or unlimited capacity.

GCP quota reads are part of the preview compute adapter and use the Rust provider boundary. Azure supports configured reservations with incomplete live VM-family coverage. Live AWS quota management is planned and unavailable.

Optional GCP adapter prerequisites

The GCP compute adapter is preview. An operator must explicitly enable it and supply an already provisioned project, canonical store, scoped managed identity or Skarbiec service account, quota overlay, network, image, ownership labels, cost policy, and immutable Stado release. Runtime compute and storage operations stay inside the Rust provider adapters; install, bootstrap, release, health, and recovery paths do not invoke a cloud CLI.

The image and the geography are required bindings: GCP_IMAGE and GCP_IMAGE_PROJECT (config keys image and image_project), GCP_ZONES (zones, the zones a machine is created in, in preference order) and GCP_REGIONS (regions, whose quota is read). None is built in: a machine create without them is refused with GCP compute bindings are not declared: … naming the missing ones, and a quota read or request without regions says so. A zone that does not carry the machine type answers GCE's own error and the next declared zone is tried. The Azure provider likewise needs its resource group, locations, vnet, subnet, NSG, image URN and VM user declared, and the AWS provider its region, security group, IAM profile and AMI; each refusal names the bindings that are missing.

Zone candidates and machine compatibility belong to the selected deployment profile. Resource exhaustion may advance to the next allowed candidate; an authorization, ownership, invalid configuration, or ambiguous provider error must not. GCP is not stable until a release-scoped live test creates an owned VM, boots the pinned agent, runs and collects a workload, exercises cancellation and recovery, and reaps all paid resources.

The active deployment workflow publishes immutable native releases and installs the Rust coordinator. It has no Cloud Function scheduler, mutable package upgrade, provider CLI authentication, or ambient credential fallback.

Workload runtime ownership

Stado does not pin Python, CUDA framework, Hugging Face, NumPy, or application package versions as part of the control-plane contract. A workload declares and owns its runtime, image, command, source revision, artifacts, and verification hook. Provider bootstrap templates may install prerequisites required by a specific workload profile, but those pins are deployment data and do not become dependencies of the Rust agent or local onboarding path.

Source: this website