Puddle is an open-source, multi-account coding agent orchestrator with first-class SSH support and a lightweight GUI. With a single command,
puddle launch <user>@<host>Puddle manages parallel agents anywhere you SSH into, insulates agents in dedicated worktrees, and keeps your agents alive across disconnects and restarts.
On your local machine where you will be using the GUI, run:
npm install -g @puddle-code/cliTo launch agents on a remote host:
puddle launch <user>@<host>This connects Puddle to the remote host over SSH, bootstrapping the Puddle daemon on first contact and enabling you to begin development.
Puddle works using your system ssh, so ~/.ssh/config, agents, and jump hosts apply.
For development on your own machine:
puddle launchThis installs the Puddle daemon under ~/.puddle and serves the GUI at http://localhost:7433.
Note that Ctrl-C closes the GUI only, while agent sessions keep running.
Daemon-only installs:
Daemon-only installs (no CLI) use the install.sh attached to each release — see the Releases page of this repository:
curl -fsSL https://github.com/PerceptronV/puddle-code/releases/latest/download/install.sh | shManaging components:
The CLI installs, upgrades, and removes all three components — daemon, desktop app, and itself — with optional versions and SSH targets:
puddle upgrade # everything installed → the newest release
puddle install daemon@v0.0.32 user@host # pin a host's daemon to a version
puddle remove daemon # uninstall; your data stays unless you --purgeDesktop app (optional):
The same cockpit also ships as a standalone desktop app — identical UI and engine, plus a File → "Connect to SSH Host…" menu for remote hosts. Grab the dmg (macOS arm64) or AppImage (Linux x64) from the Releases page.
An installed Puddle CLI manages the desktop app directly: quit Puddle, then puddle install desktop, puddle upgrade desktop, or puddle remove desktop. On macOS a fresh install goes to /Applications when writable, otherwise ~/Applications; on Linux install desktop asks where to put the AppImage (default ~/puddle) and opens the folder — later updates happen from inside the app.
The macOS downloads are not code-signed (an open-source project without Apple Developer Program fees), so Gatekeeper will refuse the first launch. Either allow it once — open the app, let macOS block it, then System Settings → Privacy & Security → Open Anyway — or clear the download quarantine in a terminal:
xattr -dr com.apple.quarantine /Applications/Puddle.appBuilding from source avoids the dance entirely (locally built apps are never quarantined): pnpm build && pnpm --filter @puddle/desktop dist.
Host requirements: Linux (glibc — Ubuntu 22.04+, Debian 12+, RHEL 9+; Alpine is not supported) or macOS, with git and curl, plus whichever agent CLIs you want on PATH. The client side works from any OS with a browser and ssh (Windows works, with repeated auth prompts unless you use a key).
- The Puddle daemon works anywhere you can SSH into. It is installed on your host during every fresh connect, relaying information across SSH to your local GUI. The daemon is the parent of every agent process, keeping sessions running when your laptop sleeps, the window closes, or the SSH connection drops. Puddle also maintains a stateful memory of your conversations to survive machine reboots.
- Puddle orchestrates parallel isolated agents each working in a unique git worktree and branch. You can choose the branch and worktree during session creation.
- Puddle's lightweight GUI allows you to track agent progress, session usage, and active worktrees.
- Puddle's philosophy is that any good developer must stay grounded in their code. Puddle natively integrates live terminals, file editing in Monaco, git commit grahps, diff views, and opens worktrees in your favourite IDE.
- Multiple profiles and accounts enable several collaborators to collaborate on a shared remote host. Puddle manages multiple accounts per agent type and profile, symlinking conversation histories so you can run from multiple Claude Code accounts at once and move your conversations between each.
client machine host machine (local or remote)
┌──────────────────────────────┐ ┌───────────────────────────────────┐
│ browser ── localhost:7433 │ │ puddled (systemd user service) │
│ │ │ local: │ ├─ REST + WS API │
│ puddle CLI ◄─┘ │ direct │ ├─ PTY manager │
│ ├─ static web UI assets │───────►│ ├─ git worktree manager │
│ └─ /api + /ws proxy │ remote:│ ├─ per-agent adapters │
└──────────────────────────────┘ ssh -L │ └─ SQLite + append-only logs │
└───────────────────────────────────┘
The CLI serves the UI at a stable local origin and reverse-proxies the API to the daemon, directly in local mode, through the tunnel in SSH mode. The daemon is headless and host-agnostic on 127.0.0.1:7434. UI updates ship with the CLI (npm update -g @puddle-code/cli refreshes the cockpit for every host); the daemon only has to update when the versioned protocol breaks, and the CLI does that automatically. A mandatory bearer token plus Host/Origin validation guard the localhost API against malicious web pages.
Everything lives under ~/.puddle on the host, installed without sudo — and puddle remove daemon takes it apart again.
One daemon, many clients. There is a single local daemon per machine, living under ~/.puddle and run by one supervised service (launchd's dev.puddle.puddled on macOS, systemd's puddled on Linux). The global puddle and a repo-run node packages/cli/dist/index.js are both just clients that talk to — and, when needed, install — that same daemon. They never run side by side, and there is no separate "dev daemon" alongside a "production daemon".
Dev build vs. production. npm i -g @puddle-code/cli is the production path — its puddle fetches and upgrades the daemon from this repo's GitHub Releases. To exercise uncommitted changes, build and run from the repo:
pnpm build && pnpm build:tarball
node packages/cli/dist/index.js start --tarball dist-release/puddled-v*.tar.gz --foreground--tarball sets the install source only, and is consulted only when the CLI actually installs the daemon — when none is running, the daemon is stopped, or a protocol-major upgrade fires. If a compatible daemon (same protocol major) is already up, start just serves the cockpit against it and the tarball is ignored (even a newer app version — nothing compares app versions). So to load a fresh dev build over a running daemon you must stop it first (see Kill below), then re-run start --tarball …. --foreground keeps the cockpit attached (connect <user>@<host> --tarball … is the remote form). Both clients share one ~/.puddle daemon and cockpit registry, so puddle list / puddle kill see either — don't point both at the same host at once. (Never launch the daemon from inside a coding-agent shell: it inherits the agent's env and breaks conversation resume — use a plain terminal.)
Kill. puddle kill --all (or Ctrl-C in a --foreground run) stops the local cockpit UI only; the daemon and its agent sessions keep running. The daemon is auto-restarting (launchd KeepAlive, systemd Restart=always), so a plain kill <pid> bounces straight back — stop it through its supervisor:
launchctl bootout gui/$(id -u)/dev.puddle.puddled # macOS (launchd)
systemctl --user disable --now puddled # Linux (systemd user unit)
kill "$(cat ~/.puddle/puddled.pid)" # nohup fallback (no supervisor)Restore the production daemon. When you're done testing, puddle remove daemon (answer no to the purge question — your profiles, sessions, and worktrees stay), then run the production puddle launch, which refetches the daemon from GitHub Releases. (Removal is what forces the refetch: the installer skips a version whose files are already present, so a dev build sharing the release's version number would otherwise stay put.)
Uninstall. Removing the CLI alone leaves the daemon installed and running — a full teardown is:
puddle remove daemon --purge # stops the daemon, unregisters its service, deletes ~/.puddle
puddle remove cli # npm uninstall -g, once the daemons you care about are gone
⚠️ ~/.puddleis your local state — the SQLite database with every profile, account, and session (plus conversation history), the daemon's worktree tracking, and the auth token.--purgedeletes it irreversibly (the command lists dirty or unpushed worktrees and asks first); without it,puddle remove daemonkeeps the data for a later reinstall.
Puddle is licensed under the MIT License. Copyright (c) 2026 Yiding Song.