---
sidebar_position: 6
title: Goal-mode deploys
---

# Goal-mode deploys

**Describe what you want. Get a deployment.**

Goal-mode is `zibby app deploy --goal "..."` — a free-form natural-language install path for any app not in the catalog. Claude writes the bash, agent-ops runs and supervises it inside the container, and you get back a stable HTTPS URL pointing at a running app, encrypted EFS volume and all.

```bash
zibby app deploy --goal "Install n8n on port 5678 with sqlite persistence" \
  --project <project-id> \
  --name automations
```

That's it. ~5 minutes wall-clock on a healthy run, $0.05-$0.30 in Claude tokens, and you have n8n.

## When goal-mode works well

- The install fits in **30 min wall-clock and 8 GB RAM**. (Most things: anything pip / npm / cargo / apt / single Docker run. Not things that need to compile LLVM from source.)
- The app exposes a **single HTTP port** for verification. (Multi-port apps work — agent-ops just verifies the main one.)
- You're OK with the app running on a fresh ephemeral EFS volume. (No "restore from my existing database" — start the customer's data flow yourself, post-deploy.)
- The upstream has a **documented install path**. Random unmaintained GitHub repos with no README work less well than mainstream projects.

If your install needs more than that — long compile steps, custom kernel modules, a 50 GB pre-trained model download — bring your own host. Goal-mode isn't trying to replace EC2.

## How it works

```
zibby app deploy --goal "Install n8n on port 5678 ..."
       │
       ▼
backend POST /apps:
  - extracts verify port from "on port NNNN" (sniffs goal text)
  - splices AGENT_OPS_BOOTSTRAP_MODE=agent_script
  - splices BOOTSTRAP_PROMPT=<your goal text>
  - splices customer's BYOK Claude token (env or --anthropic-token)
  - splices model / max-turns / timeout / token-budget flags
  - splices AGENT_OPS_BOOTSTRAP_SYSTEM_RULES (curated house rules)
  - defaults to 4 vCPU / 8 GB Fargate (heavier than the catalog tiers,
    because installs are CPU-spiky)
       │
       ▼
container starts. agent-ops runs the agent_script loop:

  ┌── Phase 1: PLAN ─────────────────────────────────────────────┐
  │ Claude with Write+Read tools only — no Bash, no Edit.        │
  │ Reads your goal + house rules. Writes one complete bash      │
  │ script to /tmp/install.sh. ~2 turns, ~$0.05.                 │
  └──────────────────────────────────────────────────────────────┘
                              │
                              ▼
  ┌── Phase 2: SUPERVISE LOOP ───────────────────────────────────┐
  │ agent-ops execs /bin/bash /tmp/install.sh in a process group │
  │ (so we can kill the whole tree on intervene).                │
  │                                                               │
  │ Every 30s:                                                   │
  │   - snapshot stdout/stderr tail + proc status + idle time    │
  │   - send to Claude (text-only, no tools)                     │
  │   - Claude returns one JSON line:                            │
  │       {"verdict":"continue","note":"..."}                    │
  │       {"verdict":"done","note":"app responding on :5678"}    │
  │       {"verdict":"intervene","reason":"...","note":"..."}    │
  │                                                               │
  │ continue: log progress, keep polling                         │
  │ done:     write success, leave the nohup'd app running       │
  │ intervene: SIGTERM the pgroup, 5s grace, SIGKILL, replan     │
  │                                                               │
  │ Auto-short-circuit: if proc EXITED with code 0 AND verify    │
  │ port returns 2xx-499, agent-ops declares done without        │
  │ asking the supervisor. Stops false-positive intervenes when  │
  │ the app went into the background and Claude can't see its    │
  │ "startup logs" in the snapshot anymore.                      │
  └──────────────────────────────────────────────────────────────┘
                              │
              intervene? ───→ back to Phase 1, with stderr +
                              stdout + exit code as new context.
                              Claude REWRITES the script (not patches).
                              Phase 2 starts fresh.
                              │
                              ▼
  Hard caps (whichever hits first):
    - 5 iterations
    - 30 min wall-clock (configurable via --timeout-min)
    - $1.00 token budget
```

Every iteration's script + supervisor turns + final status are persisted under `/var/lib/agent-ops/agent_script-state/` on the per-instance EFS volume. `zibby app logs <id>` surfaces the supervisor verdicts in real time; the persisted state is there for post-mortems.

## CLI flags

The flags that matter for goal-mode:

