Run a session
Connect with a code, record with consent, run DashDoctor recovery, and the low-level relay commands.
The quick path: connect
The owner reads you one short code off the car. Redeem it and you land in
an interactive adb shell on the car:
i99op connect <code>connect redeems the code, binds the session, brings up the tunnel, and
hands you the shell — the whole flow in one command.
The adb byte stream is peer-to-peer. Once the session binds, adb and
scrcpy ride a direct WebRTC DataChannel between your machine and the
car — the relay only carries the control plane (signalling, auth, the
kill-switch). On the same LAN the peers connect directly; across networks
they use STUN/TURN to traverse NAT. The adb stream never transits the
relay.
Explicit handle + OTP
If you have the 24-char handle and the 6-digit OTP instead of a code:
i99op shell -H <handle> -o <otp>--otp binds a fresh relay ticket. Already hold a ticket? Pass --ticket
or set REMOTE_HELP_RELAY_TICKET (kept out of argv) and skip the bind.
Recording
Pass --record to connect or shell to capture the session and upload
it on end. The upload is a flat charge against your operator
wallet:
i99op connect <code> --recordTwo-party consent. Recording is opt-in for the owner too. When you
pass --record, the owner's DashDoctor screen shows an
Allow / Don't record prompt, and no bytes are captured until they
approve. If they decline — or don't answer in time — the session runs
normally, just un-recorded. There is no way to record without the
owner's on-car consent.
Recovery (DashDoctor)
Repair or replace the car app over the live tunnel — without dropping the
session — using the plan → reinstall flow. Requires the recovery
capability on the session:
i99op recover -H <handle> -o <otp> --apk /path/to/app.apk
i99op recover -H <handle> -o <otp> --apk /path/to/app.apk --dry-run # plan onlyplan is a non-destructive snapshot + signature pre-check; reinstall
replaces the app. recover uses the relay's text channel and needs no
local adb.
Reconnect — resume without a new code
If your session drops — your laptop sleeps, the Wi-Fi flips, you close the GUI — you don't need the owner to read you a fresh code. As long as the case is still open and the car's session is still live, you can Reconnect straight back in:
- In the desktop GUI, open the Tickets panel, select the open case, and press 🔌 Reconnect. It re-binds and drops you straight back into the session — no code, no OTP.
- The owner's original code was their consent; an open case is standing consent. The owner stays in control: closing the case (from the car or the mini-app) revokes access immediately, and they get a notification on every reconnect.
Reconnect needs a live session on the car. The car hosts the session; you re-attach to it. If it has fully ended — the owner pressed End on the car, or it idled out — there's nothing to resume, and you'll be asked for a new code instead.
Streaming quality
scrcpy mirroring rides the same peer-to-peer channel as adb. Over a
car's mobile uplink, scrcpy's defaults (8 Mbps, native resolution, 60 fps)
swamp the link and the screen lags. The CLI ships conservative caps —
2 Mbps, 1024 px, 20 fps — and you can tune them three ways (highest
precedence first):
| Layer | How |
|---|---|
| Per-launch env | I99OP_SCREEN_BITRATE, I99OP_SCREEN_MAX_SIZE, I99OP_SCREEN_MAX_FPS |
| Saved config | The GUI's Screen tab has a Streaming Quality card — change it live, no rebuild or restart |
| Defaults | 2M / 1024 / 20 if nothing is set |
Raise them on a fast link for a sharper picture; drop them further on a
weak one for responsiveness. The CLI auto-detects your scrcpy major
version and uses the right flag (--video-bit-rate on 2.x, --bit-rate
on 1.x).
All commands
| Command | What it does |
|---|---|
connect <code> [--record] | Redeem a one-time code → bind → adb shell (simplest path). |
shell -H H -o OTP [--record] | Bind, open the splice, drop into interactive adb shell. |
exec -H H -o OTP -- CMD… | Run one adb shell command and exit. |
bridge -H H --ticket T | Just the TCP↔WSS splice — point your own adb at the printed 127.0.0.1:<port>. |
recover -H H -o OTP --apk … | DashDoctor recovery: plan → reinstall (--dry-run for plan only). |
session bind -H H -o OTP | Verify the OTP → mint + print a relay ticket. |
session info -H H | Session status. |
session end -H H | End the session (idempotent). |
balance | Show your operator wallet balance. |
login / logout / config | Sign in / clear token / show config. |
keys add <pub> / keys list | Manage your SSH login keys. |
gui | Launch the desktop GUI. |
upgrade | Self-update to the latest published binary. |
Common options: --port/-p sets the local adb port the bridge listens on
(default 5999); --record/-r is available on connect and shell.
Interactive console
Run i99op with no arguments for a guided console — it walks you
through handle → OTP → a menu (shell / run command / recover / end):
i99opDesktop GUI
i99op gui launches the full graphical client: paste the ticket code,
press Connect, and it runs the session in-process — the adb byte
stream goes peer-to-peer, no local adb setup needed. Once connected it's
organised into tabs:
- Session — connect/end, the live
127.0.0.1:<port>, a wallet chip, the one-shot command runner, recovery, and optional recording. - Tickets — your open + past cases, with the 🔌 Reconnect button to resume an open case codelessly.
- Device — device info and quick actions.
- Apps — list / install / uninstall packages on the car.
- Files — push and pull files over the tunnel.
- Screen —
scrcpymirroring plus the Streaming Quality card (above). - Logcat — live device logs.
You also get in-app sign-in (it remembers your SSH key, so the session stays signed in past the token's lifetime).
i99op guiSee Install → Desktop GUI for the deps.