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/chalupa.yml reference
/

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

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.

PreviousConceptsNextLifecycle

On this page

Complete exampleTop-level fieldscompose and servicesoverridesdropletsshpersistidleShutdownMinutesseedcloudMandatory validation