# CLI Reference for AI Agents

> Tarout CLI commands and confirmation rules for coding agents

# CLI Reference for AI Agents

> **Preflight - check auth first.** Run `tarout whoami --json`. If it does not
> return `success: true`, authenticate with the table in
> [start.md](https://tarout.sa/docs/for-ai/start.md)
> before running anything on this page - every command below fails without a
> credential, and the failure reads like a broken deploy rather than a missing
> login.

Install:

```sh
npm install -g @tarout/cli
```

(`curl -fsSL https://tarout.sa/install.sh | sh` does the same `npm install -g` plus `PATH` wiring. Prefer the npm line - agents are often configured to refuse piping a remote script into a shell.)

## Authentication

Run `tarout whoami --json` before anything else. It is the cheapest command in the CLI and it distinguishes "not signed in" from every other failure you might otherwise spend a deploy diagnosing.

If it fails and the user's pasted prompt carried a credential, use it - `tarout login --token <YOUR_API_KEY>` for a `Key:` suffix, `tarout agent connect --handoff <HANDOFF>` for a `Handoff:` suffix. Both write `./.tarout/auth.json`, scoped to the project directory you are in and reused by every later command, so you authenticate once per project and never again.

If it fails and you have no credential, do not hand the final user a list of commands: run `tarout deploy ...` and let the CLI open the browser login/registration flow inside that run, or run `tarout login` yourself and wait for them to approve it.

After browser or Google login, Tarout must show the CLI authorization page. The final user clicks **Yes, authorize CLI** there; the browser returns to the local CLI callback and the terminal continues. If the user lands on the dashboard instead, the CLI auth return URL was lost and the deploy flow should be retried.

Manual auth commands exist for people using the CLI directly, but an LLM agent should not hand those commands to the final user. The agent runs the deploy command and lets the CLI handle login/authorization inside that flow.

`tarout deploy` also prompts for login or registration when no local session exists.

## Agent Setup

```sh
tarout agent init [path] [--agent claude|codex|cursor|other]
```

Scaffolds agent config into the project so a coding agent can drive the CLI. **Run this
first during onboarding** - it grants the `Bash(tarout:*)` permission so subsequent
commands don't each need approval. Local-only (no auth/network) and idempotent. `--agent
claude` (default) writes `CLAUDE.md` and adds `Bash(tarout:*)` to
`.claude/settings.local.json`; `codex`/`cursor`/`other` write `AGENTS.md`. Existing files
are merged/appended, never overwritten. Under `--json` it streams `file_written` events
and a final `result` envelope listing each file and its action (`created` / `updated` /
`appended` / `unchanged` / `skipped`).

In **agent mode** (`--json` or a non-TTY), `tarout up` / `tarout deploy` / `tarout init`
auto-run this on first use (emitting an `agent_setup_done` event) so the allowlist is
always in place; pass `--no-agent-setup` to opt out. Any other command emits an
`agent_setup_required` hint when the allowlist is still missing.

## Deployment

```sh
tarout deploy [app-id-or-name] [options]
```

When `[app-id-or-name]` is omitted, Tarout uses `.tarout/project.json`. If the directory is not linked, the CLI prompts to create or select an app.

For agent workflows, the agent inspects the project first, announces the plan it derived (a statement, not a question), then types the command itself in the same turn - no approval wait. **Do not pass tier flags** (`--plan`, `--database-plan`) - Tarout defaults every resource to the org's subscribed tier (free for a free org, Starter for a Starter subscriber, etc.). If no database or storage is needed:

```sh
tarout deploy --wait --database none
```

A folder with a github.com remote deploys from that repo, so every push redeploys; any other folder is uploaded. Do not pass `--source upload` unless the user asked for an upload: it switches the GitHub bind off.

| Option | Description |
|--------|-------------|
| `-w, --wait` | Stream logs and wait for completion |
| `--watch` | Alias for `--wait` |
| `-r, --region <region>` | Region request; active region is `me-central2` |
| `--source <source>` | Source choice: `auto` (default: the GitHub repo when the org can read it, otherwise this folder), `upload` (only when the user asks), `configured`, or `connect` |
| `--plan <plan>` | App plan: `free`, `shared`, or `dedicated`. Omit to use the org's subscribed tier (recommended). |
| `--database <type>` | Database choice: `none` or `postgres`. The CLI also accepts `mysql`, but MySQL is not available yet and that create fails. |
| `--database-plan <plan>` | Database plan: `free`, `starter`, `standard`, or `pro`. Omit to use the project's entitled tier. On a paid project with no open DB slot, an interactive run buys the cheapest tier and opens the payment page; a `--json`, `--yes`, or non-TTY run returns `NEEDS_UPGRADE` instead. |

Agent announcement (a statement before deploying - not a question; deploy in the same turn):

> "Found: <database/storage/Git findings>. Deploying <owner/repo from GitHub, or the current folder> to Dammam on your subscribed tier with <resources>. Tarout will open a browser if it needs you to log in, pay, or connect GitHub. (Say 'no storage' any time and I'll adjust.)"

If code indicates database usage, include explicit `--database` flags. If it indicates file storage usage (S3-compatible storage, Google Cloud Storage, Firebase Storage, UploadThing, or multipart upload libraries), create a bucket separately with `tarout storage create` and attach it with `tarout storage attach <bucket> <app>` (over MCP: `call` with `storage.attachToApplication`), which writes the connection env vars for you. Never paste a dashboard access key into env vars: those keys only work from the bucket's external-access allow-list. See [storage.md](https://tarout.sa/docs/for-ai/storage.md). If the folder is on GitHub and the final envelope reports `data.source.pushToDeploy: false` (the org has no GitHub connection that can read the repo), run `data.source.next` in the same turn: `tarout providers github connect --wait --app <app>` opens the Tarout GitHub setup page, waits until GitHub can read the repo, and binds the app.

```sh
tarout deploy --wait --database postgres
```

```sh
tarout providers github connect [--wait] [--app <app>] [--repo owner/name] [--branch <branch>] [--timeout <seconds>] [--no-open]
```

Without `--wait` it opens the setup page and returns. With `--wait` it polls until GitHub is connected (with `--repo` or `--app`: until it can read that repo, 480 seconds by default). With `--app` it then binds the app to this folder's GitHub remote and checked-out branch.

```sh
tarout deploy:status <app-id-or-name>
tarout deploy:list <app-id-or-name> [-n <count>]
tarout deploy:logs <deployment-id> [--follow]
tarout deploy:rollback <app-id-or-name> [--to <deployment-id> | --previous] [--wait]
tarout deploy:cancel <app-id-or-name>
```

Agent confirmation rules:

- Confirm before rollback, cancel, or delete operations.
- Warn before any non-default region request.
- Ask before overwriting a configured app source with the current directory.

## Applications

```sh
tarout apps list
tarout apps create [name]
tarout apps info <app-id-or-name>
tarout apps open <app-id-or-name>
tarout apps delete <app-id-or-name>
```

`tarout apps create` prompts for a name when omitted.

## Project Linking

```sh
tarout link [app-id-or-name]
tarout status
tarout unlink
```

The project link is stored in `.tarout/project.json`.

## Environment Variables

```sh
tarout env <app-id-or-name> list [--reveal]
tarout env <app-id-or-name> set KEY=VALUE [--no-secret]
tarout env <app-id-or-name> unset KEY
tarout env <app-id-or-name> pull [--output .env] [--reveal]
tarout env <app-id-or-name> push [--input .env] [--replace]
tarout env <app-id-or-name> reveal KEY
```

Setting the variables the app needs to run (generated secrets, `DATABASE_URL` wiring) is part of the deploy - do it and say so. Ask the user only before revealing or pulling existing secret values.

## Databases

```sh
tarout db list
tarout db create [name] --type postgres
tarout db info <db-id-or-name>
tarout db connect <db-id-or-name>
tarout db sql <db-id-or-name> "<sql>"
tarout db delete <db-id-or-name>
```

Create the database the code needs as part of the deploy - announce it, don't ask. Ask only before **deleting** databases. Tier changes and backups are in [database.md](https://tarout.sa/docs/for-ai/database.md).

## Storage and Servers

```sh
tarout storage list
tarout servers list
```

## Billing and Subscription

```sh
tarout billing status
tarout billing plans
tarout billing upgrade [plan] [options]
tarout billing confirm <orderId>
tarout billing wait <orderId> [--timeout 600]
tarout billing cancel
tarout billing resume
tarout billing addon:add <addon> [--quantity n]
tarout billing addon:remove <addon>
tarout billing addon:buy <addon> [--quantity n]
tarout billing plan:cancel-pending
```

`tarout billing upgrade` is the new-customer onboarding journey. Agents pass every input via flags so no `needs_input` event has to round-trip:

| Option | Description |
|--------|-------------|
| `[plan]` (positional) | Plan key to switch to |
| `--plan <key>` | Flag alias for the positional arg (use either) |
| `-q, --quantity <n>` | Plan quantity for multi-slot plans (e.g. `shared`) |
| `--billing-period <period>` | `monthly` (default) or `yearly` (10× monthly, 2 months free) |
| `--addon <key[:qty]>` | Repeatable bundled addon (e.g. `--addon db.standard:2 --addon storage.gb:10`; `storage.gb` quantity is GB of storage capacity) |
| `-w, --wait` | Poll `subscription.pollCheckoutStatus` after creating checkout until `PAID/FAILED/EXPIRED` |
| `--timeout <seconds>` | Max wait time for `--wait` (default 600) |
| `--no-open` | Don't auto-launch the browser; the agent opens the URL itself |
| `-y, --yes` | Skip the "Switch to plan X?" confirm prompt |

The result envelope is one of:
- `{ success: true, data: { applied: true, status: "applied" } }` - free upgrade or stored payment method.
- `{ success: true, data: { status: "deferred" } }` - downgrade staged for period rollover.
- `{ success: true, data: { status: "payment_required", paymentUrl: "...", orderId: "..." } }` - agent opens `paymentUrl` for the user, then runs `tarout billing wait <orderId>` to confirm.

`billing cancel`, `billing addon:add`, `billing addon:remove`, `billing addon:buy`, and `billing plan:cancel-pending` all respect `--yes` to skip their confirms, or emit `needs_input` events under `--json` / `--non-interactive`.

## Account and Organization

```sh
tarout account
tarout orgs list
tarout orgs switch <org>
tarout envs list
tarout envs switch <environment>
```

## Global Flags

| Flag | Description |
|------|-------------|
| `--json` | Machine-readable JSON output; missing inputs emit `needs_input` events + exit 6 |
| `-y, --yes` | Skip confirmation prompts (overrides annotated `confirm()` prompts) |
| `--non-interactive` | Strict mode: refuse the inquirer TTY fallback even outside `--json`; any annotated prompt without an answer emits `needs_input` + exit 6 |
| `-q, --quiet` | Suppress non-essential output |
| `-v, --verbose` | Extra debug output |
| `--no-color` | Disable colored output |
| `--global-auth` | Ignore this project's `.tarout/auth.json` and use the machine-wide login for one command |

## Authentication

Credentials are **per project**: `tarout login` writes `./.tarout/auth.json`
(mode `0600`, git-ignored, excluded from deploy archives) and the CLI resolves it
by walking up from the working directory.

```sh
tarout login --token <api-token>   # headless: store a key for this project
tarout login                       # browser approval, same destination
tarout login --global              # machine-wide instead (CI images, shared MCP)
tarout whoami --json               # "scope": project | global | env | none
tarout token:create                # mint a new API key for the current account
tarout logout                      # removes this project's credential
tarout logout --global             # signs out machine-wide and revokes the key
```

## CI/CD

Run the same headless login in the checkout step:

```sh
tarout login --token <api-token>
tarout deploy <app-id-or-name> --wait --json
```

For non-interactive scripts, pass explicit app IDs and use `--json`. Add
`--non-interactive` so a missing answer fails fast instead of waiting on a TTY.

---

## Every Tarout agent guide

- [Start Here (Agents)](https://tarout.sa/docs/for-ai/start.md)
- [Overview](https://tarout.sa/docs/for-ai.md)
- [Deploying an app](https://tarout.sa/docs/for-ai/deploy.md)
- [Databases](https://tarout.sa/docs/for-ai/database.md)
- [Object storage](https://tarout.sa/docs/for-ai/storage.md)
- [Custom domains](https://tarout.sa/docs/for-ai/domains.md)
- [Plans and upgrades](https://tarout.sa/docs/for-ai/billing.md)
- [Troubleshooting](https://tarout.sa/docs/for-ai/troubleshoot.md)
- [Agent Onboarding](https://tarout.sa/docs/for-ai/onboarding.md)
- [CLI JSON Schema](https://tarout.sa/docs/for-ai/cli-json-schema.md)

Whole corpus in one file: https://tarout.sa/llms-full.txt · index: https://tarout.sa/llms.txt
Any docs page is raw markdown at the same URL + `.md`. Short link to the entry point: https://tarout.sa/deploy.md
