Install
The manual routes — plugin or plain clone — and the optional Desktop launcher.
You need Claude Code; the skill itself needs just Bash. The
console additionally needs Node 22.18 or newer (or 23.6+) with npm — its client is built
output: one npm ci && npm run build inside viewer/ per machine. You do not have to remember
that: an unbuilt console serves a page naming the two commands and the exact directory to run them in.
Pick a route. A and B give you the skill and the console from one tree; C gives a project its
own supervised console from a clone inside the project's folder. There is no package: the
repository is the only channel, and a release is a tag on it — docs/releasing.md.
Route A — as a plugin (recommended: one line, updates itself)
A plugin is a package Claude Code installs for you. A marketplace is a catalog that lists
plugins. This repository is both — it ships a catalog called mobin containing one plugin, itself.
So installing is one command for each.
Step 1. Open Claude Code in any project and type:
/plugin marketplace add zsarir/phased-execution
Claude Code clones this repository, checks the catalog inside it, and remembers it as mobin.
Nothing is installed yet — a marketplace is only a list.
Step 2. Install the plugin from that catalog:
/plugin install phased-execution@mobin
The @mobin part says which catalog to take it from. It matters once you have several registered.
Step 3. Load it:
/reload-plugins
Or just restart Claude Code. Type /plugin to confirm it is listed — that screen also has an
Errors tab if something failed.
What you now have. The skill, as /phased-execution:phased-execution — Claude Code puts every
plugin's skills under the plugin's name so two plugins can both ship a review skill without
clashing. Type /phased and let autocomplete finish it. You will rarely type it at all: the skill
describes itself well enough that Claude reaches for it on its own when work is phased. You also get
phase-console, a command that starts the web app from any directory — the first run serves a page
naming the client's one-time build (npm ci && npm run build, with the exact path printed, since a
plugin lives in a cache directory you would otherwise have to hunt for).
Keeping it current. /plugin update phased-execution. This plugin sets no version number on
purpose, which puts it on the commit channel: every push to main counts as a new release, and
Claude Code also refreshes in the background. Restart to apply an update. An update moves the plugin
to a fresh directory, so the console will ask for its build once more — same two commands, same
printed path. (npm and Homebrew are the tagged channel instead: releases are vX.Y.Z tags with
a CHANGELOG, packed and published by CI with provenance. Same tree, two cadences
— the plugin tracks every commit, the packages track releases.)
Removing it. /plugin uninstall phased-execution@mobin, then optionally
/plugin marketplace remove mobin.
Route B — as a plain folder (if you want to edit the skill, or script against its path)
git clone https://github.com/zsarir/phased-execution.git ~/.claude/skills/phased-execution
Restart Claude Code. The skill is /phased-execution — no prefix, because it is not inside a plugin.
Build the console's client once (cd ~/.claude/skills/phased-execution/viewer && npm ci && npm run build), then start it with ~/.claude/skills/phased-execution/start. Update with git pull, then
rebuild — ./start --agent-update does both build and restart if it runs as a background agent.
Route C — a console copy inside your hub folder (one console per project, supervised)
The shape the console is developed and run in: the repository sits INSIDE the folder it serves —
<hub>/phased-execution/ (a submodule) or <hub>/console/ (a plain clone) — and that copy installs
itself as the login agent for that hub. Nothing lives under ~/.claude but the skill.
git clone https://github.com/zsarir/phased-execution ~/work/hub/phased-execution # or `git submodule add …`
~/work/hub/phased-execution/installer/install.sh # macOS, Linux, WSL2
# Windows: powershell -ExecutionPolicy Bypass -File installer\install.ps1 (runs the same script in WSL2)
installer/install.sh builds the client once, writes and starts the unit (launchd on macOS,
systemd --user on Linux) for the hub folder holding the copy, and puts a launcher on the Desktop
that starts exactly this copy. It remembers --remote/--remote-user from an existing unit, so a
re-install never turns a Tailscale-published console into a wall of 421s. --root DIR serves another
project; --minimal installs with no capability switch; --dry-run prints the command and installs
nothing; installer/uninstall.sh removes the unit. Updating is git pull in the copy, then the
installer again. Details: installer/README.md.
Which route?
| Plugin | Clone | Hub copy | |
|---|---|---|---|
| Install | two commands, inside Claude Code | one git clone | one git clone, then installer/install.sh |
| Updates | automatic, every commit to main | when you git pull | git pull, then the installer again |
| Skill name | /phased-execution:phased-execution | /phased-execution | /phased-execution, after phase-console install-skill |
| Console | phase-console, from anywhere | ./start, from the folder | a login agent for that project, with a Desktop launcher |
| Lives at | a per-version cache directory that moves on every update | wherever you cloned it, permanently | <hub>/phased-execution/ or <hub>/console/ |
| Suits | wanting it present and current, with nothing to maintain | scripting against the path, or editing the skill itself | one console per project, supervised, surviving reboots |
Plugin and clone at once works, but you would see the skill twice and pay its always-on cost twice — pick one of those two for the skill; a hub copy can sit beside either for the console.
Linux, and Windows through WSL2
Every route above works on Linux exactly as written. The differences are below; there is no native Windows build, and on Windows the whole thing (Claude Code included) runs inside WSL2.
- The background agent is a systemd user service.
phase-console --install-agent --root <repo>writes~/.config/systemd/user/phase-console.service(Restart=always, same 150s stop grace as the launchd plist) and starts it — the app's own Restart and Shut-down buttons work the same as on macOS. It stops at logout unless you runloginctl enable-linger $USERonce. Installing a console for a second project writes its own unit,phase-console-<id>.service, so the one you already have is never renamed;phase-console listprints which unit belongs to which project. - On WSL, systemd must be on (it is on current WSL2 installs). If the install says so: add
[boot]+systemd=trueto/etc/wsl.conf, runwsl --shutdownfrom Windows, reopen. Until then — or instead — just runphase-console --root <repo>in a tmux window. WSL parks its VM when nothing runs in it, so the console is up whenever WSL is. - The browser. On a Linux desktop the console opens via
xdg-open. On WSL it hands the URL to Windows (wslview); if nothing can open one it prints the URL — WSL2 forwards localhost, sohttp://127.0.0.1:4123in your Windows browser just works. - The Terminal page (optional). Its native module (
node-pty) has no Linux prebuilds, so npm compiles it during install if build tools exist —sudo apt-get install -y build-essential python3first. Skipping this loses only the in-browser shell: board, writes, autopilot and agent sessions all run without it, and the Terminal page names exactly what is missing. - The Desktop launcher below is macOS-only (a Finder
.commandfile). On Linux the systemd agent is the equivalent — it is the supervised mode the launcher'sSUPERVISED="yes"provides.
Give yourself a launcher (optional, macOS — the double-click way to a supervised console)
A double-click that starts the console. Started with SUPERVISED="yes" it installs a launchd
agent, which is what makes the app's own Restart and Shut down buttons work — those exist
only where a clean exit comes back, and a window you double-clicked is the server's parent, not its
supervisor. Paste this into Claude Code:
Set up a Phase Console launcher on my Desktop.
1. Find the skill: whichever of ~/.claude, ~/.claude-a or ~/.claude-b contains
skills/phased-execution/viewer/server/index.ts — or, for a packaged install,
$(npm root -g)/phase-console or $(brew --prefix phase-console)/libexec.
2. Copy viewer/deploy/desktop-launcher.command from there to
"~/Desktop/Phase Console.command", and make it executable.
3. Open the copy and walk me through the knobs at the top, one at a time:
ROOT the repository the console reads — it must contain docs/plans
WRITES --allow-writes: scaffold plans/handoffs, record QA, take locks, close plans
RUNS --allow-run: spawn unattended Claude sessions that edit ROOT
TERM_FLAG --allow-terminal: a real shell in the browser, running as me
AGENT --allow-agent: interactive claude sessions + the New-plan wizard
ACCOUNTS --allow-accounts: register more than one Claude account and let a
run move to one with headroom (the usage meters work without it)
MCP --allow-mcp: register MCP servers and attach them to plans and
phases (reading the registry and its statuses works without it)
PORT leave blank — each project derives its own; set one to pin it
SUPERVISED leave "yes" — it installs a launchd agent, and that is what makes
the app's own Restart and Shut down buttons work
Blank out any door I do not want opened, and explain any I am unsure about
before changing it.
4. Then tell me to double-click it — do not run it yourself. Its first run can
install a background agent that starts at login, and that is my call.
The Desktop file is a copy, not a link: updating the skill does not update it.
Re-copy it after an update — it prints a warning when it is older than the one
in the repo.
Installing from a terminal instead — for dotfiles scripts and container images
claude plugin marketplace add zsarir/phased-execution
claude plugin install phased-execution@mobin
claude plugin details phased-execution@mobin # components + token cost
claude plugin update phased-execution
claude plugin uninstall phased-execution@mobin