Start here
Quickstart
Preview, launch, and connect to a demo environment without confusing ephemeral compute with persistent data.
Reviewed 2026-07-23
This guide starts with a project that has a docker-compose.yml. Chalupa reads
that file, selects the services declared in chalupa.yml, and infers ports,
volumes, and dependencies. The control plane receives signals from the
environment after it starts.
Creating or destroying cloud resources has cost and consequences. The preview is local;
task up,task down, andtask data-nukeare not.
1. Prerequisites
You need Bun, Pulumi, Task, an SSH client, and a DigitalOcean account. The
source project needs a docker-compose.yml, but the preview does not require
Docker to be running locally. Chalupa uses Pulumi's local backend, and the
repository tasks configure its empty passphrase.
Store tokens in your team's designated secret store. Do not put them in
chalupa.yml, committed .env files, Pulumi configuration, or agent logs.
Treat local Pulumi state as sensitive because it contains encrypted cloud-init
user data and service configuration.
Chalupa's lifecycle tasks resolve fixed credential profiles from the tvault
project chalupa; they do not inject the entire project. See
Secrets with tvault for the key map and safe discovery
workflow.
Set the location of the Chalupa repository:
export CHALUPA_HOME="$HOME/projects/chalupa"
cd "$CHALUPA_HOME"
task setup
2. Create chalupa.yml
Place the file next to your project's Compose file:
name: demo-harbor
compose: ./docker-compose.yml
services:
- api
- postgres
- redis
overrides:
api:
mem_limit: 768m
postgres:
mem_limit: 1g
persist:
sizeGb: 20
idleShutdownMinutes: 45
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
cloud:
url: https://chalupa.example.com
seed: bun run seed:demo
The names are intentionally generic. This guide calls the stack
demo-harbor. Replace demo-operator and the RFC 5737 CIDR with a key and
network you control. idleShutdownMinutes feeds an informational warning; the
current version does not delete the droplet automatically.
3. Validate without touching the cloud
From the target project, preserve its path and run the Taskfile's mandatory validation:
export DEMO_CONFIG="$PWD/chalupa.yml"
cd "$CHALUPA_HOME"
task validate CONFIG="$DEMO_CONFIG"
Review three things before continuing:
- Only the selected services appear.
- Every remote port binds to
127.0.0.1. - The retained named volumes and
depends_onentries are expected.
If the preview or TypeScript fails, correct Compose or the configuration before creating resources.
4. Prepare persistent data
If you declared persist, create the data stack once:
task data-up CONFIG="$DEMO_CONFIG"
The volume has a different lifecycle from the droplet. It can continue to incur estimated storage cost while compute is sunk.
If you do not need persistence, omit persist and skip this step.
5. Launch compute
After reviewing the preview and accepting the cost:
task up CONFIG="$DEMO_CONFIG"
The task selects the local Pulumi stack and creates the droplet. cloud-init
starts Compose and runs the health check inside the host, but task up does not
synchronously guarantee that every service is ready. Use the first agent
signal and a local check through the tunnel as confirmation.
6. Open the tunnel
In another terminal, preserve the same variables:
export CHALUPA_HOME="$HOME/projects/chalupa"
export DEMO_CONFIG="/path/to/project/chalupa.yml"
cd "$CHALUPA_HOME"
task tunnel CONFIG="$DEMO_CONFIG"
While the process remains active, the inferred ports appear as localhost on
your machine. You do not need to expose Postgres, Redis, or the API publicly.
7. Run the seed and your suites
With the tunnel open:
task seed CONFIG="$DEMO_CONFIG"
bun run test:e2e
The seed runs on your machine against remote services exposed locally through
SSH. Its data survives compute cycles when you use persist.
8. Sink compute
When you finish:
task down CONFIG="$DEMO_CONFIG"
This destroys the compute stack. Estimated droplet cost stops, but the persistent volume remains and can continue to incur storage cost.
Do not use task data-nuke for routine cleanup. It irreversibly deletes the
persistent volume and its data.
Next steps
Read Concepts to understand the boundaries between the
inference engine, Pulumi, the agent, and control plane. The
chalupa.yml reference documents every field.