# Agents, CI, and scripts

Use Deplane from AI agents, CI pipelines, and scripts with a token, JSON output, and stable exit codes.

The CLI works the same for people and programs. Every command supports `--json` and `--yes`, never prompts without a terminal, and exits with a documented code.

## Get a token

Create a CI token from your own machine:

```sh
deplane tokens create github-actions
```

Creating a token needs a fresh confirmation with your passkey from the last 5 minutes. In a terminal, the CLI opens your browser, you tap your passkey, and the command continues. The token is printed once. Store it in your CI's secret store.

Then set it in the environment where the CLI runs:

```sh
export DEPLANE_TOKEN=dpl_...
deplane deploy --json --yes
```

About CI tokens:

- A CI token belongs to your organization and acts as you.
- It lasts 90 days by default. Choose 1 to 365 days with `--expires-in-days`.
- It cannot create tokens, list or revoke other tokens, or run admin commands. It can revoke itself.
- Revoke it any time with `deplane tokens revoke ID`. It stops working at once.
- Tokens start with `dpl_`. If one leaks into a log, `deplane` output and `--debug` hide it as `dpl_[REDACTED]`.

## GitHub Actions example

The deploy step in `.github/workflows/deploy.yml`:

```yaml
- run: npx deplane deploy --json --yes
  env:
    DEPLANE_TOKEN: ${{ secrets.DEPLANE_TOKEN }}
```

Commit `deplane.toml` so the CI run knows which app to deploy, or pass `--app NAME`.

## Rules for programs

- **Use `--json`.** Each command prints exactly one JSON document on stdout. Progress messages and build logs go to stderr. `deplane logs --json` prints one JSON object per line.
- **Use `--yes`.** Commands that destroy or roll back ask for confirmation. Without a terminal, the CLI never asks. Instead the command fails with [confirmation_required](errors.md#confirmation_required), and the fix names the flag to pass: `--yes`.
- **Check the exit code.** It tells you what kind of failure happened, without parsing text.
- **Read `fix`.** Every error has a fix: a sentence that says what to do next, usually with the exact command.

## Exit codes

| Code | Meaning | What an agent should do |
|---|---|---|
| 0 | Success. | Continue. |
| 1 | User error. | Read `fix`, change the command or the project, and try again. |
| 2 | Authentication error. | Check `DEPLANE_TOKEN`, or ask a person to log in or confirm. |
| 3 | The build failed. | Read the build log on stderr and `fix`, change the code, and deploy again. |
| 4 | The deploy failed. | Run `deplane logs --json` and `deplane status --json`, fix the app, and deploy again. The previous release keeps serving. |
| 5 | Platform error. | Wait and retry. If it persists, report it. |
| 6 | Quota exceeded. | A plan limit was reached (codes starting with `limit_`). Free resources or ask a person to raise the limit. |

## Error shape

With `--json`, a failure prints:

```json
{
  "error": {
    "code": "no_app",
    "message": "This folder has no deplane.toml, so there is no app to deploy.",
    "fix": "Run `deplane launch` to create the app, or pass --app NAME.",
    "exit_code": 1
  }
}
```

`code` is stable. Look it up in [Troubleshooting and error codes](errors.md): each code has its own section at `https://deplane.cloud/docs/errors#CODE`.

## Actions that need a fresh passkey

Some actions need the person to confirm with their passkey in the last 5 minutes: creating a token, inviting or removing a team member, destroying an app, deleting, restoring or switching a database, and every admin command. In a terminal, the CLI opens the browser, waits for the tap, and retries on its own. Destroying an app and deleting, restoring or switching a database each use up their confirmation, so every one of them needs its own tap.

Without a terminal, the CLI cannot do that. It fails with exit code 2 and [step_up_required](errors.md#step_up_required):

```json
{
  "error": {
    "code": "step_up_required",
    "message": "This command needs a fresh confirmation with your passkey, and no terminal is attached.",
    "fix": "Run it in a terminal to confirm in your browser. For 5 minutes after that, most such commands also work from scripts; deleting, restoring and switching need a confirmation each time.",
    "exit_code": 2
  }
}
```

An agent should hand this step to a person. `--yes` does not replace it, and CI tokens are refused these actions with [ci_token_not_allowed](errors.md#ci_token_not_allowed). Deploys, scaling, secrets, logs, and rollbacks never need it.

## A typical agent session

```sh
deplane doctor --json
deplane launch --json --yes
deplane status --json
deplane logs --json --tail 200
deplane secrets set --json DATABASE_URL=postgres://...
deplane rollback --json --yes
```

Each command prints one JSON document and exits with a code from the table above.

## After a deploy

A deploy that succeeded can still be rolled back by Deplane in its first 10 minutes live, if the 5xx errors the app returns spike ([automatic rollback](cli.md#automatic-rollback)). To check, run `deplane releases --json`: a release Deplane made this way has `"automatic_rollback": true` and a description that starts with `Automatic rollback to vN`. Read the logs of the release that spiked before deploying again. To turn it off for an app, run `deplane config --auto-rollback off`.

## Restore a database

Restores never change the original database. Restoring and switching need a [fresh passkey](#actions-that-need-a-fresh-passkey), so a person runs them from a terminal (or the dashboard):

```sh
deplane db backups main --json
deplane db restore main --at -10m --json
deplane db switch main-restored-1442 --from main --json
```

`deplane db restore` waits until the new database is ready (up to 15 minutes); pass `--no-wait` to return at once. See [Databases](databases.md#backups-and-restore).

## AI tools

Claude, ChatGPT, Cursor and other MCP clients can use Deplane without the CLI: see [AI tools (MCP)](mcp.md).

## Docs for agents

- https://deplane.cloud/llms.txt lists every docs page with a one-line description and a link to its Markdown.
- Every docs page is also available as Markdown: add `.md` to its URL. For example, https://deplane.cloud/docs/limits.md.
- The API is described by OpenAPI at https://api.deplane.cloud/v1/openapi.yaml. API errors have the same `code`, `message`, and `fix`, plus a `docs` link and a `request_id`.
