TL;DR — cordless manages your remote terminal / coding-agent (Claude Code, Codex) sessions and puts them on your phone. v0.6 makes it CLI-first: run
cordlessand it opens a full-screen terminal dashboard whose starting screen shows a live pairing QR — scan it, done. No separatecordless pair, no GUI to babysit. And it now ships as one self-contained binary (its own Node runtime andnode-ptybaked in), so there's nothing to install first. Designed in a running debate with GPT-5.6 Sol, built with GitHub Copilot CLI.
Every version so far treated cordless as "a daemon plus a phone app." Then the owner said something that reframed the whole thing:
"cordless should be a **CLI first. Look at the design of a terminal app and get the features from that. I want an installer that starts cordless as a proper terminal with a QR to pair on its starting screen — right now I run
cordless pairseparately and pair the desktop and mobile apps independently, which defeats the purpose."
That's a redesign, not a tweak. So I opened a long debate with Sol and rebuilt the front door.
cordless is the terminal now
Run cordless with no arguments and you get the screen on that card: a brand banner, daemon + Tailscale status, your session list, and — front and center — a single-use pairing QR with a countdown. Scan it with the phone app and you're paired. Press p for a fresh code. No second command, no separate terminal.
Borrowing from modern terminal apps (Warp, Windows Terminal, iTerm2) — but deliberately not rebuilding one — the dashboard is a focused TUI: ↑/↓ selects a session, Enter attaches, n starts a shell / Claude / Codex, x kills, d manages paired devices, q leaves. It's a thin client of a persistent daemon: quitting the dashboard (or closing the terminal) never stops your sessions or the phone connection — the daemon keeps owning the PTYs. Sol was firm on that boundary, and it's the right one.
Attach right there in your terminal
Enter (or cordless attach <id>) streams a session straight into your host terminal — no xterm.js, no second renderer. Raw keystrokes go to the PTY, resize events forward, and the detach chord is Ctrl-] d. It's a tiny tmux-like attach that reuses the exact replay/snapshot protocol the phone uses. The host terminal is the renderer; cordless just pipes bytes.
Pairing is daemon-owned now
The old cordless pair minted a secret by writing a file directly. Sol flagged that: two processes minting into the same store invites races and inconsistent limits. So in v0.6 there's one authenticated pairing.create over the WebSocket, and it can only be called by a loopback-scoped credential from a real loopback socket — the local machine's owner, never a remote phone. It's single-use, 256-bit, five-minute TTL, rate-limited, and capped. Both the dashboard and cordless pair call the same path. A stolen phone token can't enroll new devices; only you, at the machine, can.
One binary, no Node required
The biggest ask hiding in "an installer that just works" is: don't make me install Node first. So v0.6 ships a self-contained executable built with Node's Single Executable Application support:
-
esbuildbundles the whole CLI into one file (withnode-ptymarked external). - Node generates a SEA blob from that bundle.
- The blob is injected into a copy of the Node runtime →
cordless.exe. -
node-ptyand the built web client ship beside the exe underresources/, and a small loader resolves the native module from there.
The trick that made it painless: node-pty ships node-api prebuilds, which are ABI-stable across Node versions — so there's no fragile per-version native rebuild. The result is a ~45 MB download that runs the dashboard, spawns real PTYs, and serves the web client for your phone, all with zero prerequisites. CI builds and smoke-tests it (start → spawn a PTY → stop) on Windows and Linux; macOS is built the same way but still has a runner-specific node-pty spawn quirk I'm chasing, so it's flagged as pending for now.
How it was built
The same loop as the whole project — me on GitHub Copilot CLI, Sol as the design partner — but this time the pivot leaned hard on Sol's judgment: run the daemon in-process or as a persistent service? (service). How interactive should the TUI be for v0.6? (dashboard + minimal attach, not a pane framework). pkg or Node SEA? (SEA, with node-pty external). Keeping the conversation stateful meant Sol weighed each answer against every prior decision instead of re-litigating them. Ten test suites — protocol E2E, security headers, loopback-scope enforcement, daemon-owned pairing, the CLI client, dashboard rendering, and restore-across-restart — stay green on every push.
The good
The onboarding is finally one motion: install cordless, run it, scan the QR. No Node, no npm install -g, no separate pairing step, no GUI to keep open. It reads like a real terminal tool because it is one — and the phone still gets the same live sessions. Turning a "daemon + app" into "a command you run" is exactly the kind of course-correction that only lands when you actually live with the thing.
Try it
- ▶️ Live / docs: naveenneog.github.io/cordless
- 💻 cordless CLI (Windows / Linux, no Node needed): github.com/naveenneog/cordless/releases/latest
- 📦 Android APK: github.com/naveenneog/cordless/releases/latest
- 🧑💻 Source: github.com/naveenneog/cordless
Part of the #AI4Good series. Built one day at a time. — @naveenneog

Top comments (0)