Skip to content
chalupa
How it worksSecurityDocumentation
Open console
Menu
How it worksSecurityDocumentationOpen console
chalupa

Operational signal for ephemeral environments. Compute can be torn down while persistent data follows its own lifecycle.

Product

How it worksSecurityConsole

Learn

QuickstartConceptsAPI and schema

Built for ephemeral operations, not forgotten resources.

All displayed costs are estimates.

Documentation/Quickstart
/

Start here

QuickstartSecrets with tvault

Operating model

Conceptschalupa.yml referenceLifecycleTunnels and securityData and seeds

Control plane

Control plane and agentSuites and artifactsCosts and idle observation

Reference

Private operationsTroubleshootingAPI and schema
Browse documentation
/

Start here

QuickstartSecrets with tvault

Operating model

Conceptschalupa.yml referenceLifecycleTunnels and securityData and seeds

Control plane

Control plane and agentSuites and artifactsCosts and idle observation

Reference

Private operationsTroubleshootingAPI and schema

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, and task data-nuke are 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:

  1. Only the selected services appear.
  2. Every remote port binds to 127.0.0.1.
  3. The retained named volumes and depends_on entries 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.

NextSecrets with tvault

On this page

1. Prerequisites2. Create chalupa.yml3. Validate without touching the cloud4. Prepare persistent data5. Launch compute6. Open the tunnel7. Run the seed and your suites8. Sink computeNext steps