i99dash docs
Operator CLI

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> --record

Two-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 only

plan 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):

LayerHow
Per-launch envI99OP_SCREEN_BITRATE, I99OP_SCREEN_MAX_SIZE, I99OP_SCREEN_MAX_FPS
Saved configThe GUI's Screen tab has a Streaming Quality card — change it live, no rebuild or restart
Defaults2M / 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

CommandWhat 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 TJust the TCP↔WSS splice — point your own adb at the printed 127.0.0.1:<port>.
recover -H H -o OTP --apk …DashDoctor recovery: planreinstall (--dry-run for plan only).
session bind -H H -o OTPVerify the OTP → mint + print a relay ticket.
session info -H HSession status.
session end -H HEnd the session (idempotent).
balanceShow your operator wallet balance.
login / logout / configSign in / clear token / show config.
keys add <pub> / keys listManage your SSH login keys.
guiLaunch the desktop GUI.
upgradeSelf-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):

i99op

Desktop 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.
  • Screenscrcpy mirroring 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 gui

See Install → Desktop GUI for the deps.

On this page