# JSON and automation

Source: https://docs.myhub.host/automation

Use `--json` when a script or agent needs structured results. MCP returns the same result format.

## Deploy and verify

From the project folder:

```sh
hub deploy --json
```

The result means the release was **accepted**, not that it is running. Read `data.target` and `data.release.number`, then check that release:

```sh
hub app my-app status --release 3 --json
```

Replace the app and release number with the returned values. Poll every few seconds until `running`, `failed`, or `superseded`. Only `running` confirms a successful deployment.

Then get the URL and service state:

```sh
hub app my-app status --json
```

## Read serving and latest releases

In `hub apps --json`, each entry in `data.apps` has a `release` for the serving release, or `null` if none has run. `hub app my-app status --json` uses the same meaning for `data.release`. A distinct newer attempt appears as `latestRelease`; it is `null` when there is no newer attempt.

For example, if release 1 serves and release 2 fails, `release.number` is `1` and `latestRelease.number` is `2`, with status `failed`. Check `latestRelease` for deployment failures without mistaking them for the serving release's state.

With `status --release 3`, `data.release` is the requested release 3. Use this exact-release lookup to verify a deployment, rollback, or environment change.

## Wait for lifecycle operations

Start, stop, restart, and suspend wait for completion by default, including CLI JSON and MCP. To return before completion:

```sh
hub app my-app restart --no-wait --json
hub app my-app runtime --operation ID --json
```

Replace `ID` with `data.operation.id` from the first response. Poll the same app and instance until `data.operation.status` leaves `queued` or `running`. Only `succeeded` confirms completion. Inspect `failed`, `expired`, or `unknown` results before retrying; an unknown result does not mean the action never happened.

For MCP, pass `wait: false` to `hub_app_start`, `hub_app_stop`, `hub_app_restart`, or `hub_app_suspend`:

```json title="hub_app_restart arguments"
{ "target": "my-app", "wait": false }
```

Poll the returned operation ID with the read-only `hub_app_runtime` tool:

```json title="hub_app_runtime arguments"
{ "target": "my-app", "operation": "123e4567-e89b-42d3-a456-426614174000" }
```

Runtime policy changes use `hub_app_runtime_set` and still return an operation ID to poll. See [runtime and sleep](https://docs.myhub.host/deploy/runtime) for policy settings and permissions.

## Handle a failure

```sh
hub app my-app logs --build --release 3 --tail 100 --json
```

Use the log to fix the cause. Check `truncated` before assuming you have the complete output.

Commands return `ok` and either `data` or an `error` with `code`, `message`, and an optional `hint`. Errors exit nonzero. Branch on `error.code`; do not parse human-readable output.

After a timeout, check release history before retrying: Hub may already have accepted the request. Verify releases returned by rollback and environment changes the same way.

## Errors that need action

| `error.code`           | What to do                                                                                                                                                                                                                                                                          |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `needs_choice`         | The requested pushed source is unavailable, for example because the branch has never been pushed, the remote is not GitHub, or HEAD is detached. Push a branch to GitHub, or choose `--local` if uploading local files matches the intended source. Do not switch sources silently. |
| `github_auth_required` | Open the returned installation link, approve GitHub access, then retry. The message distinguishes private-repository read access from push-to-deploy webhooks. Public repositories need no read grant; watching requires a webhook grant.                                           |
| `cli_outdated`         | The platform requires a newer CLI. Follow `error.hint` to update, then retry. The CLI exits with code `3`. Disabling update checks does not bypass the platform's minimum version.                                                                                                  |

## Deploy on every push

For continuous deployment, [connect GitHub with watching enabled](https://docs.myhub.host/deploy/github#deploy-on-every-push):

```sh
hub deploy --git owner/repository --watch --json
```

Watching requires a GitHub webhook grant, even for public repositories. Once enabled, Hub deploys pushes without requiring a CLI login in each CI job. New or replacement repositories default to watching off; omitting `--watch` preserves the setting for the same repository. Use `--no-watch` to disable it explicitly.

For scripts on your own machine, run `hub login` once and protect its saved credentials.

[CLI reference](https://docs.myhub.host/cli) · [MCP explorer](https://docs.myhub.host/mcp/explorer)