@dylanpiercey/work
v0.0.120
Published
Web GUI for agentic dev workspaces
Readme
work
A self-hosted web GUI for agentic dev workspaces — on desktop and as a mobile PWA. Spin up multi-repo worktree workspaces, run coding agents (Claude Code, Codex, Copilot, Cursor, Grok) or plain shells in real terminals, review diffs and send feedback to agents, and watch PR status — from any device.
- Workspaces — named directories of git worktrees (one per GitHub repo, cloned from a shared bare-repo cache), all on a generated branch. Create, add/remove repos, archive/restore, delete.
- Sessions — real CLIs in tmux, mirrored to the browser over WebSocket (xterm.js). Sessions survive server restarts and phone locks; agent hooks surface working / waiting / idle state at a glance.
- Review — a fast diff view across every repo in the workspace, with line comments you can send straight into an agent session.
- Mobile-first PWA — installable, with a touch-tuned terminal (sticky keyboard toggle, d-pad for arrows/tab/ctrl-c, momentum scrolling).
Install (bare machine)
One command on a fresh Linux or macOS box — installs the system tools (git, tmux, a compiler for node-pty), mise + node, the published package, and the background service (systemd/launchd):
curl -fsSL https://cdn.jsdelivr.net/npm/@dylanpiercey/work/install.sh | bashAlready have node (and git/tmux)? npm i -g @dylanpiercey/work && work setup
does the same minus the system tools. Update later with work update (or
re-run the installer).
Develop
Requires Linux or macOS with git, tmux, gh (authenticated), and Node 22+.
The bootstrap script installs everything via mise,
offers the agent CLIs, and runs pnpm install:
./scripts/bootstrap.shRun
pnpm dev # http://localhost:7171For a production build plus a background service (systemd on Linux, launchd on macOS):
./scripts/setup-prod.sh # build + install + start the service
# While hacking on work itself, point the background service at a checkout
# (and back at the npm install when done):
cp scripts/work-source.sh ~/.local/bin/work-source && chmod +x ~/.local/bin/work-source
work-source local # this tree (or: work-source local /path/to/work)
work-source rebuild # rebuild + restart without rewriting the unit
work-source prod # global @dylanpiercey/work again
work-source # status
./scripts/run-prod.sh # or: build with --no-service and run manually
./scripts/update.sh # later: pull latest, rebuild, restartTo reach it from other devices, put it behind something that terminates TLS
and authenticates — e.g. a Cloudflare Tunnel with Access, or Tailscale.
Everything (pages, API, and the /term websockets) serves from the single
app port, so route the whole hostname to it. Set
WORK_ALLOWED_HOSTS=your.domain so the dev server accepts the hostname.
Upgrading from the two-port layout: older setups routed
/term/*to a separate terminal port (7172). That port no longer exists — remove the/termrule from your tunnel/proxy config and send all traffic to the app port, or terminals will fail to connect.
Configuration
| Variable | Default | Purpose |
| -------------------- | ----------------------- | ------------------------------------ |
| WORK_ROOT | ~/work | Workspaces root (+ .cache bare repos) |
| WORK_DATA_DIR | ~/.local/share/work | sqlite db and server state |
| WORK_APP_PORT | 7171 | HTTP server (app, assets, and /term websockets) |
| WORK_ALLOWED_HOSTS | — | Extra dev-server hostnames (comma-separated) |
| WORK_USER / WORK_HOST | current user/host | Branch-name prefix parts |
| WORK_BRANCH_PREFIX | <user>-<host> | Whole branch-name prefix, overriding the parts |
Ports and paths can be exported before scripts/setup-prod.sh to bake them into
the service. For settings that should outlive an update, put them in an untracked
.env.local at the repo root instead — scripts/run-prod.sh reads it on every
start (the dev server does not), only WORK_* names apply, and the
surrounding environment still takes precedence:
WORK_BRANCH_PREFIX=rturnqThe usage panel (and work usage) reads plan/quota windows straight from each
agent CLI's own credentials on disk — Claude, Codex, Cursor, Grok, and Copilot
(via gh's token). Providers you are not signed into simply say so.
Running more than one work (a laptop and a desk box, say)? Settings →
Appearance gives each a name and an accent colour: the tab title, home-screen
icon, notifications, and the app's chrome all take them, so two windows or
two installed apps stop looking identical.
PR chips refresh by polling GitHub (faster for a few minutes after a
local push via repo-pushed). No inbound GitHub webhooks are required.
Layout on disk
~/work/<slug>-<id>/— a workspace: one worktree per repo + generatedAGENTS.md(andCLAUDE.mdsymlink) encoding the conventions~/work/.cache/github.com/<owner>/<repo>.git— shared bare-repo cache~/.local/share/work/work.db— sqlite database (authoritative state)
Terminals live in a dedicated tmux server (tmux -L work), kept alive by a
transient systemd unit so app restarts never kill your sessions.
