# karagoz doctor

Reports which adb Karagöz uses, its version, every other adb it could use, and how to install platform-tools when adb is missing or too old.

- Android emulator Done
- Android device Done
- iOS simulator Done
- iOS device Done

## Usage

```console title="~/app"
karagoz doctor
```

On macOS it also reports:

- the Xcode the simulator commands use: its folder and version, `simctl`, `swiftc`, `devicectl` and the helper cache, and what to fix
- the Apple teams Karagöz’s runner can be signed with, and the runner builds this Mac has
- the `xcodebuild`, usbmuxd socket, `tar` and `log` the iPhone commands need

It changes nothing. No options.

## Examples

```console title="~/app"
$ karagoz doctor
{"adb":{"status":"ok","source":"PATH","path":"/opt/homebrew/bin/adb","version":"37.0.0-14910828","candidates":[{"source":"ANDROID_HOME","status":"unset"},{"source":"ANDROID_SDK_ROOT","status":"unset"},{"source":"PATH","status":"ok","path":"/opt/homebrew/bin/adb","version":"37.0.0-14910828"},{"source":"default","status":"ok","path":"/Users/me/Library/Android/sdk/platform-tools/adb","version":"36.0.2-14143358"}]}}
```

## Output

```json
{
  "adb": {
    "status": "ok",
    "source": "PATH",
    "path": "/opt/homebrew/bin/adb",
    "version": "37.0.0-14910828",
    "candidates": [
      { "source": "ANDROID_HOME", "status": "unset" },
      { "source": "ANDROID_SDK_ROOT", "status": "unset" },
      {
        "source": "PATH",
        "status": "ok",
        "path": "/opt/homebrew/bin/adb",
        "version": "37.0.0-14910828"
      },
      {
        "source": "default",
        "status": "ok",
        "path": "/Users/me/Library/Android/sdk/platform-tools/adb",
        "version": "36.0.2-14143358"
      }
    ]
  }
}
```

The exit code is `0` whenever the report is printed, with adb or Xcode missing or broken as well.

On macOS the line also carries `xcode`.

