-
Notifications
You must be signed in to change notification settings - Fork 4
Companion Remote
Control a ClashFest instance running on another device — typically an Android TV — from your phone, over your local network. Turn the VPN on/off, share a subscription to the TV, see its status, and rename it. No accounts, no cloud, no relay — everything stays on your Wi-Fi.
- Discover ClashFest/SlothClash devices on your LAN by a friendly name (Living Room, Bedroom, …).
- Pair securely by scanning a QR on the TV (or entering a PIN for camera-less controllers like a PC).
- Toggle the VPN on/off on the TV.
- Share one of your phone's subscriptions to the TV in one tap.
- See status (connected / active profile / traffic) and rename the device.
- Open ClashFest on the TV → the Remote control entry (on Home, or in Settings).
- Enable Allow remote control. This is off by default — like ADB debugging, you turn it on deliberately.
- The TV shows a QR code (and its
ip:portfor a sanity check). Leave it on screen.- For pairing a PC / camera-less controller, choose Show pairing PIN instead — a 6-digit code, valid ~60s.
- Open ClashFest → Companion (Settings, or the
+sheet → Control a TV). - Scan the TV's QR (or enter the PIN).
- Paired! The device appears in your list. Right after pairing you're offered to share your active subscription to it.
Both devices must be on the same local network. Pairing needs you to physically see the TV screen (QR/PIN) — that's the security proof.
-
"Unreachable" right after pairing — make sure both devices are on the same Wi-Fi (not guest isolation / different VLANs). An emulator can't be an agent — its
10.0.2.15address is internal NAT and unreachable from a real device. - QR looks stale — the TV persists its port, but if you reinstalled, re-open the remote-control screen for a fresh QR.
- Nothing discovered — some routers block mDNS/multicast; try again or pair directly by scanning the QR.
| Mechanism | Why |
|---|---|
| Default OFF — explicit opt-in on the TV | No silent network exposure |
QR/PIN pairing carries ip:port + token + TLS cert fingerprint
|
Requires physically seeing the TV = presence proof |
| TLS (self-signed, pinned) by the QR fingerprint | Traffic (including subscriptions) encrypted; MITM impossible |
| Per-device bearer token, revocable by un-pairing | One compromised controller ≠ all; easy revocation |
| Command whitelist on the gateway | Even a leaked token can't do arbitrary damage |
| The proxy core's REST API stays bound to 127.0.0.1 | The core API never touches the LAN — the gateway is the single auditable entry point |
The companion is a thin, secure LAN gateway in front of the app's existing controls (VpnService toggle, subscription import) and — later — the Mihomo external-controller REST API.
-
Discovery: mDNS/NSD service
_clashctl._tcp. TXT keys:app(clashfest|slothclash),id(stable device id),name,ver,fp(TLS fingerprint). -
Pairing QR:
clashctl-pair://<ip>:<port>?id=<deviceId>&name=<name>&app=<app>&fp=<sha256>&token=<token> -
Transport: HTTPS (self-signed, pinned).
Authorization: Bearer <token>on every request. -
Endpoints (v1):
-
GET /v1/status→{ running, activeProfile, uploadTotal, downloadTotal, mode } -
POST /v1/power{ "action": "on" | "off" | "toggle" } -
POST /v1/subscription{ "url", "name" }(agent fetches + imports) or{ "payload": "<yaml>" } -
POST /v1/rename{ "name" }→ persists + re-announces mDNS -
POST /v1/pair{ "pin" }→ issues a bearer token (PIN-gated, no bearer required)
-
-
Phase 2:
ANY /v1/core/*whitelisted proxy to the localhostexternal-controller(proxy-group select,/traffic,/connections), plusWS /v1/eventsfor live push.
The shared wire contract lives in the clash-companion repo so ClashFest, SlothClash, and any future controller speak byte-for-byte the same protocol.
📱 User Guide
- Getting Started
- Profiles & Nodes
- Routing & Rules
- Settings
- Deep Links
- Encrypted Subscriptions
- Troubleshooting
🏢 Operator API
📺 Companion