Nodes
Machines join with a token and connect outbound over WebSocket — no inbound SSH, no public ports. Each reports CPU, memory, load, session capacity and installed runtimes, live.
That starts Claude Code on a different computer.
nook exec types at it and waits for the answer. No ssh, no tmux,
no hostname, no port to forward. Close your laptop and it keeps working.
# azul is a box across the room. or across the world. same command. $ nook start acme/checkout-api --node azul --runtime claude --name api ✓ api — claude on azul $ nook exec api 'what machine are you on, and what is this repo?' ❯ what machine are you on, and what is this repo? ● I'm on azul (linux), in /srv/work/acme/checkout-api — the payment capture and settlement service. Want me to run the tests? ✻ thought for 3s
Try ↑ for history · tab to complete
Not a mockup
An agent running on one machine started a Claude Code session on a second
machine, sent it prompts, read its answers, and drove the work to
completion — using nothing but nook start,
nook send, nook read and nook exec.
No ssh session was opened. No port was forwarded. No hostname was typed.
NookOS ships that capability as an agent skill, so any agent you run can
do the same thing: ./skills/install.sh --host <box>.
The protocol is small enough to explain in one line — send types,
read looks, exec does both and waits — which is exactly why an agent
can pick it up without a wrapper library.
How it works
You name a workspace and a runtime. The control plane finds a machine that has that repo checked out and starts the session there. You never address the machine directly.
Machines, repos and running sessions, kubectl-style. Every node reports its own capabilities, including which runtimes it actually has installed.
$ nook get nodes NAME PLATFORM STATUS RUNTIMES azul linux online claude,codex,bash crimson linux online hermes,bash $ nook get workspaces $ nook get sessions
Pick the runtime you want — claude, codex, hermes, bash, zsh. Drop --node and the scheduler picks an online machine that has the repo.
$ nook start acme/checkout-api --runtime claude $ nook start acme/checkout-api --node azul --runtime claude --name refactor-auth
exec polls until the screen stops changing for two consecutive reads — the only honest way to know an agent has finished, because thinking time is unpredictable and a fixed sleep either truncates the answer or wastes minutes.
$ nook exec refactor-auth 'move the token refresh into middleware' --timeout 600 $ nook send refactor-auth 'yes' # answer a permission prompt $ nook read refactor-auth --lines 400
Sessions are independent and persistent. Start work on three repos across three machines, go and do something else, and collect the results when you get back.
$ nook start acme/checkout-api --node azul --runtime claude --name api $ nook start widgets/web-dashboard --node crimson --runtime claude --name web $ nook send api 'upgrade sqlx and fix the fallout' $ nook send web 'migrate settings to the new form component'
What it is
NookOS does not replace your editor, your Git, or your AI. It coordinates everything around them, and it keeps the coordination in one place you own. Claude writes the code. Nook decides where it runs, remembers that it ran, and is still holding the session when you come back — an operating system for the work rather than for the machine.
Machines join with a token and connect outbound over WebSocket — no inbound SSH, no public ports. Each reports CPU, memory, load, session capacity and installed runtimes, live.
A workspace is a repo, not a machine. The same workspace can exist on many nodes; a repository's identity is its git remote, so two checkouts of the same thing are the same thing.
tmux-backed and persistent, streamed to xterm.js in the browser. They survive page refreshes, network drops, your process exiting and the node restarting.
A session runs whatever you choose — bash, zsh, claude, hermes, codex. Ask a node for a runtime it doesn't have and it fails immediately, not mysteriously.
Kanban that actually dispatches work. Triage → Todo → In Progress → Done, where start work creates a worktree and a session, and prune tears the worktree back down.
Everything produces an event, streamed live over WebSocket. Plus rolling per-workspace notes, so the context of a piece of work lives next to the work.
An MCP server at /mcp exposes the whole system to any MCP client: list workspaces, nodes and sessions, start a session, send to it, read activity, create a task.
Generic OIDC against any standards-compliant IdP, authorization code + PKCE, multi-tenant from the schema up. Access tokens are issued and revoked in the UI.
A Tauri shell wraps the same application, so the fleet is a native window when you want one and a browser tab when you don't.
The application
One screen for every machine, every repo and every running session you own.
Install
Point OIDC_* at your identity provider, or leave dev sign-in on while you look around. Open http://localhost:5173.
$ git clone https://github.com/nook-os/nook-os $ cd nook-os $ cp .env.example .env $ ./run.sh
In the UI: Nodes → add node, then run this on the machine you want to add. It connects outbound; nothing needs to be reachable from the internet.
$ nook join --server https://nook.example.com --token nook_join_... $ nook run
A node token is confined to its own machine on purpose — it sits in a file on a box that runs other people's code, so one compromised machine must not become every machine. A user token is what drives the fleet.
$ nook login --token nook_user_... $ nook whoami
NookOS ships as an agent skill. Install it and your agent can start and drive sessions across the fleet on its own.
$ ./skills/install.sh # this machine $ ./skills/install.sh --host crimson # and that one
Posture
| Property | How it behaves |
|---|---|
| Network | Nodes dial out over WebSocket. No inbound SSH, no public ports, no reverse tunnel to a vendor. |
| Telemetry | None. There is no phone-home, no analytics endpoint, and no account required to run it. |
| Credentials | A node token can only act on its own machine. Only a user token drives other machines, and it lives 0600 in your home directory. |
| Data | Your Postgres, your disks, your repos. Git stays the source of truth; NookOS coordinates, it does not own. |
| Licence | Apache-2.0. Fork it, run it, embed it, sell services on it. |
| Extensibility | Rust owns the types: OpenAPI is generated from the code and TypeScript from OpenAPI, so third-party clients cannot drift. |
Questions
You can. You will also be managing hostnames, keys, jump hosts, VPN state, port forwards and a mental map of which box has which repo — and none of that is addressable by an agent without giving it shell credentials to everything.
NookOS gives you one verb per intent instead: name the repo, name the runtime, go. The machine is an implementation detail the control plane resolves.
Yes — they're tmux sessions on the node, not proxied processes. Your laptop closing, your terminal dying, the network dropping and the control plane restarting are all survivable. Come back hours later and nook read still prints the screen and its scrollback.
The session is marked as having an offline node and starts working again when the machine reconnects. The tmux session was never destroyed; only the transport went away.
--runtime is any executable the node reports. Claude Code, Codex and Hermes are the ones in daily use; a plain shell is a first-class runtime, and adding another is a matter of it being installed on the machine.
That's the point. There's an MCP server at /mcp covering the whole surface, and an agent skill that teaches the CLI. The built-in dispatcher recommends where work should run — it recommends, it never acts. Humans approve.
Multiple worktrees of the same app on one machine can collide on ports, and there's no automatic fix yet. Kanban federation to Jira, GitHub, Linear and Trello sits behind a provider trait but ships local-only today. The roadmap is in the repo, not in a press release.
A managed service is coming. The self-hosted build is not a crippled tier — it is the whole product, and it always will be. Join the waitlist if you'd rather someone else ran the control plane.
Free, open source, Apache-2.0, self-hosted, no telemetry. Clone it and have a fleet in about five minutes.