# Output and errors

What every command prints, how its arguments are read, and the coordinate space the screen commands share.

Every command prints exactly one line of JSON on stdout and exits, except `mcp`, which speaks JSON-RPC on stdout until stdin closes ([MCP server](https://karagozmcp.com/docs/mcp/)). The samples on this site are indented for reading; Karagöz prints each one on a single line.

- **Success:** the command’s result object, exit code `0`.

- **Failure:** an error object, exit code `1`:

  ```json
  {
    "error": {
      "code": "DEVICE_NOT_FOUND",
      "message": "device 'nosuch' from --device matches no device id or name. Listed: emulator-5554 (Medium_Phone_API_36.1)."
    }
  }
  ```

  The same message goes to stderr as `karagoz: <message>`. It can span more than one line when it quotes adb or Node output; the stdout line never does.

Branch on `error.code`, not on the message. Messages are for people and can change. Every code is on [Error codes](https://karagozmcp.com/docs/error-codes/).

[`INSTALL_FAILED`](https://karagozmcp.com/docs/error-codes/#install-failed) and [`UNINSTALL_FAILED`](https://karagozmcp.com/docs/error-codes/#uninstall-failed) add a `reason` field with the platform’s own code for the failure. No other code has it. Their rows say what `reason` holds on each target; on Android it is Android’s code:

```json
{
  "error": {
    "code": "INSTALL_FAILED",
    "message": "adb: failed to install /Users/me/app-v1.apk: Failure [INSTALL_FAILED_VERSION_DOWNGRADE: Downgrade detected: Update version code 1 is older than current 2]",
    "reason": "INSTALL_FAILED_VERSION_DOWNGRADE"
  }
}
```

On success, stderr also carries adb’s own notices, such as `* daemon started successfully` when the adb server was not running. That first call takes about 3 s longer.

`karagoz --version` prints the version as plain text and exits `0`. It wins over any command: `karagoz devices --version` prints the version.

## Arguments

- Options can appear anywhere, before or after the command name. A repeated option keeps its last value.
- There are no short flags.
- A value that starts with `-` is read as an option. `--device=-x` passes it as a value. A positional that starts with `-` goes after `--`, with options before it: `karagoz text --device emulator-5554 -- -5`.
- An empty value (`--out=`) is refused.
- An option the command does not take is refused: `'devices' does not take the option '--device'`.

All of these fail with [`INVALID_ARGS`](https://karagozmcp.com/docs/error-codes/#invalid-args) before any device is contacted.

## Coordinates

[`screenshot`](https://karagozmcp.com/docs/commands/screenshot/) pixels, [`ui-tree`](https://karagozmcp.com/docs/commands/ui-tree/) bounds and the [`tap`](https://karagozmcp.com/docs/commands/tap/) / [`swipe`](https://karagozmcp.com/docs/commands/swipe/) coordinates share one space: physical pixels of the current screen orientation, origin top left. A node’s `bounds` of `[581,1905,754,2100]` can be tapped at its center, `(667.5, 2002.5)`, and that point is the same pixel in the screenshot. Decimals are allowed.

On iOS:

- On a simulator with Xcode 27, the screenshot and the tree follow the interface orientation. With Xcode 26, the screenshot is the panel in portrait, whatever the interface orientation.
- `ui-tree` bounds are the element’s frame in points times `scale`.
- `tap` and `swipe` take the same pixels. Karagöz turns them for the interface orientation, and takes a `null` rotation as portrait.

`screenshot` reports `scale` (physical pixels per density-independent pixel on Android, per point on iOS) and `logical` size so a caller can convert to dp or points.
