Skip to main content

JSON output and exit codes

Each command accepts --json. A script, a tool, and an AI agent can read the same output.

  • With --json, stdout holds one JSON value and nothing else.
  • Progress lines and warnings go to stderr, also without --json.
  • Each path is absolute. Each date is an ISO 8601 string.

Exit codes​

CodeMeaning
0Success.
1A failure. stdout is empty, and stderr holds the message with the fix.
2A usage error, for example an unknown option or a missing argument.

These commands print their JSON and also exit with 1:

CommandWhen
devhub sync --jsonA project failed. The JSON shows which one.
devhub devices --jsonEach device tool failed. The JSON has the warnings.
devhub match --jsonNo stored build matches.
devhub whoami --jsoneas-cli has no login, or does not run.
devhub doctor --jsonA check has the status fail.

The output of each command​

CommandPrints
devhub sync --jsonSyncReport: dryRun, and for each project its status, its profiles, its builds with the result of each build, and its warnings.
devhub list --jsonBuildList: store, builds, incomplete, and unreadable.
devhub where <id> --json{ "id": string, "path": string }
devhub devices --jsonDeviceReport: devices and warnings.
devhub install <id> --jsonInstalledBuild: id, path, and the device.
devhub match --jsonMatchReport: project, fingerprintVersion, and for each platform its hash and its matches.
devhub ui --json{ "url": string, "port": number }. The server then runs until Ctrl+C.
devhub whoami --jsonWhoamiReport: state, cli, and user or message.
devhub doctor --jsonDoctorReport: checks, and for each check its id, label, status, detail, and fix.

The full TypeScript types of each output are in llms.txt.

A build in the list​

Each build in devhub list --json and in the matches of devhub match --json has these fields:

FieldValue
idThe full build ID.
source"eas" for a build that devhub sync downloaded, or "local" for a build that npx expo run:* made.
pathThe absolute path of the build file.
sizeThe size of the file, in bytes.
sha256The SHA-256 hash of the file.
storedAtThe date on which DevHub stored the build.
installProblemWhy devhub install refuses the build on this system, with the fix. The text says "this build" and names no ID, because the record has id. Absent when it can install the build.
easAn EAS build: the record of eas build:list --json with no change.
localA local build: the platform, the fingerprint, the variant, the project folder, and the app values.

eas-cli drops each field with a null value, so an absent field in eas means "no value". The eas record can have more fields than the types name.

A device​

{
"platform": "android",
"kind": "physical",
"id": "R5CT21ABCDE",
"name": "R5CT21ABCDE",
"state": "unauthorized",
"ready": false,
"problem": "Unlock the device, and accept the USB debugging prompt on it."
}
FieldValue
platform"android" or "ios".
kind"emulator", "physical", or "simulator".
idThe adb serial, or the simulator UDID.
stateThe state as the device tool prints it.
readytrue when DevHub can install a build on the device now.
problemWhy DevHub cannot install on the device now, and the fix.
osVersionThe iOS version of a simulator.

Example: install the newest Android build of a project​

id=$(devhub list --json | jq -r '[.builds[] | select(.source == "eas" and .eas.platform == "ANDROID" and .eas.app.slug == "trail-app" and (has("installProblem") | not))][0].id')
devhub install "$id" --json

devhub list sorts the builds of each project newest first, so the first build that fits is the newest one.