Skip to content

Scripting

--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:

Terminal window
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.

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:

Terminal window
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"

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

Terminal window
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 for the full precedence chain.

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

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