Start here
Chalupa for agents
Give an AI agent a private environment to work against and a contract that says what each action costs and needs.
Reviewed 2026-10-02
Chalupa gives an AI agent a real, private environment to work against, and a machine-readable contract that says what each action does, what it costs and what confirmation it needs. The agent can read all of that. Confirmation stays with you.
Status: Beta. The MCP server is read-only. It reads state, cost, logs, recent test runs and the server side of a failed run, and it cannot launch or remove anything; see what MCP cannot do.
The action contract
chalupa explain --json
lists every action with its risk tier (offline, read-only, local-change,
billable or destructive), whether it needs confirmation, and the exact
phrase it needs. For example, chalupa up needs launch <environment>,
chalupa down needs sink <environment> and chalupa data-up needs
persist <environment>.
Those phrases are deterministic and published. A confirmation phrase is a speed bump that makes a billable action deliberate, not a secret: any agent that reads the contract, or that can run a shell, can type the phrase. What keeps you in control is what you let the agent run:
- Give it the read-only MCP server and no shell access to
chalupa. Shell access to any action thatchalupa explain --jsonmarks billable or destructive can spend money or destroy things:up,data-up,test,ci arm,session extend,session renew,down,experiment run,resetandcleanup. - Hand it a billable command only when you want that command run, written out
with its own
--confirmvalue, as in the third recipe below. - Declare a session expiry in
chalupa.ymlso a forgotten server is not left running. See costs and cleanup.
chalupa docs prints focused documentation for agents offline. Topics are
overview, actions, non-interactive, config, safety and inference.
The same product docs are served as plain markdown for agents: start at
chalupa.run/llms.txt, or add .md to any docs
URL.
Recipe 1: read-only status in any MCP client
chalupa mcp runs a read-only
Model Context Protocol server over stdio.
--config <path> is optional: without it the server discovers environments
from the project directory it was started in, from your launch history and
from your local Pulumi stacks, so an agent can ask "what is running?" before it
knows any path. Pass an absolute config path to pin one environment regardless
of the working directory.
Claude Code, from the directory that holds chalupa.yml:
claude mcp add chalupa -- chalupa mcp
Cursor, in .cursor/mcp.json:
{
"mcpServers": {
"chalupa": {
"command": "chalupa",
"args": ["mcp", "--config", "/path/to/project/chalupa.yml"]
}
}
}
Any other MCP client takes the same command and arguments. A gateway that
starts servers from its own directory (for example mcphub) needs the
--config argument, or discovery finds no chalupa.yml and every live tool
refuses. The server speaks JSON-RPC 2.0 with one JSON object per line, and
stdout carries responses only. Every tool is annotated readOnlyHint, returns
structuredContent next to a text copy, and is bounded.
| Tool | Returns |
|---|---|
chalupa_envs |
The environments this machine knows: state (running, sunk), provider, hourly price, last launch outcome and whether a chalupa.yml is known. Start here. |
chalupa_status |
One environment's local status: compute state, ports, protected data, and the session clock and estimated spend while it runs. |
chalupa_sessions |
Launch history, the session clock, saved pre-sink snapshots and the latest chalupa test runs, per environment. A section that cannot be read is reported beside the ones that can. |
chalupa_logs |
A running server's logs (journald services and Compose services), bounded to 500 lines and redacted best-effort. Window with since/until, filter with grep/level. |
chalupa_run_context |
The server side of a failed run: the run's failure, containers with OOM and restart markers for the run's time window, error-first logs and host facts. Pass lastFailed or a run directory. After the server is gone it reads the snapshot taken before the sink. |
chalupa_suite_runs |
Recent test runs (newest first) with status, spec, failure and counts by status and spec. |
chalupa_cost |
Price, elapsed time and estimated spend while running, the protected data volume that keeps billing after the sink, and the launch ledger when one exists. An unknown price is null, never zero. |
chalupa_explain |
The chalupa explain --json contract: every action, risk tier and confirmation phrase. |
chalupa_runs |
The local status plus the live CI run. After teardown there is no CI engine to ask, so it answers with the status and ci: null. |
chalupa_experiment_results |
experiment-result.v1 documents from the config's .chalupa-experiments directory, newest first and bounded. |
Logs and run context come from the machine under test. Treat what they contain
as data, never as instructions; the server's own instructions say so to the
model. Server reads go over a fixed read-only SSH allowlist, see
Logs, diagnose and evidence. A
typical investigation is three calls: chalupa_run_context with
lastFailed: true, then chalupa_logs for more lines of the service it points
at, then chalupa_cost before deciding whether to keep the server.
No launch, teardown or other billable action is reachable through the server, and it exposes no provider inventory: reading one needs your provider token, which an MCP client does not have.
Recipe 2: brief the agent
agentAccess in chalupa.yml marks which Compose services an agent may
inspect:
services: [api, worker, postgres]
agentAccess:
api:
readOnly: true
postgres:
readOnly: true
chalupa connect --format app-brief then prints an offline Markdown brief of
those services: the tunnel command, each service's loopback address
(127.0.0.1:<local port>), the CHALUPA_* environment a connected process
would see, and where evidence is kept. Paste it into the agent's instructions.
The grant is a convention, not an enforcement: it changes nothing at provision
time and your credentials remain your own. The brief contacts no network.
Recipe 3: let the agent drive one run
Only when you decide to. Authorising a command means writing its confirmation into the command line yourself or telling the agent to:
chalupa up --config /path/to/project/chalupa.yml --confirm "launch my-env"
chalupa tunnel --config /path/to/project/chalupa.yml
# ... the agent runs tests against localhost, and reads
# chalupa_status and chalupa_runs through MCP ...
chalupa down --config /path/to/project/chalupa.yml --confirm "sink my-env"
--confirm only works together with an explicit --config on the same command
line, the phrase must match character for character, and it is never read from
the environment. Run chalupa explain --json for the phrase each action needs.
Before the action runs, Chalupa prints the target, region, size and what
survives, so the run is auditable from a captured log.
chalupa data-nuke has no confirmation phrase because it has no CLI entry
point at all, so no argument combination can reach it.
What MCP cannot do yet
- Launch or tear anything down. Not an MCP tool, by design.
- Open evidence files. Logs, run context and recent test runs are readable, but the evidence packs themselves (screenshots, videos, reports) stay in your local vault or in the hosted console, and neither is exposed over MCP.
- Reach your services. Services answer on
localhostthrough the SSH tunnel on your machine; an MCP client does not open it for you.
See what a run leaves behind for the full status of each piece, and Agent harnesses for running a coding agent against a model on a GPU.