Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,31 @@ hydrates root and `packages/client` `node_modules` plus
falling back to `npm ci` for missing package installs and ensuring Homebrew
`pkgconf`/`x264` are available for native builds. Its Run action executes
`npm run codex:run`, which builds the CLI and client, saves fresh caches, and
restarts the workspace-local daemon.
restarts the local service.

Run the local daemon:
Run the local service:

```sh
./build/simdeck
./build/simdeck daemon start --port 4311
./build/simdeck -p 4311
```

Running without a subcommand starts a foreground workspace daemon, prints local and LAN HTTP URLs, prints a six-digit pairing code for LAN browsers, and stops when the command exits, when you press `q`, or when you press Ctrl-C. If the always-on service is active on 4310, running without a subcommand or running `simdeck ui` prints the existing service endpoints instead of starting a project daemon. Pass a simulator name or UDID as the only argument to select it by default in the UI. Use `./build/simdeck -d`, `./build/simdeck -k`, and `./build/simdeck -r` as detached start, kill, and restart shortcuts.
Running without a subcommand starts or reuses the background service, prints
local and LAN HTTP URLs, and prints a six-digit pairing code for LAN browsers.
Pass a simulator name or UDID as the only argument to select it by default in
the UI. Use `./build/simdeck -a` or `./build/simdeck pair` when the service
should be registered as a LaunchAgent.

Use software H.264 when macOS screen recording starves the hardware encoder:

```sh
./build/simdeck daemon start --port 4311 --video-codec h264-software
./build/simdeck daemon restart --video-codec h264-software
```

For LAN access:

```sh
./build/simdeck daemon start --port 4311 --bind 0.0.0.0 --advertise-host 192.168.1.50
./build/simdeck -p 4311 --bind 0.0.0.0 --advertise-host 192.168.1.50
```

Useful direct commands:
Expand Down
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ To focus a specific simulator by name or UDID, pass it as the only argument:
simdeck "iPhone 17 Pro Max"
```

`simdeck -d` for detached start, `simdeck -k` to kill the background daemon, and `simdeck -r` to restart it.
Use `simdeck --open` to open the browser automatically, `simdeck -p 4311` to
use a non-default port, and `simdeck -a` to register the service for login
autostart.

The served loopback browser UI receives the generated API access token automatically.
LAN clients should pair with the printed code before receiving the API cookie.
Expand All @@ -77,20 +79,17 @@ For pairing with SimDeck iOS app:
simdeck pair
```

This starts or refreshes the global LaunchAgent-backed SimDeck service, prints
This starts or refreshes the LaunchAgent-backed SimDeck service, prints
local, LAN, and Tailscale URLs when available, and shows a QR code with a
`simdeck://pair` link. The QR contains the pairing code plus all detected
non-loopback addresses, so pairing once can save both the LAN and Tailscale
routes with the same service token.
Normal service restarts preserve that token so paired clients stay connected.
Use `simdeck service reset` only when you want to rotate the service token and
restart the LaunchAgent.
The LaunchAgent service uses port 4310. Project daemons start at port 4311 and
probe upward when that port is busy. When the service is active, `simdeck` and
`simdeck ui` print the existing service endpoints instead of starting a project
daemon; use the `daemon` subcommand when you explicitly want a workspace daemon.
The service uses port 4310 unless you pass `-p` or `--port`.

CLI commands automatically use the same warm daemon:
CLI commands automatically use the same warm service:

```sh
simdeck list
Expand Down Expand Up @@ -195,8 +194,8 @@ try {
}
```

`connect()` starts the project daemon when needed, reuses it when it is already
healthy, and only stops daemons it started itself. Pass `udid` to `connect()`
`connect()` starts the SimDeck service when needed and reuses it when it is
already healthy. Pass `udid` to `connect()`
to make it the default for session methods; each method still accepts an
explicit UDID as the first argument when needed. Query helpers such as
`tree()`, `query()`, `waitFor()`, `assert()`, and selector `tapElement()`
Expand Down Expand Up @@ -236,7 +235,7 @@ import "expo-router/entry";
Import it before `expo-router/entry` or `AppRegistry.registerComponent(...)`
so the package can capture React Fiber commits. The auto entrypoint no-ops
outside development, reads `EXPO_PUBLIC_SIMDECK_PORT` when present, and
otherwise scans common SimDeck daemon ports.
otherwise scans common SimDeck service ports.