| Flag | What |
|---|---|
| `--goal "<text>"` | Free-form install description. Mutually exclusive with `[appType]`. |
| `--model <name>` | Claude model — `claude-sonnet-4-6` (default), `claude-opus-4-8` (heavier installs), `claude-haiku-4-5-20251001` (cheaper). |
| `--max-turns <n>` | Claude subprocess max turns, 1-200 (default 25). Bump for heavy installs (n8n, OpenHands) that need many supervisor checks. |
| `--timeout-min <n>` | Bootstrap wall-clock minutes, 1-120 (default 30). |
| `--anthropic-token <token>` | Per-deploy Claude credential override. An Anthropic API key (`sk-ant-api03-…`). Also accepts `ZIBBY_ANTHROPIC_TOKEN` env. Falls back to workspace credentials if absent. |
| `--name <name>` | Display name for `zibby app list` / dashboard. |
| `--auth-type / --auth-user / --auth-password / --auth-token` | Optional Caddy auth sidecar in front of the installed app. See [Auth proxy](./auth). |

Goal-mode tasks default to **4 vCPU / 8 GB** Fargate — heavier than catalog tiers — because `npm install -g n8n` and friends are CPU/memory spiky. You can still pass `--cpu` / `--memory` to override.

## Cost expectations

Per goal-mode deploy:

- **Compute** — 5-15 min of 4 vCPU / 8 GB Fargate at standard Fargate pricing. Single-digit cents per deploy.
- **Claude tokens** — typically $0.05-$0.30 on Sonnet (the default). Opus-4-8 can hit $1.00 if the install takes 4-5 intervene iterations. Hard-capped at $1.00 by agent-ops — beyond that the deploy fails.
- **Ongoing** — once the app is running, the deploy is exactly like any catalog app: per-minute Fargate billing at the resource tier you ended up with. No Claude tokens spent after the install converges.

Practical: budget $0.20 - $0.50 per goal-mode deploy attempt, including failed ones. Re-runs after a fix are cheaper because the planner gets shorter context.

## When it converges, when it loops

It converges fast when:

- The install is a single package manager call + a config file + a port to listen on.
- The app's own README has the exact install steps in a copy-pasteable block.
- You include the port in your goal (`"on port 5678"`) — saves the planner a guess.

It loops or fails when:

- The install needs interactive prompts and the planner forgets to `apt-get install -y` / `DEBIAN_FRONTEND=noninteractive`.
- The app needs a sister service (Postgres + Redis + web) and you didn't tell it. Goal-mode does one task; for multi-service, prefer a [catalog multi-service entry](./index#multi-service-entries) or split into multiple deploys.
- The download is huge (multi-GB models) and times out the 30-min wall-clock. Use `--timeout-min 60` if you know that's coming.

If it fails, the supervisor verdicts in the logs tell you exactly what went wrong on each iteration — paste the goal + the failure output back into the next `--goal "..."` with a hint and it usually converges.

## License responsibility

Goal-mode is intentionally a different licensing posture from the catalog:

- **Catalog apps** — Zibby pre-cleared the license. We're confident we can ship that bundle as a paid host.
- **Goal-mode** — **you** are directing the install. You named the upstream project, you accepted whatever license terms apply, you decided to run it on infrastructure you're paying for. Same model as deploying it on your own EC2 instance — Zibby is the compute provider, not the redistributor.

This is why n8n (Sustainable Use License — forbids paid commercial hosting by a third party) isn't in the catalog but **can** be installed via goal-mode: when you direct the install, you're the operator. The SUL is between you and n8n GmbH, not between Zibby and them.

If you're unsure whether your install is fine for goal-mode, read the upstream license. If it requires you-as-the-operator to accept terms before running it, you're the one accepting — make sure that's a thing you're allowed to do for your use case.

## Worked example: n8n

```bash
zibby app deploy --goal "Install n8n on port 5678 with sqlite persistence" \
  --project <project-id> \
  --name automations \
  --max-turns 40
```

Streaming output (abbreviated):

```
↑ Goal-mode deploy: "Install n8n on port 5678 with sqlite persistence"
  Fargate task: 4 vCPU / 8 GB
  model: claude-sonnet-4-6, max-turns: 40, timeout: 30 min
  phase 1: planning install script…
    plan turn 1/40: reading house rules
    plan turn 2/40: wrote /tmp/install.sh (47 lines)
  phase 2: executing /tmp/install.sh under supervision…
    [30s ] supervisor: continue — apt-get update in progress
    [60s ] supervisor: continue — installing nodejs 20 from nodesource
    [120s] supervisor: continue — npm install -g n8n (compiling sqlite3)
    [240s] supervisor: continue — n8n starting, binding to :5678
    [270s] auto-short-circuit: process exit 0, port 5678 returns 200
✔ Deployed (instanceId: f1e2d3c4)
→ Public URL: https://f1e2d3c4.apps.zibby.dev
```

Total: ~4.5 min, 1 iteration, $0.07 in Claude tokens. Open the URL, set up your n8n admin account, you're done.

→ Next: [Auth proxy](./auth) (put basic auth in front of the install you just did) or [Agent operator](./agent-ops) (how the supervise loop works in detail)
