Skip to content

Script the CLI with JSON

Drive alis from a script or a coding agent: get one machine-readable result per command, keep progress separate, and branch on exit codes.

Prerequisites

  • A signed-in CLI with an active account.
  • A shell, or an agent tool that runs a command and captures stdout, stderr and the exit code separately.

Steps

  1. Add --json to every call, and run one standalone command at a time. Pass the working directory with your tool's workdir setting or --cwd; do not wrap the command in a shell chain, pipe or redirect.

    alis --cwd /home/me/alis.build/acme/build/shop/orders/v1 build --json --branch main
    
  2. Parse stdout as one JSON document. It is the result, the final operation, or an error envelope. For long-running commands it is the final operation even when the operation failed, so parse stdout before looking anywhere else:

    JSON
    {"schemaVersion": 1, "name": "operations/<id>", "done": true, "status": "failed", "error": {"…": "…"}, "logsUri": "https://…"}
    
  3. Treat stderr as progress only. Under --json it carries one small NDJSON event per line and never a result:

    {"elapsed":"0:12","operation":"operations/<id>","progress":"Building image neurons/orders-v1"}
    

    There is no final stderr event; stdout arriving is the completion signal.

  4. Branch on the exit code:

    Code Do
    0 Parse the result.
    1 Read the structured failure on stdout (error on the operation, or an envelope), then stderr.
    3 Stop. Show the human the envelope's retry command and run it only after they approve. Never add --approve or --confirm-production yourself.
    4 Have the human run alis login, then retry.
    5 No change (reply_timeout on alis specialist wait). Not a failure.
  5. When stdout is an error envelope, follow its fields:

    JSON
    {"error": {"code": "ENVIRONMENT_SELECTION_REQUIRED", "message": "…", "retry": "alis deploy --json -e <env-id>", "retryArgv": ["…"], "retryCwd": "…", "agent": "…", "details": {}}}
    

    retry is the recovery command, retryArgv and retryCwd its exact arguments and directory, agent the instruction for an automated caller, details structured extras such as the deployment environments to pick from.

  6. Read stdout whole. A streamed result is pruned to what is actionable and a success is under 1 KB, so never pass it through head, tail, grep or 2>/dev/null: you would drop the fields you need. Absent fields mean zero or empty. Add --verbose when you want every field and full progress snapshots.

  7. Verify creations by exit code 0 and the identifiers in the result. If a repeat returns an AlreadyExists envelope, follow its agent field instead of repeating the mutation.

Headless budgets

A headless invocation (--json, or stdin and stdout not a terminal) has a time budget. If a command overruns it, usually because it hit a prompt nobody could answer, it exits 1 with a TIMEOUT envelope whose details.phase names the step. Run its retry once; if it repeats, alis doctor --json carries the command log. ALIS_COMMAND_TIMEOUT=<duration> changes the budget.

Example: build, then act on the result

build.sh
#!/usr/bin/env bash
set -u
out=$(alis build --json --branch main 2>progress.ndjson)
code=$?
case $code in
  0) version=$(printf '%s' "$out" | jq -r .version); echo "built $version" ;;
  3) echo "approval needed:"; printf '%s' "$out" | jq -r .error.retry; exit 3 ;;
  4) echo "run: alis login"; exit 4 ;;
  *) printf '%s' "$out" | jq .error; exit "$code" ;;
esac

The script captures stdout into a variable and stderr into a file, then parses the whole result. It does not pipe alis itself.

Related: Output contract, Exit codes, Run long operations asynchronously.