# Command line

Where the silan command lives, how to put it on your PATH, a five-command walkthrough and its exit codes.

`silan` is the engine's command-line client. It lists devices, looks at a screen, taps, types, waits, claims devices, answers approvals and runs Silan's MCP server. It ships inside the app and finds the engine on this Mac by itself. Status: **supported**. Proven on an iPhone 11 (iOS 27) on a cable with `silan devices`, and on this Mac with no phone for keys and `silan mcp`. The [command line reference](/reference/cli/) lists every command and option.

<figure class="shot"><img src="/media/cli-devices.webp" alt="Terminal: silan devices lists an iPhone 11 on a cable as ready, with its id, iOS version and kind." width="1180" height="359" loading="lazy" /><figcaption>Terminal: silan devices lists an iPhone 11 on a cable as ready, with its id, iOS version and kind.</figcaption></figure>

## Setup

1. **Find the command.** It is at `/Applications/Silan.app/Contents/Helpers/silan`. Nothing puts it on your PATH.
2. **Call it by its path, or link it.** A link in a folder on your PATH works, and `~/.local/bin` is also where Silan's plugins and examples look for it:

   ```sh
   mkdir -p ~/.local/bin
   ln -s /Applications/Silan.app/Contents/Helpers/silan ~/.local/bin/silan
   ```

   Or set a variable for one session: `SILAN=/Applications/Silan.app/Contents/Helpers/silan`, then `$SILAN devices`.
3. **No key to set up.** On this Mac `silan` reads the engine's port and its local key file from `~/Library/Application Support/Silan/engine.json`. Only your user can read that file. To reach another engine or use another key, set `--url` or `SILAN_URL`, and `--key` or `SILAN_API_KEY`. If the engine is stopped, `silan` wakes it.
4. **Pick the output.** Add `--json` before the command to get the engine's answer as JSON instead of words: `silan --json devices`.

## Try it

Five commands, start to finish, on a phone or a simulator. Take the device id from the first one.

```sh
silan devices
silan observe ios:00008120-001A2B3C4D5E6F70 --elements interactive
silan launch ios:00008120-001A2B3C4D5E6F70 com.apple.Preferences
silan tap ios:00008120-001A2B3C4D5E6F70 --text "General"
silan wait ios:00008120-001A2B3C4D5E6F70 --text "About" --timeout 5000
```

`devices` lists each device with its id, name and state. `observe` prints the elements you can act on, each with a ref such as `e12@snap_7f3a`, and `--save FILE` keeps the screenshot. `launch` opens Settings. The first launch of an app that is not on your allow list waits for your yes in Silan. `tap` presses the row that says General. `wait` returns as soon as About is on screen, or fails when 5 seconds pass.

A target is `--text`, `--id`, `--role` or `--description`, with `--match exact|contains|regex|caseInsensitive` and `--index N`, or `--ref` from the last `observe`, or `--at X,Y`. To stop every agent on every device from the shell, run `silan stop`, and `silan resume` to let held tasks go on.

### Exit codes

| Code | Meaning |
|---|---|
| `0` | Success |
| `1` | The command failed |
| `2` | Wrong usage. `silan help` prints the usage |
| `3` | No engine answered |
| `4` | The engine refused the key |

## Limits

- `silan keys create`, `keys list` and `keys revoke` are in the usage, but making or revoking keys needs the admin right, which no key has, so the engine answers `403`. Make and revoke keys on the **Connections** page.
- `silan run` for flows is in the usage but answers `the scenario engine is not available in this engine` on the current release (seen 4 Nov 2026 against a real engine). Run flows from the app and collect `junit.xml`, `report.json` and `index.html` from the run folder, see [Export a JUnit report](/guides/export-a-junit-report/).
- Taps, typing and the element tree need a phone on the Developer way, a simulator or an emulator. On the Simple way there is no element list, so `observe` has no elements and a target by text is not available.
- A person's own step holds a device for 30 seconds after it, and the `silan` command counts as you. An agent's call in that time answers `DEVICE_LEASED`.
- `silan` needs the Silan app and its engine on this Mac. There is no headless or CI use.
- `silan mcp` with no key speaks to the engine over XPC and asks you on the first call. With `--key` or `SILAN_API_KEY` it uses the HTTP listener and asks nothing. See [Any MCP client](/integrations/any-mcp-client/).

:::note[Proof]
Proved on an iPhone 11 (iOS 27) on a cable, 14 Oct 2026, by a Silan worker: `silan devices` from `engine.json` alone, with no `SILAN_URL` and no `SILAN_API_KEY`. Run `20261014-154515-65263`. On this Mac with no phone, 14 Oct 2026: `silan devices` still worked with the local key after a key made in the app was revoked. Run `20261014-190535-89037`. Source: verify-silan feature map, api and connections.
:::