- `adb` object: Which adb Karagöz uses, its version, every other adb it could use, and how to install platform-tools when adb is missing or too old.
- `adb.status` string: `ok`, `outdated` or `failed` (see the Status table below): the status of the candidate Karagöz uses. `missing`: no candidate can be used.
- `adb.source` string: Copied from the candidate Karagöz uses, when it has one.
- `adb.path` string: Copied from the candidate Karagöz uses, when it has one.
- `adb.version` string: Copied from the candidate Karagöz uses, when it has one.
- `adb.candidates` array: The four places Karagöz looks, in lookup order (see [Requirements](https://karagozmcp.com/docs/requirements/#adb)).
- `adb.candidates[].source` string: One of `ANDROID_HOME`, `ANDROID_SDK_ROOT`, `PATH`, or `default` for Android Studio's default SDK.
- `adb.candidates[].status` string: One of `ok`, `outdated`, `failed`, `missing` or `unset`: see the Status table below.
- `adb.candidates[].path` string: When known: the file Karagöz would run. For `PATH`, the path adb prints for itself in `adb version`, so it is absent when adb printed none. See below.
- `adb.candidates[].version` string: With `ok` and `outdated`: the `Version` line of `adb version`, as printed. See below.
- `adb.message` string: Copied from the candidate Karagöz uses, when it has one.
- `adb.install` string: Only when `status` is not `ok`: how to install platform-tools on this OS, the same text [`ADB_NOT_FOUND`](https://karagozmcp.com/docs/error-codes/#adb-not-found) prints.
- `adb.candidates[].message` string: With `failed` and `outdated`: why, cut at 300 characters.
- `xcode` object: macOS only: the Xcode the iOS commands use, and what the iPhone commands need from this Mac.
- `xcode.status` string: One of `ok`, `outdated`, `failed` or `missing`: see the `xcode.status` table below.
- `xcode.source` string: Which rule picked the developer folder, in the commands' order: `DEVELOPER_DIR`, `xcode-select` (`/var/db/xcode_select_link`), or `default` (`/Applications/Xcode.app/Contents/Developer`). Absent when none is there.
- `xcode.path` string: With `source`: the developer folder.
- `xcode.version` string: From that Xcode's `version.plist`, when it has one: `27.0`.
- `xcode.build` string: From that Xcode's `version.plist`, when it has one: `27A266a`.
- `xcode.message` string: When `status` is not `ok`: the first entry's message in the order `simctl`, `swiftc`, `devicectl`, `helper`, or for `outdated`, which commands need a newer Xcode.
- `xcode.simctl` object: An entry: `status`, `path` when known, and `message` when not `ok`.
- `xcode.simctl.status` string: See the Entry status table below.
- `xcode.simctl.path` string: When known: the `simctl` file.
- `xcode.simctl.message` string: When `status` is not `ok`: why. With `missing`, the text the command itself would fail with.
- `xcode.simctl.version` string: Unless `simctl` is `missing`: this Mac's CoreSimulator version.
- `xcode.swiftc` object: An entry: `status`, `path` when known, and `message` when not `ok`.
- `xcode.swiftc.status` string: See the Entry status table below.
- `xcode.swiftc.path` string: When known: the `swiftc` file.
- `xcode.swiftc.message` string: When `status` is not `ok`: why. With `missing`, the text the command itself would fail with.
- `xcode.devicectl` object: An entry: `status`, `path` when known, and `message` when not `ok`.
- `xcode.devicectl.status` string: See the Entry status table below.
- `xcode.devicectl.path` string: When known: the `devicectl` file.
- `xcode.devicectl.message` string: When `status` is not `ok`: why.
- `xcode.helper` object: An entry: `status`, `path` when known, and `message` when not `ok`.
- `xcode.helper.status` string: See the Entry status table below.
- `xcode.helper.path` string: When known: the helper file.
- `xcode.helper.message` string: When `status` is not `ok`: why.
- `xcode.signing` object: The teams [`install-runner`](https://karagozmcp.com/docs/commands/install-runner/) can sign with.
- `xcode.signing.status` string: `ok` with `teams`, `missing` with a `message`, or `failed` when Xcode's preferences could not be read.
- `xcode.signing.teams` array: With `ok`: an array of `{id, name, free}` (`free` for a Personal Team).
- `xcode.signing.teams[].id` string: With `ok`: an array of `{id, name, free}` (`free` for a Personal Team).
- `xcode.signing.teams[].name` string: With `ok`: an array of `{id, name, free}` (`free` for a Personal Team).
- `xcode.signing.teams[].free` boolean: With `ok`: an array of `{id, name, free}` (`free` for a Personal Team).
- `xcode.signing.message` string: With `missing`: no Apple account in Xcode, or an account whose teams Xcode has not saved yet (open a project's Signing & Capabilities tab once, or pass `--team`).
- `xcode.iosRunner` object: The runner builds for this Karagöz and Xcode.
- `xcode.iosRunner.status` string: `ok` with `path` and `teams`, `not built`, or `failed` with a `message`.
- `xcode.iosRunner.path` string: With `ok`, and with `not built` when an Xcode is selected.
- `xcode.iosRunner.teams` array: With `ok`: one build per team.
- `xcode.iosRunner.message` string: With `failed`: the cache folder is not yours, or Karagöz's runner sources are missing.
- `xcode.xcodebuild` object: The `xcodebuild` in the developer folder, which builds the runner (`install-runner`) and starts it (`ui-tree` and input on an iPhone). An entry like `swiftc`.
- `xcode.xcodebuild.status` string: See the Entry status table below.
- `xcode.xcodebuild.path` string: When known: the `xcodebuild` file.
- `xcode.xcodebuild.message` string: When `status` is not `ok`: why. With `missing`, `install-runner`'s own text.
- `xcode.usbmuxd` object: The socket the runner and iPhone `logs` connect to. Read without connecting.
- `xcode.usbmuxd.status` string: See the Entry status table below.
- `xcode.usbmuxd.path` string: The socket: `/var/run/usbmuxd`, or `USBMUXD_SOCKET_ADDRESS` in its `UNIX:<path>` form.
- `xcode.usbmuxd.message` string: The commands' text: `cannot reach usbmuxd at <path> (<code>)`.
- `xcode.tar` object: The `tar` iPhone `logs` runs, found on `PATH` as the command finds it (no `PATH`: `/usr/bin:/bin`).
- `xcode.tar.status` string: See the Entry status table below.
- `xcode.tar.path` string: Not with `missing`: the `tar` found on `PATH`.
- `xcode.tar.message` string: When `status` is not `ok`: why. With `missing`, the command's text: `tar not found on PATH`.
- `xcode.log` object: The `log` iPhone `logs` runs, found on `PATH` as the command finds it (no `PATH`: `/usr/bin:/bin`).
- `xcode.log.status` string: See the Entry status table below.
- `xcode.log.path` string: Not with `missing`: the `log` found on `PATH`.
- `xcode.log.message` string: When `status` is not `ok`: why. With `missing`, the command's text.

| Status     | Means                                                                                                                                                                                  |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`       | `adb version` exited `0` and reported platform-tools 30.0.0 or newer.                                                                                                                  |
| `outdated` | `adb version` exited `0` and reported a version below 30.0.0. [`install`](https://karagozmcp.com/docs/commands/install/) fails; the other commands still work. Debian 12 ships 29.0.6. |
| `failed`   | Something is there but cannot be used: it did not start, exited non-zero, did not answer within 10 s, or printed no `Version` line. The message says which.                            |
| `missing`  | Nothing at that location. For `PATH`: no `adb` on `PATH`, or on macOS and Linux only ones that fail to start with `ENOENT` (see Notes).                                                |
| `unset`    | No location to check: the variable is unset or empty. For `default`: Windows without `LOCALAPPDATA`.                                                                                   |

| `xcode.status` | Means                                                                                                                                                                                                                                  |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`           | `simctl`, `swiftc` and `devicectl` are `ok`, and the helper is `ok` or `not built`. `signing`, `iosRunner`, `xcodebuild`, `usbmuxd`, `tar` and `log` do not count: a Mac without iPhones needs none of them. Check their own `status`. |
| `outdated`     | As `ok`, with an Xcode below 27. `tap`, `swipe` and `key` return [`NOT_SUPPORTED`](https://karagozmcp.com/docs/error-codes/#not-supported) on a simulator; the other commands work.                                                    |
| `failed`       | `simctl`, `swiftc` or `devicectl` is not `ok`, or the helper is `failed`.                                                                                                                                                              |
| `missing`      | `simctl` and `swiftc` are both `missing`: no Xcode Karagöz can use, such as the Command Line Tools alone.                                                                                                                              |

| Entry status | Means                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`         | `simctl`, `swiftc`, `devicectl`, `xcodebuild`, `tar`, `log`: a file Karagöz can run. `usbmuxd`: a socket Karagöz can read and write. `helper`: built, and a file you own.                                                                                                                                                                                                                                                                             |
| `missing`    | Nothing at `path`. With no developer folder, `swiftc` and `xcodebuild` have no `path` and say no Xcode is selected. `tar` and `log` have no `path`.                                                                                                                                                                                                                                                                                                   |
| `failed`     | There but not runnable: `cannot run <path> (EACCES)`. For `tar` and `log`, the first such file on `PATH` when none after it runs.                                                                                                                                                                                                                                                                                                                     |
| `failed`     | `usbmuxd`: not a socket (`ENOTSOCK`) or not yours to use (`EACCES`).                                                                                                                                                                                                                                                                                                                                                                                  |
| `failed`     | `simctl` and `devicectl`: also when Xcode’s first launch has not finished. The message: `the selected Xcode expects CoreSimulator <version>, this Mac has <version>: open Xcode once to finish installing its components` (CoreDevice for `devicectl`).                                                                                                                                                                                               |
| `failed`     | `simctl` and `devicectl` with `DEVELOPER_DIR` set: also when a newer Xcode installed a newer framework, so that Xcode’s own `simctl` or `devicectl` would run `xcodebuild -runFirstLaunch` on every call. The message: `the Xcode in DEVELOPER_DIR expects CoreSimulator <version> but this Mac has <version> from a newer Xcode, so its simctl runs xcodebuild -runFirstLaunch on every call: point DEVELOPER_DIR at the newest Xcode, or unset it`. |
| `failed`     | `helper`: the cache folder or binary is not yours or not the right type. Delete `~/Library/Caches/karagoz`.                                                                                                                                                                                                                                                                                                                                           |
| `not built`  | `helper` only: the next `ui-tree`, `tap`, `swipe`, `text` or `key` compiles it.                                                                                                                                                                                                                                                                                                                                                                       |

For `PATH`, `adb.candidates[].path` is the symlink as invoked on macOS (`/opt/homebrew/bin/adb`) and the resolved file on Linux. On Windows it is the `adb.exe` found on `PATH`.

`adb.candidates[].version`, and the `adb.version` copied from it, keep the builder’s suffix: digits from Google, `-debian`, `-android-tools`. Debian’s 8.1.0 package prints its package version, `1:8.1.0+r23-8`, and is `outdated`. `1.0.41` in `Android Debug Bridge version 1.0.41` is adb’s protocol number and is not shown.

## Errors

`doctor` fails with [`INVALID_ARGS`](https://karagozmcp.com/docs/error-codes/#invalid-args) for any argument or option (`'doctor' does not take the option '--device'`), and with [`INTERNAL`](https://karagozmcp.com/docs/error-codes/#internal).

## Notes

- What doctor does not show:

  - adb server trouble: only `adb version` runs, on every candidate at once, and it never connects to the server. The other commands report it as [`ADB_TIMEOUT`](https://karagozmcp.com/docs/error-codes/#adb-timeout).
  - a stuck simulator service: for Xcode, doctor reads files, and cannot start the simulator service or Xcode’s first launch. A stuck service shows in the `errors` of [`devices`](https://karagozmcp.com/docs/commands/devices/).
  - a usbmuxd socket that is there but answers nobody: doctor never runs `xcodebuild` and never connects to usbmuxd; only the iPhone commands show it.
  - paired iPhones: `devices` lists them.

- A candidate that is there but fails to start with `ENOENT` (a script whose interpreter is missing, a broken link) is shown `failed`. Karagöz moves on to the next one, as every command does; any other failure stops the lookup at that candidate.

- On macOS and Linux, a `PATH` candidate that fails with `ENOENT` is shown `missing` instead: `adb` runs by name there, and the error does not say which file failed.

- An invalid `ANDROID_ADB_SERVER_PORT` makes `adb version` itself fail, so every `adb` found is `failed` with adb’s message: `adb: $ANDROID_ADB_SERVER_PORT must be a positive number less than 65535: got "abc"`.

- Windows and Linux were not run.

## MCP equivalent

MCP equivalent `doctor {}` [MCP tools](https://karagozmcp.com/docs/mcp/#tools)

No arguments.

## Related commands

- [karagoz install-runner](https://karagozmcp.com/docs/commands/install-runner/): Signs the runner with one of the teams that xcode.signing lists.
