All your work, machines and models, in one place.
A Tauri (Rust) desktop app that drives Claude Code, OpenAI Codex, and Kimi Code natively over their wire protocols — no terminal wrapping, no Node server — and serves the same UI to any browser on your LAN.
Pair your machines and they become one mesh: launch a thread on your desktop from your laptop, watch three models work on three different computers at once, and drive the whole thing from your phone. No cloud, no account — your machines talk to each other directly.
The same UI a phone gets, streaming a live model turn over the LAN.
(That's Threadknot working on Threadknot.)
Prebuilt packages are on Releases — no Rust, no Node, no toolchain. Take the one for your platform.
macOS (Apple Silicon) — Threadknot_<version>_aarch64.dmg
Open the disk image and drag Threadknot to Applications. The build is ad-hoc signed rather than notarised, so the first launch needs right-click → Open; a plain double-click reports that the app "cannot be opened" and looks like a corrupt download. Once is enough. Or clear the quarantine flag outright:
xattr -dr com.apple.quarantine /Applications/Threadknot.appWindows (x64) — Threadknot_<version>_x64-setup.exe
Run the installer. It is unsigned, so SmartScreen interrupts with "Windows protected your PC" — More info → Run anyway.
Debian / Ubuntu — Threadknot_<version>_amd64.deb
sudo apt install ./Threadknot_<version>_amd64.debFedora / RHEL — Threadknot-<version>-1.x86_64.rpm
sudo dnf install ./Threadknot-<version>-1.x86_64.rpmAny distro, Arch included — Threadknot_<version>_amd64.AppImage
chmod +x Threadknot_<version>_amd64.AppImage
./Threadknot_<version>_amd64.AppImageThere is no pacman package and there will not be one; the AppImage is the download-and-run answer for every distro without a native bundle.
Threadknot drives the coding agents you already have — it does not replace them
and it never handles their auth. Install at least one and log in before first
launch: claude, codex, or kimi. Each runs against your own subscription,
so everyone uses their own account. An agent you are not logged into simply
shows as unavailable in the composer; nothing else breaks.
- Launch Threadknot. It opens on an empty fleet.
- Add workspace in the sidebar, and point it at a project folder.
- New chat, pick a model, and type.
Settings is the gear at the foot of the sidebar: the LAN URL for phone access, themes, and updates.
Every release also carries threadknot-headless-<platform> — the same server
without the desktop window, which is what you want on a spare machine or a
homelab box:
chmod +x threadknot-headless-linux
./threadknot-headless-linux # prints the LAN URL and access tokenOpen that URL from any browser on your network and you get the same UI the desktop app shows. Real model turns work with no desktop session at all.
A headless box holding the team's checkouts is the case this is for. Add each person under Settings → People, pair their browser, and assign the two to each other under Settings → Phone & access. From then on each of them gets their own sidebar: their own chats by default, a row of faces to look at anyone else's, and their own stars, stashed projects and settled shelf, so filing something away stops filing it away for everybody. Give each person their own Claude login from the same panel and their turns spend their own subscription seat instead of all three sharing one.
Everyone can still open everyone's chats, which is the point — you drop into a
colleague's thread to help. It is not an isolation boundary: agents all run
as the same OS user, so anyone granted files or terminal can read anything
on that machine. If you need people separated rather than merely tidy, run one
headless instance per OS user instead.
Adding a machine under Settings → Machines makes two installs equals: both sides dial, and both push their whole project catalog to the other. That is what you want for your own laptop and homelab, and it is the wrong shape for a box you share with colleagues — pair three laptops to one and all three sidebars merge through it.
Settings → Servers is the other shape. Paste the machine's address and a one-time pairing code from its Settings → Phone & access, and its projects appear in your sidebar next to your own, marked with its name. Chats there run there. The link is one way: your desktop never sends its catalog, nothing of theirs is written to this machine, and what you hold is an ordinary device credential their owner scopes, assigns to you by name, and can revoke without asking. Starring or stashing one of their projects is your own view of it and does not touch theirs.
Installed copies update themselves: Settings → updates → check now, then one
click downloads the new build, installs it over this one and relaunches. The
download survives closing the window. A machine that has a Threadknot git
checkout builds from master instead of downloading — it says so on the card,
and either machine can be switched to the other route from the same panel.
With Rust and Node 22+ present:
npm install
npx tauri build --no-bundle
./src-tauri/target/release/threadknotOr ./build-linux.sh, ./build-mac.sh, .\build-windows.ps1 to produce the
same installable packages the releases carry. You will also need your platform's
webview toolchain — see Prerequisites. More build detail,
including the one mistake that produces a binary with no UI, is under
Build & run.
Pair two or more machines and they form a symmetric mesh — no hub, no cloud, no account. Whichever Threadknot you happen to be looking at drives all of them, and that includes the one in your phone's browser.
phone · laptop · any browser on the LAN
│
connect to ANY one machine…
▼
┌───────────────┐ ┌───────────────┐
│ desktop │◀───────▶│ macbook │
│ claude ▶▶ │ peer │ codex ▶▶ │
└───────┬───────┘ └───────┬───────┘
│ │
peer │ ┌───────────────┐ │ peer
└─────▶│ homelab │◀─┘
│ kimi ▶▶ │
└───────────────┘
…and you are driving all three.
A workspace groups threads that live on different machines under a single sidebar entry. Starting a thread means picking which machine, and which of that machine's registered folders, it runs in. From then on the thread is pinned there — and its events stream to every paired device.
Workspace "Storefront"
├─ desktop ~/projects/storefront ← Claude, mid-refactor
├─ macbook ~/work/storefront-seo ← Codex, running tests
└─ homelab /srv/storefront ← Kimi, on a long build
Three models, on three machines, working at once. Open a new thread on any of them, or interrupt a turn you don't like, from whichever device is in your hand.
- Discovery is mDNS plus explicit pairing. Identity is the machine id, so a DHCP lease change never breaks the mesh; IP addresses are disposable hints.
- No cloud plane. Peers talk directly over your LAN or tailnet. There is no sync service, no account, and nothing to sign up for.
- Nothing is copied around. A thread is pinned to the machine that owns it and runs against that machine's real filesystem. Git stays the only channel for code.
Still machine-local: git panes, terminals, and artifact bytes are served only by
the machine owning the thread, and push notifications don't yet fire for remote
threads. Details and the remaining work: docs/MULTI-MACHINE.md.
Models are confidently wrong in ways another one often catches immediately. So point one at another one's work.
Review with… throws one or more reviewers at a live thread. Claude planned a refactor; hand the plan to Codex and let it argue. Reviewers are read-only — they cannot touch a file, only make a case — and any model can review, including the one that did the work.
thread: "Rewrite the sync layer"
Claude ── plans the refactor ──▶
Codex ── "this drops writes on
reconnect; here's the case"
Kimi ── "agreed, and the retry is
unbounded"
Claude ── concedes, revises ──▶
…until everyone concedes, or you call it
One reviewer at one round is a plain critique. Add reviewers, or raise the round count, and it becomes a debate that runs until the participants stop objecting. They can be different providers, different models, or the same model twice — each with its own model, effort, and access.
Design notes and the reasoning behind the roles: docs/PARLEY.md.
| Control | Options |
|---|---|
| Agent | Claude Code, Codex, Kimi Code, Claudex (Claude harness + any model) |
| Model | Claude: Fable 5.1 / Fable 5 / Opus 5 / Sonnet 5 / Haiku 4.5 · Codex: discovered via model/list · Kimi: K3 / K3 256K / K2.7 Code |
| Effort | K3: low / high / max (high default) · other models expose their supported levels (+ 1M context toggle on supported Claude models via the [1m] suffix) |
| Access | Read-only (ask for everything) / Edits (auto-accept edits) / Full (no prompts) |
| Mode | Plan (read-only planning, plan approval card → one-click "Approve & build") / Build |
┌───────────────────────────────────────────────┐
│ Tauri shell (desktop window) │
│ └─ React UI ←────────────┐ │
├─────────────────────────────┼─────────────────┤
│ Rust core (threadknot_lib) │ same UI, phone │
│ axum server :42800 ───────┴──── browser ────┼──→ http://<lan-ip>:42800/?token=…
│ ├─ /ws (token-gated JSON protocol) │
│ ├─ /browser (shared Chrome screencast) │
│ ├─ /mcp (agent browser + artifacts) │
│ ├─ agent hub (events → JSONL + fanout) │
│ ├─ claude driver ── spawns `claude` │ stream-json + control_request
│ ├─ codex driver ─── spawns `codex` │ app-server (JSON-RPC/stdio)
│ ├─ kimi driver ──── spawns `kimi acp` │ ACP (JSON-RPC/stdio)
│ └─ claudex ──────── `claude` + gateway env │ any model, Claude harness
└───────────────────────────────────────────────┘
- Auth is your existing subscriptions: the local drivers spawn the
installed
claude,codex, andkimiCLIs, which use their ownclaude login/codex login/kimi logincredentials. No API keys for the local agents. (Claudex is the exception: it runs the sameclaudeharness against a compatible gateway, so it takes a base URL and key.) - Projects are folders; each thread runs in that folder with its own model / effort / access / plan-build settings.
- Everything is event-sourced: normalized agent events are appended to
~/.threadknot/threads/<id>.jsonland broadcast to every connected client, so desktop and phone stay in sync and threads replay on reconnect. - Provider sessions resume: Claude via
--resume <session_id>, Codex viathread/resume, and Kimi via ACPsession/resume. - Agent and human share one browser: the agent gets semantic page snapshots and deterministic browser tools while the Browser workspace shows the same live Chrome, including the agent cursor, target, action status, and failures. You can take over its mouse and keyboard at any time.
Protocol contract: docs/PROTOCOL.md. Codex app-server
schemas vendored in docs/protocol/.
- Rust (stable) and Node 22+.
- Platform toolchain for Tauri's webview stack. On Linux:
macOS needs the Xcode command-line tools; Windows needs the MSVC build tools. Linux is the primary development target and gets the most testing.
sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \ librsvg2-dev libgtk-3-dev libssl-dev patchelf - The agent CLIs you intend to drive, installed and already logged in:
claude,codex,kimi. Threadknot does not handle auth — it reuses each CLI's own subscription login, so every person runs against their own account. An agent you are not logged into shows as unavailable in the composer; nothing else breaks.
The first build compiles the full dependency tree and takes a while. Later builds are incremental.
npm install
npm run tauri dev # desktop app w/ vite HMR (port 1430)npx tauri build --no-bundle # desktop app
./src-tauri/target/release/threadknot # desktop app
./src-tauri/target/release/threadknot-headless # LAN server only, prints URLBuild the desktop app with the Tauri CLI, as above. A plain
cargo build --releaseproduces a binary with no UI embedded: it tries to load the dev server and opens on "Could not connect to localhost".npx tauri buildrunsnpm run buildfor you.
Server state: ~/.threadknot/ (server.json holds the port + access token —
delete it to rotate the token). Override port with THREADKNOT_PORT, UI location
with THREADKNOT_DIST.
Upgrading from Armada? Nothing is migrated: an existing ~/.armada keeps being
used, in place. See "Rename compatibility" in CLAUDE.md.
Open Settings (gear, bottom of sidebar) in the desktop app and open/copy the
LAN URL — e.g. http://192.168.0.54:42800/?token=… — on any device on your
network. The token persists in the browser after first load.
Inspired by t3code and Codex — thanks to both teams.
t3code is MIT-licensed, © 2026 T3 Tools Inc.; its notice is in
THIRD-PARTY-NOTICES.md.
Apache License 2.0. Use it for anything — personally, at work, commercially — modify it, fork it, redistribute it. Keep the copyright notice and license text if you redistribute it, modified or not.
The hosted relay that backs the optional paid tier is a separate service and is not in this repository. Nothing here needs it: the LAN server, the mesh, and the mobile companion all work with no account and no internet.
