JSON output and automation
Every data-producing CLI command accepts -j, --json and writes a single envelope to stdout:
json
{ "ok": true, "data": <payload> }
{ "ok": false, "error": { "message": "...", "code": "<code>" } }Three properties make this dependable in scripts:
- Stdout is always valid JSON in this mode: spinners and progress messages are suppressed.
- Exit codes are real:
0on success, non-zero on failure,130on Ctrl+C, anddevice execexits with the remote command's code. Pipelines withset -ebehave correctly. - Error codes are stable:
not_found,unauthorized,timeout, … the full contract is in error codes, and the envelope shapes (including the fan-outsummary/results[]form) in the JSON envelope reference.
Field extraction
-f, --field <dot.path> drills into the result so you don't need jq for simple lookups:
bash
thinr device property store-14 information -f hardware.id
thinr product property edge-gateways temperature -f data.celsiusjq recipes
bash
# fail the pipeline on error
thinr device status store-14 --json | jq -e '.ok' >/dev/null
# devices that failed a fleet command
thinr product exec edge-gateways "systemctl is-active app" --json \
| jq -r '.data.results[] | select(.ok | not) | .device'
# version inventory across the fleet
thinr product exec edge-gateways "thinr-agent --version" --json \
| jq -r '.data.results[] | "\(.device): \(.stdout | rtrimstr("\n"))"'Non-interactive environments
Two things change in scripts and CI compared with your terminal:
- Commands that normally prompt for confirmation refuse to run and fail with
needs_confirm; pass-y, --yesexplicitly. - Pick the environment per invocation with
THINR_PROFILE=<name>(or--profile; see global options), instead of relying on the default profile of whoever runs the job.
A CI example
yaml
# GitHub Actions: deploy a config and verify, against the staging profile
- run: npm install -g @thinremote/thinr-cli
- run: |
thinr product push edge-gateways ./config.yaml /etc/app/config.yaml --json
thinr product exec edge-gateways "systemctl restart app && systemctl is-active app" --json \
| jq -e '.data.summary.failed == 0'
env:
THINR_PROFILE: stagingThe token comes from the profile store; provision the runner once with a pre-issued token (see Install the CLI) or bake ~/.config/thinr-cli/config.json into the runner's secrets.
Beyond shell scripts
When the automation grows past a few pipelines, two better tools exist: playbooks for multi-step procedures with check mode and staged rollouts, and the MCP server when the thing driving the fleet is an AI agent rather than a script.