@dylanpiercey/work

中文文档
0.2.92发布于 2026/11/13MITES Module近 30 天下载 8963

Web GUI for agentic dev workspaces

原始使用文档
文档目录7 节
  1. Install (bare machine)
  2. Develop
  3. Run
  4. From the command line (and agents)
  5. Access
  6. Configuration
  7. Layout on disk

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 | bash

Already 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). Under a version manager (mise, as the installer sets up; nvm, asdf, fnm) work is installed inside that one Node version's directory, so upgrading or removing that Node removes work with it: with the new Node active, install it again the same way (work doctor says when this applies).

Develop

Requires Linux or macOS with git, tmux, gh (authenticated), and Node 24+. The bootstrap script installs the tools via mise and runs pnpm install; GitHub sign-in and the agent CLIs are the app's own Settings:

./scripts/bootstrap.sh

Run

pnpm dev                  # http://localhost:7171

# 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

From the command line (and agents)

Everything the app's pages do has a work command too, so an agent — or a script — can use and set up work from a terminal: work help lists them. Inside a workspace, work branches, work session, work topic, work review, work notify and work open (agents delegate through their own CLI's subagents, not through work); to change things, work workspace create, work repo add, work config get|set (checked against what each setting takes; work config schema lists them), work agent|skill|lsp|host and work gh login; work status sums the machine up, and work procs prints each workspace port's link as the user's browser would open it. Every command takes --json (JSON alone on stdout) and never prompts under it or --non-interactive.

Access

work has no login of its own — it runs agents and terminals as you, so it answers this machine only by default (it listens on 127.0.0.1). To reach it from other devices, put it behind something that terminates TLS and authenticates — a reverse proxy with a login, a Cloudflare Tunnel with Access, tailscale serve — and tell work about it:

  • WORK_ALLOWED_HOSTS=work.example.com — the name(s) the proxy serves (their workspace-port subdomains are included). work refuses any other name, which is what stops a web page elsewhere from pointing its own name at your machine (DNS rebinding).
  • If the proxy runs on another machine, work has to listen on the network for it: WORK_LISTEN=0.0.0.0 and WORK_TRUSTED_PROXIES=<proxy ip> (IPs or CIDRs, comma-separated). work then answers that proxy and this machine, and refuses everyone else on the network, who would otherwise walk around the proxy's login. WORK_TRUSTED_PROXIES=* answers any machine — only on a network you trust as it is.

Set them when installing (WORK_ALLOWED_HOSTS=… WORK_TRUSTED_PROXIES=… WORK_LISTEN=0.0.0.0 work setup); work setup keeps them in the service from then on. A refused request gets a page saying which setting it needs. Everything (pages, API, and the /term websockets) serves from the single app port, so route the whole hostname to it.

Tailscale is the zero-config way. On a machine logged in to Tailscale (1.52 or newer), work setup offers to run tailscale serve --bg <port>, which puts work at https://<machine>.<tailnet>.ts.net/ for your devices on the tailnet alone (never Funnel, which would publish it to the internet), and adds that name to WORK_ALLOWED_HOSTS: open it on a phone signed in to the same tailnet. work setup --tailscale does it without asking and --no-tailscale skips the question; --yes alone leaves Tailscale's config as it is. A serve config already pointing at work only has its name allowed, and work doctor says which of these holds.

Direct connections. Behind a proxy, a tunnel or a relay, terminals move to a direct WebRTC connection to this machine when it is measurably faster than the path through the proxy (Settings → Terminal → Direct connection: Auto by default, Always, or Off, one setting for every device). Pages, the API and sign-in still go through your proxy; the direct path is set up over the app's authenticated events socket, carries terminal traffic alone, encrypted (DTLS), to UDP port WORK_RTC_PORT (by default the app's port number), and ends when that login does. That port is held by a helper process of work's own, only while direct connections are in use: it starts at the first one and exits ten minutes after the last. Proxy-side inspection or logging does not see terminal traffic that goes direct: turn the feature off (per device in Settings, or WORK_RTC=off for the machine) where it must. On the LAN the direct path needs nothing more; from another network (a phone on cellular) the UDP port has to be reachable through your router. Settings → Terminal can allow work to open it on the router when needed (UPnP, off by default): only after a device failed to connect without it, leased, and given back once unused. A host firewall can keep a device out too, though usually it does not (ICE gets through a stateful one from most networks), so work says nothing of it until a device has failed to connect directly while nothing has come in through the port. Then work doctor says it drops the port, or may (where only root can read its rules, it judges from the defaults and gives the command that shows them), with the command that admits it, and work setup offers to add that rule, named work so it is removed as one (--firewall adds it without asking, --no-firewall skips the question). macOS's firewall admits programs rather than ports, so there it is the node the service runs that work doctor checks and work setup lets in. WORK_RTC_STUN names the STUN servers that find this machine's public address (Cloudflare's by default; empty for none).

