{"slug": "show-hn-runkit-a-browser-based-tmux-manager", "title": "Show HN: RunKit – a browser based tmux manager", "summary": "RunKit, a browser-based tmux manager from the shll toolkit, launches as a remote console that exposes live tmux sessions and panes in a sidebar, designed to let users monitor multiple AI coding agents simultaneously without wrapping any agent's protocol. The tool, installed via `curl -fsSL https://shll.ai/install | sh`, relies on sibling tools like `wt` for worktree management and provides a dashboard at localhost:3000, with commands such as `run-kit riff` spawning agent workspaces in parallel. Creator Sahil87 emphasizes that RunKit is agent-agnostic, stating, 'The agent is one of the things you run, not the thing run-kit is,' ensuring the terminal layer remains stable as agent tooling evolves.", "body_md": "Part of the\n\n[shll toolkit]— see all projects there.\n\n**Your tmux, in the browser and on your phone.** run-kit is a remote console for the machine you actually work on — every tmux session and pane as a live terminal, in a sidebar, from your desk or your couch. It's the modern, terminal-native answer to the old server web-console: nothing to configure, no database, state read straight from tmux.\n\nWhat makes it sing in 2026 is what you tend to run in those panes: **AI coding agents, many at once.** `rk riff`\n\nspawns each one in its own [git worktree](https://github.com/sahil87/wt), and the dashboard lets you watch the whole fleet. But run-kit never wraps the agent — a pane is just a pane. It's equally a build, a REPL, an ssh session, `htop`\n\n. **The agent is one of the things you run, not the thing run-kit is.** That's the point: when the agent tooling churns underneath you (and it does, monthly), the terminal layer stays put.\n\n```\ncurl -fsSL https://shll.ai/install | sh\n```\n\nInstalls the entire shll toolkit via Homebrew, handling tap trust automatically. run-kit relies on its sibling tools (`wt`\n\nfor the riff worktree flow), so the full-toolkit install is the supported path.\n\nFrom install to a working dashboard with one agent running:\n\n```\nrun-kit agent-setup             # optional, once per machine: agent busy/waiting/idle in the dashboard\nrun-kit daemon start            # start the dashboard daemon on :3000\nopen http://localhost:3000      # open the dashboard in your browser\n\n# in a tmux session (tmux new -s work if you aren't in one):\nrun-kit riff                    # spawn an agent workspace (--skill /name picks the slash-command)\n```\n\n`run-kit riff`\n\nalso needs [ wt](https://github.com/sahil87/wt) on your\n\n`PATH`\n\n— included with the full-toolkit install, or `shll install wt`\n\n— and your agent CLI available. When something fails, `run-kit doctor`\n\nprints per-dependency status.The new workspace appears in the sidebar; click into it to drive the agent — or any command — from the browser.\n\nThe formula also installs `rk`\n\nas a fully interchangeable short alias of `run-kit`\n\n, so every command here works the same whether you type `run-kit`\n\nor `rk`\n\n.\n\nTo upgrade later, run `run-kit update`\n\n— pulls the latest version via Homebrew and restarts the daemon so the new binary takes effect immediately.\n\nComing from the oldrun-kit was originally published as`rk`\n\nformula?`sahil87/tap/rk`\n\n. If brew warns that`sahil87/tap/rk was renamed to sahil87/tap/run-kit`\n\n, you have a keg installed under the old name — remove it with a benign`brew uninstall sahil87/tap/rk`\n\n(your config and the`rk`\n\ncommand alias are unaffected), then`brew install sahil87/tap/run-kit`\n\nif`run-kit`\n\nis no longer on your`PATH`\n\n.\n\nSee the [install & access guide](/sahil87/run-kit/blob/main/docs/site/install.md) for prerequisites, `run-kit doctor`\n\n, development setup, and driving run-kit from your phone over Tailscale HTTPS.\n\n| run-kit | |\n|---|---|\nIt is |\nA remote, phone-first console for your tmux — agent-agnostic, no database, state derived from tmux + filesystem. A spawner (`run-kit riff` ) and a dashboard (`run-kit serve` ) that compose. |\nIt isn't |\nAn agent wrapper. It doesn't speak any agent's protocol, parse any agent's output, or care what's in the pane. That's deliberate — it's what makes it outlive whichever agent you run. |\n\n**A remote terminal console, not an agent wrapper**— run-kit exposes your tmux, full stop. Drive an agent in one pane, a dev server in the next, an ssh session in a third. Because it's agent-agnostic, it outlives whatever coding agent you're running this month.**One command per parallel agent**—`run-kit riff`\n\ncreates a worktree, opens a tmux window in it, and launches your agent.`run-kit riff -N 3`\n\nspawns three workspaces in parallel; failures roll back cleanly.**Watch a whole fleet, from anywhere**— every tmux session and pane shows up in a sidebar. Click for a live browser terminal; pin several into a[board](#boards--watch-many-panes-at-once)to watch three agents side-by-side; open the same dashboard on your phone over Tailscale.**Mobile-first, keyboard-first**—`Cmd+K`\n\ncommand palette is the primary discovery surface. Touch targets are tuned for mobile so you can steer a session from your phone while away from your desk.**No database, no daemon magic**— state is derived from tmux and the filesystem, the way a good console mirrors the system it manages. Sessions survive`run-kit`\n\nrestarts because the daemon never touches them.**The dashboard layer over**—and`fab-kit`\n\n`wt`\n\n`run-kit riff --skill /fab-fff`\n\nlaunches a full fab-kit pipeline in an isolated worktree. Reach for run-kit when you have more parallel changes than one terminal can hold.\n\nrun-kit is two independent halves that compose (the command is `run-kit`\n\n; `rk`\n\nis the fully interchangeable short alias people tend to type):\n\n```\nrun-kit riff         run-kit serve\n  ▼                    ▼\nspawns agent        runs the\nworkspaces ─────►   browser dashboard\n(tmux + worktree)   (watches tmux)\n```\n\nYou can run either alone. Run `run-kit riff`\n\nin any tmux session without ever starting `run-kit serve`\n\n— you get the spawning behavior, no dashboard. Run `run-kit serve`\n\nand never call `run-kit riff`\n\n— you get a tmux browser dashboard for sessions you spawn manually. The two are designed to compose, not depend on each other.\n\nOne invocation gives you a git worktree, a tmux window inside it, and one or more panes ready to go. The default pane runs your coding agent, but a pane can run anything — `run-kit riff`\n\nis a workspace launcher, not an agent launcher.\n\n**Pane array model.** `--skill`\n\nand `--cmd`\n\nare repeatable. Each occurrence adds one pane; argv order (left to right) becomes pane order. Bare `--skill`\n\nopens a blank agent session; bare `--cmd`\n\ndrops into `$SHELL`\n\n.\n\n**Layouts.** `auto`\n\n(default), `tiled`\n\n, `even-horizontal`\n\n, `even-vertical`\n\n, `main-horizontal`\n\n, `main-vertical`\n\n. Set with `--layout`\n\n.\n\n**Presets.** Common pane/layout combos go in `fab/project/config.yaml`\n\nunder `riff.presets.<name>`\n\n. Invoke as `run-kit riff <name>`\n\nor `run-kit riff --preset <name>`\n\n.\n\n**Parallel.** `-N <N>`\n\nspawns N workspaces in parallel; failures roll back successful ones before exiting.\n\n**wt passthrough.** Flags after `--`\n\ngo to `wt create`\n\nverbatim (e.g. `--base`\n\n, `--reuse`\n\n, `--worktree-name`\n\n).\n\nExamples:\n\n```\nrun-kit riff                                         # 1 pane, default skill (/fab-discuss)\nrun-kit riff --skill /fab-fff                        # 1 pane, specific slash-command\nrun-kit riff --skill /fab-fff --cmd \"just dev\"       # 2 panes (agent + dev server)\nrun-kit riff --skill /a --cmd x --cmd y --layout main-vertical\nrun-kit riff ship                                    # invoke the 'ship' preset\nrun-kit riff ship -N 3                               # 3 parallel ship workspaces\nrun-kit riff -- --worktree-name pacing-canyon        # name the worktree\n```\n\n**Prerequisites:** must be inside a tmux session, [ wt](https://github.com/sahil87/wt) on\n\n`PATH`\n\n, and the launcher (default `claude --dangerously-skip-permissions`\n\n) available. Override the launcher per-project via `agent.spawn_command`\n\nin `fab/project/config.yaml`\n\n— point it at any agent CLI, or any command at all.See the [riff guide](/sahil87/run-kit/blob/main/docs/site/workflows.md) for the full reference.\n\nStart the HTTP server in the foreground. Configurable via `RK_HOST`\n\n(default `127.0.0.1`\n\n) and `RK_PORT`\n\n(default `3000`\n\n).\n\n```\nrun-kit serve                                # foreground on 127.0.0.1:3000\nRK_HOST=0.0.0.0 RK_PORT=8080 run-kit serve   # bind all interfaces, port 8080\n```\n\nTo run it in the background, use the `run-kit daemon`\n\nsubcommands:\n\n```\nrun-kit daemon start                         # background daemon in a tmux session\nrun-kit daemon restart                       # stop and start\nrun-kit daemon stop                          # graceful shutdown\nrun-kit daemon status                        # show daemon state and port owner\n```\n\nThe daemon runs in its own dedicated tmux server (`rk-daemon`\n\n), completely separate from your sessions. Restart the daemon and everything you're running keeps running — the console reconnects automatically.\n\nEach window in the sidebar, dashboard, and pane panel carries a single **status dot** that tells you where it sits in the fab → PR lifecycle and how healthy it is — using two orthogonal channels:\n\n**Hue = phase**(where in the journey):[intake →](https://camo.githubusercontent.com/20f4207eb67087d28b400bc185e95886db0e031a83ec422368cc4f29f6bd2ec5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f696e74616b652d3630613566613f6c6162656c3d)[execution (apply/review) + completion (hydrate) →](https://camo.githubusercontent.com/b6f918ec2bd8146bf30cda8b04e6a2b3466e3b3c88dd4253a23511829d183a1a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f657865632d6662626632343f6c6162656c3d)[shipping (ship/review-pr) →](https://camo.githubusercontent.com/defbefe2e0a011d33c85bf441b4e05cf194533dfe14c63b102de2ef2addb46fb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f736869702d3965636536613f6c6162656c3d)[the live PR. A plain window with no fab change is gray — color is reserved for the journey.](https://camo.githubusercontent.com/590fe1cb36744f150dda409e0a7425a919f63b9add6c752c3dfb3a5362746d98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f70722d6330383466633f6c6162656c3d)**Shape = status**(health), one vocabulary across every phase:** ring**= pending ·** solid circle**= active/ready ·** dashed ring + red center**= failed ·** square**= done/merged ·** gray ring**= skipped/closed.\n\nExactly one signal drives the dot, in precedence order **PR > fab > tmux**.\n\nSee the [status dot reference](/sahil87/run-kit/blob/main/docs/site/status-dot.md) for the full matrix, the per-state rendering, and the design rationale.\n\nWindows running an AI agent can report a live lifecycle state in the sidebar and pane panel: **active** (turn in progress), **waiting** (blocked on you — a permission prompt or question), or **idle** (turn done, with elapsed duration). `waiting`\n\nis the state worth a glance at your phone: the agent isn't working, it's waiting for *you*.\n\nThis is opt-in and needs a one-time setup per machine:\n\n```\nrun-kit agent-setup              # shows the settings diff, asks before writing\nrun-kit agent-setup --uninstall  # removes exactly the run-kit-owned entries\n```\n\nIt installs agent-harness hooks into your user-global agent config (v1: Claude Code, `~/.claude/settings.json`\n\n) that stamp a `@rk_agent_state`\n\ntmux pane option on lifecycle events. Each hook is a thin, stable wrapper that delegates to `run-kit agent-hook`\n\n— a stable interface whose logic (the pid resolution, the value write) lives in the binary. No run-kit **server** is needed at fire time, and because the logic is in the binary, hook fixes track `brew upgrade run-kit`\n\nwith no settings changes and no session restarts. They work for any session, in any repo, under any workflow. Idempotent: re-running updates run-kit's entries in place (recognizing and replacing older-generation entries too) and never touches your other hooks. Until it's run (and agents are restarted so new sessions pick up the hooks), agent state shows `—`\n\n.\n\nUpgrading from an earlier run-kit?Older installs had the hooklogicinlined in`settings.json`\n\n. Run`run-kit agent-setup`\n\nonce more to swap in the new delegating wrapper, then restart your agent sessions (harnesses snapshot hook config at session start). This is the last time a hooklogicchange needs a re-setup — future fixes ship in the binary. (Changes to which events map to which state still need a re-setup, since that mapping lives in the settings entries.)\n\nThe cross-repo convention is documented in [ docs/specs/agent-state.md](https://github.com/sahil87/run-kit/blob/main/docs/specs/agent-state.md).\n\nA **board** is a named, cross-server pane dashboard. Pin any tmux window from any server into a board, and the board renders all pinned panes side-by-side in a horizontally-scrollable layout — perfect for watching three parallel agent sessions, or comparing a `just dev`\n\nserver's output against the agent that's editing it.\n\nThree ways to pin a window to a board:\n\n**Sidebar pin icon**— every window row in the sidebar has a pin icon. Click it to open a popover listing existing boards (click to pin/unpin), plus a \"Pin to new board…\" input that creates a new board on first pin.**Command palette (**—`Cmd+K`\n\n)`Board: Pin Current Window`\n\n,`Board: Unpin Current Window`\n\n,`Board: Switch to <name>`\n\n,`Board: Leave Board View`\n\n.**Board pane header**— each pinned pane shows an unpin button in its header for one-click removal.\n\nInside a board:\n\ncycles pane focus to the next / previous pane (wraps).`Cmd+]`\n\n/`Cmd+[`\n\n**Click a pane** to focus it; keystrokes route to that pane's terminal.**Drag the pane edge** to resize (desktop only; widths persist per-board in`localStorage`\n\n).**On mobile**, panes render as a single-pane swipe carousel.\n\nPin state lives in tmux (via the `@rk_board`\n\nwindow option) so it follows the window, not the browser — open the same board URL on your phone and you see the same panes. Pane widths are intentionally local to each device.\n\nSome browser features (clipboard, secure context) require HTTPS. Accessing run-kit from another machine on your tailnet also requires HTTPS:\n\n- Enable HTTPS at\n[DNS > HTTPS Certificates](https://login.tailscale.com/admin/dns). - Run\n`tailscale serve --bg http://localhost:3000`\n\n. - Open\n`https://<machine>.<tailnet>.ts.net`\n\non your phone or another laptop.\n\nFor a stable custom hostname or public access via Funnel, see the [Tailscale guide](/sahil87/run-kit/blob/main/docs/site/install.md).\n\nAny process on the box can push a real OS-level notification to your phone or\ndesktop — even when the RunKit PWA tab is **closed** — via Web Push:\n\n```\nrun-kit notify \"deploy finished\" --title \"CI\"\n```\n\n`run-kit notify`\n\nPOSTs to the local server, which fans the message out to every\nsubscribed browser using the Web Push protocol (signed with a server-side VAPID\nkey persisted under `~/.rk/`\n\n). It is **fail-silent**: if the server is\nunreachable or returns an error it exits 0 and prints nothing, so it never\nstalls a calling script or agent loop.\n\n**Opt in from the browser**: click the **bell icon** in the top bar (or open the\ncommand palette with `Cmd+K`\n\nand run **Notifications: Enable push**). This\nrequests notification permission and subscribes the current device. There is no\nsettings page — the bell dropdown and the palette are the opt-in gestures. The\nbell dropdown also offers **Send test notification** (a local test that bypasses\nthe server) and a **Notifications help** link.\n\nSee the [notifications guide](/sahil87/run-kit/blob/main/docs/site/notifications.md) for setup and the\ncommon \"it says sent but nothing appears\" troubleshooting (almost always an\nOS-level notification block — e.g. macOS Focus mode).\n\nSecure-context requirement: Web Push (service worker +`PushManager`\n\n) only works in a[secure context]— that meansHTTPS or. Hitting run-kit on`localhost`\n\n`localhost:3000`\n\nor behind a TLS reverse proxy (e.g.`tailscale serve`\n\n, see[Drive it from your phone]) both qualify. Over plain HTTP to a remote host, the browser silently refuses to register the service worker and theEnable pushcommand will report that a secure context is required.\n\n`run-kit shell-init <shell>`\n\nemits eval-safe tab-completion for your shell (it registers completion for both `run-kit`\n\nand the `rk`\n\nalias). Add this line to your rc file:\n\n```\neval \"$(run-kit shell-init zsh)\"   # in ~/.zshrc\neval \"$(run-kit shell-init bash)\"  # in ~/.bashrc\n```\n\nSupports `zsh`\n\n, `bash`\n\n, `fish`\n\n, and `powershell`\n\n. Completion-only — run-kit has no shell function wrapper; every subcommand is reached via `run-kit <subcommand>`\n\n(or the `rk`\n\nalias).\n\n💡 Have other shll tools?\n\n[handles all of their shell integrations and autocompletions at once.]`shll shell-install`\n\n| Command | What it does |\n|---|---|\n`run-kit riff` |\nCreate a worktree + tmux window + agent/command pane(s). |\n`run-kit serve` |\nStart the HTTP server (foreground or daemon). |\n`run-kit status` |\nShow a tmux session summary. |\n`run-kit url` |\nPrint the run-kit server URL (config-derived from `RK_HOST` /`RK_PORT` , default `http://127.0.0.1:3000` ) — a heuristic for AI agents, not a liveness probe. |\n`run-kit skill` |\nPrint the agent skill bundle — a static usage briefing for agents operating run-kit (canonical source `docs/site/skill.md` ); `run-kit skill display` prints the visual-display topic page. |\n`run-kit notify` |\nSend a Web Push notification to your subscribed devices (see\n|\n\n`run-kit doctor`\n\n`run-kit agent-setup`\n\n[Agent state](#agent-state--run-kit-agent-setup)). Once per machine;`--uninstall`\n\nreverses it.`run-kit init-conf`\n\n`tmux.conf`\n\nand `tmux.d/`\n\ndrop-in directory to `~/.rk/`\n\n. Optional.`run-kit update`\n\n`run-kit completion`\n\n`run-kit shell-init`\n\nfor eval-safe output).`run-kit help`\n\nEvery command is also reachable via the short `rk`\n\nalias (e.g. `rk riff`\n\n). Run `run-kit <command> --help`\n\nfor full flag details, or see the [full command reference](https://shll.ai/tools/run-kit/commands/) for every command and flag.\n\n— riff requires`run-kit riff`\n\nfails with \"not in a tmux session\"`$TMUX`\n\nto be set. Start tmux first (`tmux new -s work`\n\n), then run`run-kit riff`\n\ninside it.— install`run-kit riff`\n\nfails with \"wt not found\"`wt`\n\nvia`shll install wt`\n\n, or install the full toolkit from[https://shll.ai](https://shll.ai).**Agent state shows**— run`—`\n\nfor every window`run-kit agent-setup`\n\nonce on the machine, then start a fresh agent session (hooks apply to new sessions, not already-running ones). A pane sitting at a plain shell also reads`—`\n\nby design — state clears when the agent exits.**Anything else broken**— run`run-kit doctor`\n\n. It checks tmux,`wt`\n\n, the launcher binary, port availability, and prints per-dependency status.\n\nrun-kit's daemon runs in a dedicated tmux server (`rk-daemon`\n\n), separate from your sessions (`runkit`\n\n). Restarts use kill-and-restart (no polling loop or signal files), are idempotent (`--restart`\n\nworks whether or not a daemon is running), and never touch your tmux sessions — everything you're running survives daemon restarts unaffected.", "url": "https://wpnews.pro/news/show-hn-runkit-a-browser-based-tmux-manager", "canonical_source": "https://github.com/sahil87/run-kit", "published_at": "2026-07-22 07:26:57+00:00", "updated_at": "2026-07-22 07:52:22.899864+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "artificial-intelligence"], "entities": ["RunKit", "shll toolkit", "Sahil87", "Homebrew", "Tailscale"], "alternates": {"html": "https://wpnews.pro/news/show-hn-runkit-a-browser-based-tmux-manager", "markdown": "https://wpnews.pro/news/show-hn-runkit-a-browser-based-tmux-manager.md", "text": "https://wpnews.pro/news/show-hn-runkit-a-browser-based-tmux-manager.txt", "jsonld": "https://wpnews.pro/news/show-hn-runkit-a-browser-based-tmux-manager.jsonld"}}