# Scripting

## JSON output

`--json` puts the result on stdout and nothing else. Progress, warnings, and errors all go to stderr, so a pipeline never has to filter them out:

```bash
layer --json whoami | jq -r .workspace
layer --json generate image -p "..." | jq -r '.files[].path'
```

`--quiet`/`-q` suppresses the stderr progress as well, for a log you want to stay quiet on success.

## Exit codes

Part of the CLI’s published contract: these may gain members, but an existing code never changes meaning.

| Code | Name                  | Meaning                                                         |
| ---- | --------------------- | --------------------------------------------------------------- |
| 0    | OK                    | The command succeeded                                           |
| 1    | ERROR                 | Anything without a more specific code                           |
| 2    | USAGE                 | Unknown flag, missing argument, or a bad value                  |
| 3    | AUTH                  | Not signed in, credentials expired, or the token lacks access   |
| 4    | INSUFFICIENT\_BALANCE | The workspace cannot pay for the run, or \--max-cost refused it |
| 5    | INVALID\_INPUT        | The request reached the API and was rejected as invalid         |
| 6    | CONTENT\_POLICY       | Refused by the content policy                                   |
| 7    | TIMEOUT               | The run did not finish inside the time allowed                  |

A caller can branch on those without reading the message:

```bash
layer generate image -p "$PROMPT" -o out/
status=$?
case "$status" in
  3) echo "re-authenticate: layer login" >&2 ;;
  4) echo "top up Creative Units" >&2 ;;
  6) echo "prompt refused by the content policy" >&2 ;;
esac
exit "$status"
```

## Unattended runs

Set `LAYER_API_KEY` to a personal access token and the CLI never asks for a browser or reads a stored credential:

```bash
env:
  LAYER_API_KEY: ${{ secrets.LAYER_API_KEY }}
  LAYER_WORKSPACE: my-studio
```

Pair it with `LAYER_WORKSPACE` (or a committed `layer.toml`) so the job does not depend on a stored profile at all, and `--quiet` to keep progress out of the build log. See [configuration](/docs/cli/configuration) for the full precedence chain.

## Long jobs

Submit now, collect later, so a slow video render does not hold a job open:

```bash
id=$(layer --json generate video --no-wait -p "..." | jq -r .inference_id)
# … other work …
layer generate status "$id" --wait -o out/
```

Tip

Price a batch before you start it: every generation prints its estimate, and `--max-cost` turns a ceiling into a hard failure rather than a surprise. See [Creative Units](/docs/creative-units).