A faster git status. Listing a large repo's untracked files is most of what git status costs, and work asks it of every checkout and topic branch's worktree. So the service turns on git's untracked cache (core.untrackedCache) in the repos work keeps (<work root>/.cache, whose worktrees are every workspace's checkouts), after which git reads again only the directories that changed; your agents' own git status gets faster too. It relies on directory modification times, so it is only turned on where the work root is a local filesystem with fine timestamps (not NFS, SMB, FUSE mounts, HFS+ or FAT) and git's own check passes there. A repo set core.untrackedCache=false is left alone, and git config --global core.untrackedCache false keeps it off everywhere; work doctor says which it is.

Opening workspace ports remotely. The port chips in the sidebar link to http://<host>:<port>, which only works where the machine is reachable directly — under a tailnet name too, since tailscale serve has no wildcard names: there a chip reaches a dev server that listens beyond loopback (--host), and one on loopback says so. Through a tunnel, route a wildcard hostname to the app port as well and work proxies it — HTTP and websockets, so HMR works — to localhost:<port>. WORK_PORT_HOSTS picks the hostname shape the chips link to; sub is always accepted, dash only when picked, and only for a name of three labels or more:

  • sub (default): https://3000.work.example.com. Needs a wildcard *.work.example.com route and a certificate that covers it (your own reverse proxy with a DNS-01 wildcard; Cloudflare only with Advanced Certificate Manager, since Universal SSL covers one label).
  • dash: https://3000-work.example.com. One label under the zone, so a Cloudflare Tunnel works on the free plan. DNS wildcards match a whole label, so the tunnel's public hostname is *.example.com pointing at the app port, with an Access application on the same wildcard so the ports sit behind the same login as the app. Work ignores hostnames that do not start with a port, so other names under the zone are unaffected.

Only loopback ports on the work machine are reachable, behind the same auth as the app. API writes and the terminal websockets refuse a foreign Origin, so a page a workspace serves cannot drive work with the shared login cookie.

Configuration

VariableDefaultPurpose
WORK_ROOT~/workWorkspaces root (+ .cache bare repos)
WORK_DATA_DIR~/.local/share/worksqlite db and server state
WORK_APP_PORT7171HTTP server (app, assets, and /term websockets)
WORK_ALLOWED_HOSTS—Hostnames a proxy serves it under (see Access)
WORK_LISTEN127.0.0.1Listen address (0.0.0.0 for every interface)
WORK_TRUSTED_PROXIES—Proxy IPs/CIDRs allowed in from the network (*)
WORK_PORT_HOSTSsubPort-chip hostname shape: sub / dash (see above)
WORK_USER / WORK_HOSTcurrent user/hostBranch-name prefix parts
WORK_BRANCH_PREFIX<user>-<host>Whole branch-name prefix, overriding the parts
WORK_RTConoff turns direct connections off (see Access)
WORK_RTC_PORTthe app portUDP port of direct connections
WORK_RTC_STUNCloudflare's STUNTheir STUN servers, comma-separated (empty: none)

The 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. A script that waits for room in a window reads work usage --json, whose shape (and what each field means when a reading is stale) work help usage spells out.

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 + generated AGENTS.md (and CLAUDE.md symlink) 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.

版本与发布记录

@dylanpiercey/work 共发布 317 个版本,首次发布于 2026/08/13;过去 12 个月发布了 317 个版本。

版本发布日期距今
0.2.92latest2026/11/13今天
0.2.912026/11/103 天前
0.2.902026/11/058 天前
0.2.892026/11/0310 天前
0.2.882026/11/0310 天前
0.2.872026/11/0310 天前

关于 @dylanpiercey/work 的常见问题

@dylanpiercey/work 是什么?

Web GUI for agentic dev workspaces

如何安装 @dylanpiercey/work?

在项目目录运行 npm install @dylanpiercey/work,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 work,可以用 npx work 直接运行。

@dylanpiercey/work 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/dylanpiercey__work 是否存在。

@dylanpiercey/work 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@dylanpiercey/work 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dylanpiercey/work 可以商用吗?

@dylanpiercey/work 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dylanpiercey/work 的下载量有多少?

根据 npm 官方下载统计,@dylanpiercey/work 在 2026/10/13 – 2026/11/11 这 30 天内被下载 8,963 次,日均约 299 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dylanpiercey/work 还在维护吗?

最新版本 0.2.92 发布于 2026/11/13(今天);至今共发布 317 个版本,其中过去 12 个月发布了 317 个;首次发布于 2026/08/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。