Run and test
Lifecycle
Operate an environment through explicit steps and retain data only for as long as you need it.
Reviewed 2026-10-04
The lifecycle is split into local preview, optional data preparation, compute, access, and shutdown. The Taskfile bundled with the CLI encapsulates the operational logic; do not reproduce its Pulumi commands by hand.
One entrypoint
Operator commands on this page use the chalupa CLI. It runs from any
directory and delegates each action to the exact public Taskfile action
described here; see Local CLI and operator UI. A few
operations have no chalupa verb yet: the
Advanced section at the end lists them, and
adding a verb for each is a known gap.
At a glance
| Stage | Command | Changes the cloud | Effect |
|---|---|---|---|
| Preview | chalupa preview --config <path> |
no | Offline: the inferred Compose, CI plan and tunnelled ports. |
| Prepare data | chalupa data-up --config <path> |
yes | Creates the persistent volume. |
| Launch | chalupa up --config <path> |
yes | Creates ephemeral compute. |
| Connect | chalupa tunnel --config <path> |
no | Keeps local SSH tunnels open. |
| Keep the tunnel | chalupa tunnel keep|stop|status --config <path> |
no | Runs a supervised tunnel in the background, stops it, or reports it. No terminal needed. See Supervised tunnels. |
| Wait | chalupa wait --config <path> |
no | Waits until every compute.readiness probe passes. No terminal needed. |
| Shell | chalupa ssh --config <path> |
no | Opens an interactive session on the server. |
| Seed | chalupa seed --config <path> |
changes data | Runs the seed through the tunnel. |
| Inspect | chalupa status --config <path> |
read-only | Reads exact local compute and protected-data stack state. |
| Test | chalupa test <suite> --config <path> |
yes | Launches, runs a declared suite from your machine, and sinks, in one command. See Run a suite with chalupa test. |
| Sink | chalupa down --config <path> |
yes | Destroys compute only. |
Deleting the persistent volume is deliberately not in this table: the CLI never exposes it. See Delete data.
The local CLI and operator UI presents this model and delegates the public actions in the table. The Taskfile remains authoritative: the CLI does not reconstruct the Pulumi commands.
Related pages:
- Warm boxes and reuse: keep a server for a window and reuse it.
- Expiry and the local teardown runner: what destroys a server when its deadline passes, and how to extend or renew a session.
- Data and seeding: the volume that outlives the server.
Preview
The preview runs the same inference as the Pulumi program without creating resources:
export DEMO_CONFIG="$PWD/chalupa.yml"
chalupa preview --config "$DEMO_CONFIG"
Without --config, preview looks for ./chalupa.yml and then in parent
directories, and only falls back to the bundled demo with a visible warning.
Stop if a service is missing or an unexpected port appears. Every
provider-changing action refuses a missing config; it never promotes the
synthetic preview default into a billable or destructive operation.
Prepare the data stack
This step applies only when chalupa.yml declares persist:
chalupa data-up --config "$DEMO_CONFIG"
Run it once per volume. The data stack has a separate name so destroying compute does not include it.
Launch
Before it touches the provider, chalupa up (and chalupa data-up) runs an
offline launch gate: the config's Compose preview and CI plan. It does not run
Chalupa's own test suite, so an unrelated failing test cannot block a launch.
Set CHALUPA_STRICT_GATE=1 to run the full chalupa validate gate instead.
Capacity check
After the offline gate and before anything bills, chalupa up, chalupa data-up
and chalupa cache-up run a read-only capacity check. It compares the memory
limits your config declares with the server size's RAM, and asks the provider
whether your account has room (its server quota) and whether that size is
sellable in that region right now. It needs no confirmation and creates
nothing. A result it cannot verify (no token yet, provider API unreachable)
never blocks the launch; only a positive refusal does, and the message names the
fix. If the primary target is refused for capacity, the entries in
alternatives (see chalupa.yml) are
printed as suggestions; to use one, make a separate config with its own name.
Set CHALUPA_CAPACITY_PREFLIGHT=off to skip the check.
chalupa up creates billable resources:
chalupa up --config "$DEMO_CONFIG"
When cloud.url is configured, the task first validates that the ingest-only
profile is available so a credential error occurs before resource creation.
It then loads only the provisioning credential into Pulumi, creates the stack,
and delivers the agent through cloud-init without the ingest key. After
provisioning, a separate ingest-only subprocess streams the key over SSH and
installs it as a root-only file, so Pulumi and the provider's user data never
receive it. See Hosted console for how the agent
and key work.
When observability.monitor is configured, cloud-init downloads only the exact
declared Monitor release and verifies its digest before installing it. A
checksum mismatch fails closed rather than falling back to another version. See
Performance telemetry.
After provisioning, chalupa up opens a temporary tunnel and waits for the
forwarded ports and for compute.health to answer (up to its timeoutSeconds).
If it never answers, up fails and the server keeps running and billing, so
inspect it or run chalupa down. Without compute.health, only the tunnel
ports are checked and application readiness is unverified, so confirm it with
the first heartbeat and through the tunnel, or pass --wait
(below) to have up wait for compute.readiness.
If SSH key delivery fails after provisioning, the task exits non-zero and warns that compute may still be billable. It never destroys the environment as an implicit rollback. Correct the same OpenSSH access used for the tunnel and retry without provisioning again:
chalupa agent-bootstrap --config "$DEMO_CONFIG"
The retry fails closed if the current config's cloud.url differs from the
origin recorded by the provisioned stack. In that case, run the normal
validated chalupa up flow so Pulumi can review and apply the configuration
change before any credential is delivered.
Connect and work
Keep the tunnel open in one terminal:
chalupa tunnel --config "$DEMO_CONFIG"
In another terminal, you can run:
chalupa seed --config "$DEMO_CONFIG"
bun run test:e2e
For an interactive shell on the host itself:
chalupa ssh --config "$DEMO_CONFIG"
That action resolves the server address from Pulumi output, so operating an environment never requires reading or pasting its IP.
Connections arrive at localhost; the SSH process is the access boundary.
For a tunnel that survives sleep and network changes, see
Supervised tunnels. Closing the tunnel does not destroy the environment. Chalupa can show an
observed idle window to remind you to sink it.
Waiting for readiness
When the config declares compute.readiness,
chalupa wait waits until every probe passes together, through the tunnel
(chalupa tunnel keep first). It needs no terminal, so a script or an agent
can use it:
chalupa tunnel keep --config "$DEMO_CONFIG"
chalupa wait --config "$DEMO_CONFIG"
✓ elasticsearch (http service:elasticsearch/_cluster/health (json status in [yellow, green])) — ready at +12.4s (2026-10-02T10:00:12.400Z)
✓ rabbit (amqp service:rabbit (stable 3x1s)) — ready at +4.1s (2026-10-02T10:00:04.100Z)
Ready in 12.4s (demo-harbor).
| Flag | Effect |
|---|---|
--probe NAME |
Wait for one named probe only. An unknown name lists the declared ones and exits 64. |
--timeout SECONDS |
How long a probe with no timeoutSeconds of its own has (default 300). |
--json |
One JSON document at the end: ready, elapsedMs, and per probe name, ok, readyAt, readyAtMs, error, attempts. |
--events ndjson |
One JSON line per change as it happens (probe-ready, probe-lost, probe-timeout), then a final result line. Not combinable with --json. |
Exit status: 0 ready, 1 not ready in time, 64 usage or config refusal. A timeout names each failing probe with its last error, and says so when no tunnel is answering at all.
Three places run the same probes for you:
chalupa up --wait— after provisioning it opens a supervised tunnel, waits, and leaves the tunnel running (chalupa tunnel stopcloses it).--waitchanges nothing about authorization or spend. If a probe does not pass,upexits non-zero and tells you the compute is still running and billing; it never destroys it for you. Plainupdoes not wait.chalupa test— areadinessphase between the tunnel and the specs. If a probe does not pass, no spec starts, the compute is sunk, and the run ends as an infrastructure failure (exit 69), not a test failure. Each probe's verdict and ready-at time is recorded in the run'srun.json.chalupa exec— the command starts only after every probe passes.
Sink
When the work is complete:
chalupa down --config "$DEMO_CONFIG"
When compute was created with a dedicated identity, export the same
SSH_IDENTITY=/absolute/path/to/private-key before down. The destroy still
proceeds if a best-effort SSH flush fails, but using the correct identity gives
the final log and Monitor windows their bounded delivery opportunity.
For an additional local identity check, the operator UI can require a compute
provider ID refreshed within two minutes and pass it to the same Taskfile
destroy path. A direct chalupa down is not
provider-ID-bound; the CLI target summary states that limitation. See
Local CLI and operator UI.
This destroys the server and stops its estimated compute cost. The persistent volume remains intact and can continue to incur estimated storage cost.
If the environment uses the hosted console, the action captures its provider ID before the destroy. If Monitor is enabled, it first requests a partial-window flush over SSH and waits at most 30 seconds for the producer and adapter's bounded spool to drain. Failure emits a warning but never keeps billable compute alive. The adapter resumes collection after the attempt, so a later provider failure does not leave a surviving server unobserved.
The provider-only subprocess then writes non-secret outputs to a private,
short-lived local receipt and exits. Only after a successful destroy does a
separate ingest-only subprocess send the signed, idempotent sunk event. A
reporting failure does not undo the destruction: the action emits a warning.
Reconciliation may recover the state only when Chalupa already knows the
deployment; a short-lived cycle missed between inventory polls is not
observable. Verify the state manually and treat the provider invoice as
authoritative. Chalupa retains events, suite runs, and downsampled performance
windows so the resource's absence does not erase operational context.
Idle window
With idleShutdownMinutes, the agent reports idle checks and the control plane
derives an informational window. Use the warning as a prompt to run
chalupa down.
Delete data
Deleting the persistent volume is an independent action that the chalupa CLI
deliberately never exposes, interactively or otherwise. It is not part of the
normal shutdown path and must not be used merely to “clean up” an environment.
The one way to do it, a separately confirmed Taskfile operation, is in
Advanced. Confirm the backup, target, and
stack name before you run it.
Optional local expiry runner
Moved to Expiry and the local teardown runner.
Expiry and billing
Extending and renewing a session moved to Expiry and the local teardown runner.
Keeping a box warm
Moved to Warm boxes and reuse.
Scheduled teardown failures
Moved to Expiry and the local teardown runner.
Supervised tunnels
Moved to Tunnels and security.
Advanced: Taskfile-only targets
These operations have no chalupa verb yet, so they run through the Taskfile
bundled in the installed @thelacanians/chalupa-cli package, with go-task:
task --taskfile <package directory>/Taskfile.yml <target> CONFIG=<path>. The
commands below are written as task <target> for brevity. Each is a known gap.
Review registered teardowns without changing anything, and run the armed
runner, which destroys expired compute and leaves <stack>-data untouched
(see Expiry and the local teardown runner):
task teardown:run
task teardown:run-armed TEARDOWN_ENABLED=1
Show or remove the installed teardown schedule:
task teardown:schedule:status
task teardown:schedule:remove
Delete the persistent data volume. This is irreversible, and the confirmation
value must exactly match the name in chalupa.yml; otherwise the target
refuses to unprotect or destroy the data stack:
task data-nuke \
CONFIG="$DEMO_CONFIG" \
CONFIRM_DATA_NUKE=demo-harbor