## Flutter Inspector

Expand Down
3 changes: 1 addition & 2 deletions actions/run-android-comment-session/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,7 @@ runs:
SIMDECK_REALTIME_MIN_BITRATE="${stream_min_bitrate}" \
SIMDECK_REALTIME_BITS_PER_PIXEL="${stream_bits_per_pixel}" \
SIMDECK_LOCAL_STREAM_FPS="${stream_fps}" \
simdeck daemon run \
--project-root "${GITHUB_WORKSPACE}" \
simdeck service run \
--metadata-path "${metadata_path}" \
--port "${SIMDECK_PORT}" \
--bind 127.0.0.1 \
Expand Down
3 changes: 1 addition & 2 deletions actions/run-ios-comment-session/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ runs:
SIMDECK_REALTIME_MIN_BITRATE="${stream_min_bitrate}" \
SIMDECK_REALTIME_BITS_PER_PIXEL="${stream_bits_per_pixel}" \
SIMDECK_LOCAL_STREAM_FPS="${stream_fps}" \
simdeck daemon run \
--project-root "${GITHUB_WORKSPACE}" \
simdeck service run \
--metadata-path "${metadata_path}" \
--port "${SIMDECK_PORT}" \
--bind 127.0.0.1 \
Expand Down
30 changes: 17 additions & 13 deletions docs/api/health.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Health and metrics

Use these endpoints to check whether a daemon is reachable and to diagnose stream performance.
Use these endpoints to check whether the service is reachable and to diagnose stream performance.

## Health

Expand Down Expand Up @@ -36,18 +36,18 @@ Example:

Important fields:

| Field | Meaning |
| --------------- | --------------------------------------------------------- |
| `ok` | Server is alive |
| `serverId` | Stable identity for the current daemon token |
| `advertiseHost` | Host/IP the daemon advertises for non-local clients |
| `hostId` | Stable hashed identity for the Mac hardware host |
| `hostName` | Local host name for grouping LAN/Tailscale/Bonjour URLs |
| `httpPort` | Port serving UI and API |
| `serverKind` | `launchAgent`, `workspace`, `foreground`, or `standalone` |
| `videoCodec` | Requested codec mode: `auto`, `hardware`, or `software` |
| `streamQuality` | Active stream profile and limits |
| `webRtc` | ICE settings the browser should use |
| Field | Meaning |
| --------------- | ------------------------------------------------------- |
| `ok` | Server is alive |
| `serverId` | Stable identity for the current service token |
| `advertiseHost` | Host/IP the service advertises for non-local clients |
| `hostId` | Stable hashed identity for the Mac hardware host |
| `hostName` | Local host name for grouping LAN/Tailscale/Bonjour URLs |
| `httpPort` | Port serving UI and API |
| `serverKind` | `launchAgent` or `standalone` |
| `videoCodec` | Requested codec mode: `auto`, `hardware`, or `software` |
| `streamQuality` | Active stream profile and limits |
| `webRtc` | ICE settings the browser should use |

When auth is required, the `401` JSON body still includes `serverId`, `advertiseHost`, `hostId`, `hostName`, `httpPort`, and `serverKind` so native clients can group endpoints before pairing.

Expand All @@ -64,6 +64,10 @@ Useful fields:
| `latest_first_frame_ms` | First-frame startup time |
| `frames_dropped_server` | Server dropping stale frames to stay current |
| `keyframe_requests` | Stream refresh or recovery activity |
| `stream_pipeline_resets` | Encoder resets after all viewers disconnect |
| `latest_accessibility_snapshot_ms` | Most recent native accessibility duration |
| `max_accessibility_snapshot_ms` | Slowest native accessibility duration |
| `accessibility_snapshot_timeouts` | Native accessibility calls that timed out |
| `active_streams` | Open browser streams |
| `encoders[].encoder.overloadState` | `nominal`, `strained`, or `overloaded` |
| `client_streams` | Recent browser decoder and render reports |
Expand Down
2 changes: 1 addition & 1 deletion docs/api/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Use the CLI for most automation. Use the API when you are building a custom clie

## Authentication

Browser sessions loaded from the SimDeck server receive auth automatically. Direct callers should send the daemon token from `simdeck daemon status`:
Browser sessions loaded from the SimDeck server receive auth automatically. Direct callers should send the service token from `simdeck daemon status`:

```text
X-SimDeck-Token: <token>
Expand Down
37 changes: 17 additions & 20 deletions docs/cli/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,37 @@

Replace `simdeck` with `./build/simdeck` when running from a source checkout.

## UI and daemon
## UI and service

| Command | Purpose |
| -------------------------------- | ------------------------------------------- |
| `simdeck` | Start a foreground browser session |
| `simdeck` | Start or reuse the service and print URLs |
| `simdeck <name-or-udid>` | Start and select a device |
| `simdeck -d` | Start or reuse the detached project daemon |
| `simdeck -k` | Stop the detached project daemon |
| `simdeck -r` | Restart the detached project daemon |
| `simdeck ui --open` | Open the browser UI from a daemon |
| `simdeck --open` | Open the browser UI |
| `simdeck -p 4311` | Use a non-default service port |
| `simdeck -a` | Register the service for login autostart |
| `simdeck pair` | Show native iOS pairing code and QR |
| `simdeck daemon status` | Show daemon URL, PID, token, and log path |
| `simdeck daemon stop` | Stop the current project daemon |
| `simdeck daemon killall` | Stop all project daemons |
| `simdeck daemon status` | Show service URL, PID, token, and log path |
| `simdeck daemon stop` | Stop the current background service |
| `simdeck daemon restart` | Restart the current background service |
| `simdeck service on/off/restart` | Manage the optional always-on macOS service |

Examples:

```sh
simdeck ui --port 4320 --open
simdeck ui --open
simdeck -p 4320 --open
simdeck --open
simdeck pair
simdeck daemon restart --video-codec software --stream-quality low
```

`simdeck pair` uses the global LaunchAgent-backed service instead of a
project-local daemon. It binds the service for LAN access, preserves an existing
service token and pairing code when present, detects LAN and Tailscale IPv4
addresses, and prints a `simdeck://pair` QR for the native iOS app. The service
uses port 4310; workspace daemons start at 4311 and probe upward.
`simdeck` starts or reuses one local service. It uses port 4310 unless you pass
`-p` or `--port`. Normal commands reuse that same warm service.

When the service is active, `simdeck` and `simdeck ui` print the existing
service endpoints instead of launching a project daemon. Use `simdeck daemon
start` or `simdeck daemon restart` when you explicitly want a workspace daemon.
`simdeck pair` installs or refreshes the LaunchAgent-backed service. It binds
the service for LAN access, preserves an existing service token and pairing code
when present, detects LAN and Tailscale IPv4 addresses, and prints a
`simdeck://pair` QR for the native iOS app.

`simdeck service restart` also preserves the installed service token so native
clients remain paired across service restarts. Use `simdeck service reset` to
Expand Down Expand Up @@ -158,7 +155,7 @@ Use `wait-for` or `assert` steps instead of fixed sleeps when possible.

## Maestro YAML

Run common Maestro flows through SimDeck's daemon-backed iOS Simulator API:
Run common Maestro flows through SimDeck's service-backed iOS Simulator API:

```sh
simdeck maestro test flow.yaml --artifacts-dir artifacts/maestro
Expand Down
39 changes: 20 additions & 19 deletions docs/cli/flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,36 @@ Pass `--help` to any command for the generated flag list:
```sh
simdeck --help
simdeck tap --help
simdeck daemon start --help
simdeck daemon restart --help
```

## Global

| Flag | Env | Purpose |
| --------------------- | -------------------- | -------------------------------- |
| `--server-url <url>` | `SIMDECK_SERVER_URL` | Target a specific running daemon |
| `--device <selector>` | `SIMDECK_DEVICE` | One-off simulator override |
| Flag | Env | Purpose |
| --------------------- | -------------------- | --------------------------------- |
| `--server-url <url>` | `SIMDECK_SERVER_URL` | Target a specific running service |
| `--device <selector>` | `SIMDECK_DEVICE` | One-off simulator override |

`SIMDECK_UDID` is also accepted for compatibility. Device commands resolve in
this order: positional UDID, `--device`, `SIMDECK_DEVICE`, `SIMDECK_UDID`, the
project default from `simdeck use <udid>`, then auto-inference from the daemon.
project default from `simdeck use <udid>`, then auto-inference from the service.

## Server options

Used by `simdeck ui`, `daemon start`, `daemon restart`, `service on`, and `service restart`.

| Flag | Default | Notes |
| ---------------------------- | -------------------------------------- | --------------------------------------------------------------------------------- |
| `--port <port>` | `4311` for daemons, `4310` for service | HTTP port. Daemons probe upward when busy |
| `--bind <ip>` | `127.0.0.1` | Use `0.0.0.0` or `::` for LAN access |
| `--advertise-host <host>` | detected | Host printed for remote browsers |
| `--client-root <path>` | bundled client | Static client directory |
| `--video-codec <mode>` | `auto` | `auto`, `hardware`, or `software` |
| `--stream-quality <profile>` | `full` | `full`, `balanced`, `economy`, `low`, `tiny`, `ci-software`, and related profiles |
| `--local-stream-fps <fps>` | `60` | Local stream frame target |
| `--low-latency` | off | Conservative software H.264 profile |
| `--open` | off | `ui` only |
Used by `simdeck`, `daemon start`, `daemon restart`, `service on`, and `service restart`.

| Flag | Default | Notes |
| ---------------------------- | -------------- | --------------------------------------------------------------------------------- |
| `--port <port>` / `-p` | `4310` | HTTP port |
| `--bind <ip>` | `127.0.0.1` | Use `0.0.0.0` or `::` for LAN access |
| `--advertise-host <host>` | detected | Host printed for remote browsers |
| `--client-root <path>` | bundled client | Static client directory |
| `--video-codec <mode>` | `auto` | `auto`, `hardware`, or `software` |
| `--stream-quality <profile>` | `full` | `full`, `balanced`, `economy`, `low`, `tiny`, `ci-software`, and related profiles |
| `--local-stream-fps <fps>` | `60` | Local stream frame target |
| `--low-latency` | off | Conservative software H.264 profile |
| `--open` | off | Open the browser after starting the service |
| `--autostart` / `-a` | off | Register the service as a macOS LaunchAgent |

## `describe`

Expand Down
15 changes: 8 additions & 7 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
# CLI

`simdeck` is the main entrypoint for opening the browser UI, managing the daemon, and scripting simulator actions.
`simdeck` is the main entrypoint for opening the browser UI, managing the local service, and scripting simulator actions.

## Common use

```sh
simdeck
simdeck "iPhone 17 Pro Max"
simdeck -d
simdeck -k
simdeck -r
simdeck --open
simdeck -p 4311
simdeck -a
```

With no subcommand, SimDeck starts a foreground server and prints browser URLs. A single simulator name or UDID selects that device in the UI. The shorthand flags start, stop, and restart the detached project daemon.
With no subcommand, SimDeck starts or reuses the background service and prints browser URLs. A single simulator name or UDID selects that device in the UI.

## Command shape

```sh
simdeck [SIMULATOR_NAME_OR_UDID]
simdeck [-p <port>] [--open] [--autostart]
simdeck [--server-url <url>] <command> [options]
```

Expand All @@ -26,7 +27,7 @@ default for later device commands. Most commands accept `[<udid>]`; `--device`,
`SIMDECK_DEVICE`, and `SIMDECK_UDID` override the saved project default when a
one-off target is needed.

Use `--server-url` or `SIMDECK_SERVER_URL` when a script should target a specific daemon:
Use `--server-url` or `SIMDECK_SERVER_URL` when a script should target a specific service:

```sh
SIMDECK_SERVER_URL=http://127.0.0.1:4310 simdeck list
Expand Down Expand Up @@ -70,7 +71,7 @@ Most successful commands print JSON so they can be piped into tools such as `jq`
```sh
simdeck --help
simdeck tap --help
simdeck daemon start --help
simdeck daemon status
```

## Next
Expand Down
10 changes: 5 additions & 5 deletions docs/extensions/browser-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ simdeck

Then open the printed local URL.

Detached flow:
Open directly:

```sh
simdeck ui --open
simdeck --open
```

LAN flow:

```sh
simdeck ui --bind 0.0.0.0 --advertise-host 192.168.1.50 --open
simdeck --bind 0.0.0.0 --advertise-host 192.168.1.50 --open
```

## What the UI shows
Expand All @@ -45,10 +45,10 @@ Use the default URL for normal operation.

## Serve a custom client

Point the daemon at another static bundle:
Point the service at another static bundle:

```sh
simdeck ui --client-root /path/to/dist --open
simdeck --client-root /path/to/dist --open
```

Your client should use the [REST API](/api/rest), WebRTC offer endpoint, and control WebSocket documented in the API reference.
Expand Down
Loading
Loading