Operating model
chalupa.yml reference
Configure a project declaratively without duplicating what Docker Compose already knows.
Reviewed 2026-07-23
This file belongs to the target project and sits next to its Compose file.
Tasks receive its path through CONFIG; the name field defines the Pulumi
stack names.
Complete example
name: demo-harbor
compose: ./docker-compose.yml
services:
- api
- worker
- postgres
- redis
overrides:
api:
env:
LOG_LEVEL: info
mem_limit: 768m
worker:
command: ["bun", "run", "worker"]
mem_limit: 1g
droplet:
region: nyc3
size: s-2vcpu-4gb
image: ubuntu-24-04-x64
health:
url: http://localhost:8080/health
status: 200
timeoutSeconds: 300
ssh:
keys:
- demo-operator
allowedCidrs:
- 198.51.100.24/32
persist:
sizeGb: 20
idleShutdownMinutes: 45
seed: bun run seed:demo
cloud:
url: https://chalupa.example.com
heartbeatSeconds: 30
Do not put tokens in this file. The control-plane URL is not a secret; ingest keys are secrets and are delivered at runtime.
Top-level fields
| Field | Required | Purpose |
|---|---|---|
name |
yes | Slug used to name the environment and its Pulumi stacks. |
compose |
yes | Path to the project's docker-compose.yml. |
services |
yes | Services sent to the remote environment. |
overrides |
no | Per-service adjustments applied after inference. |
droplet |
no | Region, size, image, and health check. |
ssh |
yes | Authorized keys and firewall CIDRs. |
persist |
no | Block storage with an independent lifecycle. |
idleShutdownMinutes |
no | Idle window reported to Chalupa. |
seed |
no | Local command run while the tunnel is open. |
cloud |
no | Agent registration with a control plane. |
compose and services
compose must point to the actual file. services uses the exact keys under
services: in Docker Compose:
compose: ./docker-compose.yml
services:
- api
- postgres
The preview fails if a service does not exist. When depends_on points to an
unselected service, Chalupa removes that reference; it does not include the
service implicitly.
overrides
Available overrides are env, mem_limit, and command:
overrides:
api:
env:
NODE_ENV: test
LOG_LEVEL: warn
mem_limit: 768m
command: ["bun", "run", "start:test"]
Entries under env replace Compose values with the same key. Use this
mechanism for non-sensitive behavior. Resolve secrets outside the versioned
file.
droplet
droplet:
region: nyc3
size: s-2vcpu-4gb
health:
url: http://localhost:8080/health
status: 200
The health check runs inside the droplet, so it can use localhost. The schema
requires HTTP(S), loopback, and a URL without embedded credentials. It must
target a port published by one of the selected services; the preview fails
if the URL's port does not appear among the inferred tunnels. cloud-init uses
the check as a readiness diagnostic, but task up does not wait synchronously
for the probe to complete.
The size directly affects estimated cost. Check the current provider price before creating the resource.
ssh
Authorize specific keys whenever possible:
ssh:
keys:
- demo-operator
allowedCidrs:
- 198.51.100.24/32
keys accepts names, IDs, or fingerprints from the account. allowedCidrs
controls the port 22 firewall. The example range belongs to RFC 5737.
An isolated demo can use this explicit opt-in instead:
ssh:
useAllAccountKeys: true
allowedCidrs:
- 198.51.100.24/32
keys and useAllAccountKeys are mutually exclusive. Chalupa never
implicitly authorizes every account key.
persist
persist:
sizeGb: 20
sizeGb creates or references a volume in the data stack. Increasing capacity
and deleting a volume have different consequences; read
Data and seeding before changing it.
idleShutdownMinutes
idleShutdownMinutes: 45
Omitting the field disables idle observation. A value from 5 to 10,080 minutes is reported by the agent and lets the console derive an informational window.
The current version does not delete the droplet when the window expires and
does not put a deletion credential in cloud-init. Use the warning as a prompt
to run task down deliberately. An automatic sinking worker belongs to a
later phase.
seed
seed: bun run seed:demo
The command runs on the local machine while the tunnel is open. It should be idempotent or clearly document why it is not. Do not embed credentials in the command; it is stored as a local Pulumi output.
cloud
cloud:
url: https://chalupa.example.com
heartbeatSeconds: 30
This enables agent installation and configuration. The URL must be an HTTPS
origin without a path, query, or fragment. heartbeatSeconds accepts values
from 15 to 300 seconds and defaults to 30. The task up flow obtains the HMAC
key from the secret store; it is never declared here.
Mandatory validation
Before task up:
export DEMO_CONFIG="$PWD/chalupa.yml"
cd "$CHALUPA_HOME"
task validate CONFIG="$DEMO_CONFIG"
The output must match the remote Compose stack you intend to operate.