# workz v2 — The Environment Engine for Agent Worktrees > **Thesis:** Claude Code, Cursor, and Codex create worktrees now. Orchestrators are dying. > The one layer everybody punts on is making a fresh worktree *runnable* — deps, env files, > ports, databases, compose projects. That layer is `sync.rs` + `isolation.rs`. It is the only > part of workz nobody else has, and v2 strips everything that hides it. > > **One-liner:** *Your agent creates the worktree. workz makes it run.* Status: plan drafted 2026-07-02, based on a code audit + competitive survey + user-pain research. Supersedes the strategy sections of `ROADMAP.md` (the v0.8 "swarm" direction is cancelled). --- ## 1. Why v2 — the honest audit ### 1.1 Where v1 actually stands | Signal | Value | Read | |---|---|---| | GitHub stars | 68 | People like the idea | | crates.io downloads | 176 total, 30 recent | Almost nobody uses it | | Issues filed (ever) | 0 | Nobody uses it *deeply* | | External PRs | 1 (path fix) | One real user hit one real bug | | Dev cadence | v0.1→v0.8 in a 10-day sprint (Feb 25–Mar 6), dormant since | Feature-breadth demo, nothing hardened by use | | Show HN (Mar 2026) | 2 points, 1 comment | "Another worktree manager" positioning failed | ### 1.2 What the code audit found - **Fleet mode does not work.** `fleet.rs::launch_agent` spawns `claude` with **no arguments, no task prompt, and no TTY**. `.workz-task.md` is written but nothing ever tells the agent to read it. Interactive CLIs (claude/aider/codex) need a terminal; spawned detached they exit or hang. The flagship feature is a demo that can't drive agents. (This is why claude-squad is built on tmux.) - **`--isolated` clobbers user env.** `cmd_start` runs sync first (which copies `.env.local` from the main worktree), then `isolation::write_env_local` unconditionally overwrites `.env.local` — silently dropping the user's variables. - **Config merge is a footgun.** A project `.workz.toml` that customizes *any* sync list replaces **all 27 defaults**. There is no way to say "defaults + one change" or "copy node_modules instead of symlinking it." - **Heavy deps for marginal surface.** `serve.rs` (427 lines) drags in axum + tokio. `tui.rs` (1,115 lines) drags ratatui + crossterm for a 4-panel dashboard whose Fleet and Ports panels serve features being cut. - **Three identities.** Cargo.toml says "Zoxide for Git worktrees," README says "worktree manager for AI-native development," ROADMAP says "open-source Conductor for Linux." - **The good news:** `sync.rs` (451 lines) and `isolation.rs` (351 lines) are small, tested, and genuinely unique. The core is worth keeping. The wrapping isn't. ### 1.3 What the market says (research, mid-2026) **The orchestrator category collapsed:** | Tool | Stars | Status | |---|---|---| | vibe-kanban (Bloop) | 27,242 | **Shut down** Apr 2026 | | claude-squad | 7,995 | Abandoned (own top issues: "Project Seems Abandoned") | | crystal (stravu) | 3,097 | **Deprecated** Feb 2026, pivoted away | | uzi | 579 | Dead 13 months (was the only fleet CLI with managed ports) | Squeezed between **free native features** and **free Conductor**: - **Claude Code**: native `claude --worktree`, `EnterWorktree` tool, agent teams, `.worktreeinclude` (native .env copying!), `WorktreeCreate`/`WorktreeRemove` **hooks**. Docs literally say: *"Remember to initialize your development environment in each new worktree: install dependencies, set up virtual environments."* - **Cursor 2.0+**: up to 8 parallel agents in worktrees; `.cursor/worktrees.json` with user-authored `setup-worktree` commands. - **Codex app**: worktree threads + automations; per-worktree setup scripts (user-authored). - **Conductor** (free, Mac-only, weekly releases): setup scripts, env-var settings, run scripts. - **worktrunk** (`wt`, 5.7k stars in ~6 months, daily commits — the real CLI competitor): hooks, LLM commit messages, squash-merge flows, cache **copying** via config, stateless `hash_port` filter. **No** managed port registry, **no** DB/compose isolation, **no** zero-config dep detection. **Every single one of these ships a lifecycle hook and expects the user to write the setup command.** Nobody ships the setup command. **What users actually complain about** (HN threads 2025–2026, ranked): 1. *"git worktree still leaves you reinstalling node_modules per tree and fighting over a dev server port. That's the actual cost, and none of these tools touch it."* 2. Can't **run** the app to verify agent work — port conflicts, missing secrets, shared DBs. Verification is the bottleneck, not codegen. 3. DB / docker-compose isolation per worktree (multiple single-purpose tools appearing: wtdb, Silo, coasts.dev). 4. Review bandwidth — parallel agents multiply cognitive load (argues *against* fleet UIs). 5. Everyone hand-rolls the same 50–100-line setup/teardown scripts. 6. Symlinked `node_modules` breaking Vite/Vitest/pnpm monorepos (the #1 objection to workz's approach — needs a per-dir `copy` escape hatch). **Validation that the hook-filler slot is wanted:** claude-squad issue #260 (asking for exactly workz's env setup as a hook) has 8 reactions and a volunteer implementer. ### 1.4 The conclusion workz v1 is three products: an env engine (unique, works), an orchestrator (broken, category dead), and dashboards (commoditized). v2 deletes two of them. **v2 positioning: workz is not a worktree manager. It is the environment engine that every worktree hook calls.** Claude Code / Cursor / Codex / Conductor / worktrunk / claude-squad stop being competitors and become distribution channels. --- ## 2. Product principles for v2 1. **Hook-first.** Every feature must work when invoked *by another tool* (non-interactive, idempotent, quiet, machine-readable). The human CLI is a nice frontend on the same core. 2. **Zero-config by default, escape hatches for the 10%.** Auto-detection stays the default; per-directory overrides handle the Vite/pnpm cases. 3. **Never lose user data.** Merge, don't overwrite. Managed content lives between explicit markers. 4. **Small.** One binary, minimal deps, fast compile. If a feature needs tokio, it doesn't belong in workz. 5. **Boring reliability over surface area.** `workz doctor` exists so users trust the magic. --- ## 3. The cut list (v0.9.0) Target: **−~2,200 of 4,733 lines, −4 heavy dependencies** (axum, tokio, ratatui, crossterm). | Remove | Lines | Rationale | |---|---|---| | `fleet.rs` + `Fleet` subcommand | 626 | Broken by design (no prompt/TTY); category dead; native agent teams / Cursor / forks do it better — and become workz *callers*. | | `serve.rs` + `Serve` subcommand | 427 | Commoditized by free Conductor + every GUI tool. Drops axum + tokio. | | `tui.rs` 4-panel dashboard | ~1,100 | Dashboards are table stakes (claude-squad, ccmanager, dmux, native agent-view). Fleet/Ports panels die with fleet anyway. Bare `workz` → the `status` table instead. Drops ratatui + crossterm. | | MCP tools that wrap orchestration | — | Retarget MCP to env operations (see §4.6). | **Keep untouched:** `workz switch` (skim fuzzy picker — real daily value), `start`, `list`, `done`, `sync`, `status`, `clean`, shell integration, MCP server core. **Deprecation notes:** - Realistically there are no fleet users to migrate (0 issues, 30 recent downloads). Still: v0.9 keeps `workz fleet` as a stub that prints a pointer to the migration note in the CHANGELOG ("use your agent's native parallel mode + `workz sync --isolated` in its worktree hook"). Remove the stub in v1.0. - `workz init ` is renamed `workz shell-init ` (with a hidden alias for compat), freeing `init` for the v1.0 wizard. --- ## 4. The build list ### 4.1 Hook mode — make `workz sync` perfect as a callee (v0.9) The hero command other tools invoke. Spec: ``` workz sync [PATH] [--isolated] [--json] [--quiet] [--no-install] ``` - `PATH` defaults to cwd; may be a worktree path passed by a host hook. - **Idempotent:** safe to run N times; already-correct symlinks/copies/allocations are no-ops. - `--quiet`: warnings to stderr only, nothing on success. - `--json`: single JSON object on stdout: ```json { "worktree": "/path", "branch": "feat-x", "symlinked": ["node_modules", "target"], "copied": [".env", ".env.local"], "installed": null, "isolation": {"port": 3010, "port_end": 3019, "db_name": "feat_x", "compose_project": "feat_x", "env_file": ".env.local"}, "warnings": [] } ``` - Exit codes: `0` ok (warnings allowed), `1` hard failure, `2` not a git worktree. - Must work when the *main* checkout is bare or busy (agents hold locks) — read-only against the source tree. ### 4.2 `workz hook ` — one-command host integration (v0.10) Prints (default) or installs (`--install`) the exact config for each host. This is the distribution feature. | Host | What it emits | |---|---| | `claude` | `WorktreeCreate` hook entry for `.claude/settings.json` running `workz sync --isolated --quiet "$WORKTREE_PATH"`; note on `.worktreeinclude` overlap (workz handles .env copying; users can keep either). | | `cursor` | `.cursor/worktrees.json` with `"setup-worktree": ["workz", "sync", "--isolated", "--quiet"]` (unix + windows keys). | | `codex` | Per-worktree setup-script snippet for the Codex app's local environments. | | `conductor` | `.conductor/settings.local.toml` setup-script line. | | `worktrunk` | `[hooks] create = "workz sync --isolated --quiet"` for `wt`'s config. | | `wtp` / `gtr` / `claude-squad` | Equivalent post-create hook snippets. | `--install` edits the config file in place (with a backup), `--print` (default) just prints. Each recipe also lands as a copy-paste block in the README. ### 4.3 `workz doctor` (v0.10) Trust-builder. Checks, each ✓/✗ with a one-line fix hint; `--fix` applies the safe ones: - Broken/dangling symlinks in the current worktree (target deleted or moved). - Symlinks pointing into a worktree that no longer exists. - `ports.json`: parse errors; **orphaned allocations** (worktree path gone) → `--fix` releases; overlapping ranges; allocation vs. actually-listening ports (best-effort bind test). - Stale git worktree refs (`git worktree prune` candidates). - `.workz.toml` / global config: parse errors, unknown keys, entries that shadow each other. - `.env.local` managed-block drift (markers present but content stale vs. registry). - Tooling: git ≥ 2.5, `dropdb`/`createdb` present if DB isolation is in use, docker/podman compose if compose isolation is in use. - Exit code 0 = healthy, 1 = problems found (CI-friendly). ### 4.4 Config v2 — additive semantics + per-directory strategies (v0.10) Fixes the two real gaps. Backward compatible: existing keys keep their (replace) meaning. ```toml [sync] # v1 keys still work: symlink/copy/ignore replace defaults wholesale. # v2 additive keys — defaults stay, these adjust them: symlink_add = ["my-large-cache"] copy_add = ["config/local.settings.json"] ignore_add = ["logs"] # v2 per-entry strategy override — the Vite/pnpm-monorepo escape hatch: [sync.overrides] node_modules = "copy" # symlink | copy | ignore ".vscode" = "symlink" ".env.local" = "ignore" # e.g. when the host's .worktreeinclude already handles it ``` Also fix `merge_configs`: project values should override global **per key**, not detect-default by equality comparison (current logic misfires when a user explicitly sets the default value). ### 4.5 Isolation hardening (v0.9–v0.10) - **Fix the clobber bug:** `write_env_local` must merge. Managed values live between markers: ``` # >>> workz managed — do not edit between markers >>> PORT=3010 ... # <<< workz managed <<< ``` User lines outside the block are preserved verbatim; re-runs update only the block. - **Derive `DATABASE_URL`** from an existing `DATABASE_URL` in the copied `.env` (swap the db name), instead of hardcoding `postgres://localhost/`. - **`--create-db` opt-in:** actually run `createdb` (and optionally clone from a template DB: `--create-db --from-db dev`), not just name it. Pair with existing `--cleanup-db`. - **Port sanity:** verify allocated ports are actually free (bind test) at allocation time; warn and re-allocate on collision with non-workz processes. - Replace the hand-rolled RFC3339 code with a tiny crate or keep-but-test (low priority). ### 4.6 MCP server retarget (v0.10) Keep the dependency-free stdio server; reshape tools around the env engine: | Tool | Change | |---|---| | `workz_sync` | Now the hero: full sync + optional isolation, returns the §4.1 JSON. | | `workz_start` / `workz_done` / `workz_list` / `workz_status` | Keep (Codex/Gemini/other MCP clients lack native worktrees). | | `workz_conflicts` | Keep — cross-worktree overlap detection is thin but unique; also expose as a CLI command `workz conflicts`. | | `workz_doctor` | New — agents can self-diagnose a broken environment. | ### 4.7 `workz init` wizard (v1.0) Lightweight, four steps, every answer skippable (Enter-through accepts detected defaults): 1. **Detect & confirm** — stack, package manager, frameworks, docker-compose, monorepo. Show exactly what would be symlinked vs. copied. (Detection code already exists in `sync.rs`.) 2. **Adjust** — toggle strategy per heavy dir (symlink/copy/ignore) — writes `[sync.overrides]`. 3. **Isolation** — enable `--isolated` by default for this repo? base port, range size, DB isolation on/off. 4. **Install the hook** — "Which agent tool(s) do you use?" → runs `workz hook --install`. *This is the step that matters most.* Writes a minimal `.workz.toml` containing only deviations from defaults. Non-interactive mode: `workz init -y` writes detected defaults. --- ## 5. CLI surface after v2 ``` workz # status table (was: TUI dashboard) workz start # create worktree + sync (+ --isolated, --base, --no-sync) workz sync [path] # THE HERO — idempotent env setup (+ --isolated --json --quiet) workz switch [query] # fuzzy picker (skim), unchanged workz list | status # unchanged workz done [branch] # unchanged (+ --cleanup-db) workz clean [--merged] # unchanged workz conflicts # cross-worktree overlap report (promoted from MCP-only) workz doctor [--fix] # NEW workz hook # NEW (--print | --install) workz init # NEW wizard (-y for non-interactive) workz shell-init # renamed from `init ` workz mcp # unchanged transport, retargeted tools ``` Gone: `fleet`, `serve`. Also gone from `start`: `--ai/--ai-tool` stays but is demoted in docs (launching an agent is the host's job now; keep the flag since it's 30 lines and harmless). --- ## 6. Release plan ### v0.9.0 — "The Strip" (~3–5 days of focused work) - [ ] Remove `fleet.rs`, `serve.rs`, `tui.rs` dashboard; stub `fleet` with migration message - [ ] Drop axum, tokio, ratatui, crossterm from Cargo.toml; confirm binary size/compile win - [ ] Bare `workz` → status table - [ ] `workz sync`: `PATH` arg, `--json`, `--quiet`, idempotency pass + tests - [ ] Fix `.env.local` clobber → managed-marker merge + tests - [ ] Rename `init ` → `shell-init` (hidden alias kept) - [ ] One tagline everywhere: Cargo.toml, README, repo description - [ ] CHANGELOG explaining the refocus (link this doc) ### v0.10.0 — "The Hook Release" (~1–2 weeks) - [ ] `workz hook ` print + install for claude / cursor / codex / conductor / worktrunk / wtp / claude-squad - [ ] `workz doctor` (+ `--fix`) - [ ] Config v2: additive keys + `[sync.overrides]` + merge-logic fix - [ ] Isolation: DATABASE_URL derivation, `--create-db`, port bind-check - [ ] `workz conflicts` CLI command; MCP retarget (`workz_sync` JSON, `workz_doctor`) - [ ] README rewrite: hook recipe above the fold, per-host blocks - [ ] Integration tests: hook mode against a real Claude Code `WorktreeCreate` fixture and a worktrunk config ### v1.0 — "The Relaunch" (~1–2 weeks + launch) - [ ] `workz init` wizard (+ `-y`) - [ ] Remove fleet stub - [ ] Docs pass: 5-minute quickstart, per-host guides, doctor reference - [ ] Homebrew/AUR/winget refresh; verify Windows junctions path (or explicitly document Linux/Mac-only) - [ ] Launch (see §7) --- ## 7. Distribution plan (do these, in order) 1. **Answer claude-squad #260 yourself** — "workz does this today," one-line hook recipe. 8 reactions + a volunteer implementer are already waiting there. 2. **PR a recipe into worktrunk's hooks docs** (`create = "workz sync --isolated"`). 5.7k-star audience of exactly the right users; `wt` and `workz` are complementary, not competitors. 3. Same play for ccmanager, dmux/workmux, gtr, wtp docs + the awesome-claude-code / awesome-worktree lists. 4. **Blog post:** "Every worktree tool ships a setup hook. Nobody ships the setup command." — walk through the Claude Code docs line that says "install dependencies yourself." 5. **Show HN (after v1.0):** *"Show HN: workz — Claude Code creates the worktree, workz makes it run."* Lead with the 6-line hook config, not a TUI gif. 6. README top: three tabs (Claude Code / Cursor / worktrunk), each a copy-paste hook block. **Success metrics (6 months):** ≥3 external tools/docs referencing workz as their hook recipe; recent crates.io downloads 30 → 500+; **issues filed > 0** (engagement is the metric — zero issues means zero users); a `.workz.toml` appearing in repos you don't own. --- ## 8. Non-goals for v2 (explicitly rejected) - **VS Code / Cursor extension** — the hook strategy reaches editors through their own worktree features; an extension is a second product for a solo maintainer. - **`workz swarm` (old v0.8 roadmap)** — that's fleet again. Cancelled. - **Web dashboard / GUI** — vibe-kanban's 27k-star corpse marks this lane. - **Team registry / enterprise / SQLite state** — no users to serve yet. - **Containers/VM sandboxing** — container-use, Sculptor, sketch.dev own that lane; workz stays the lightweight non-container option. - **Being an orchestrator in any form.** workz sets tables; it doesn't seat guests. ## 9. Risks & mitigations | Risk | Mitigation | |---|---| | worktrunk adds zero-config detection + isolation | Speed + interop: ship the hook release first, PR the worktrunk recipe so `wt` users adopt workz *inside* worktrunk; managed DB/compose isolation is a deeper moat than port hashing. | | Hosts absorb the env layer natively (like `.worktreeinclude` did to .env copying) | The deeper you go (ports registry, DB clone, compose projects, doctor), the less likely absorption; `.worktreeinclude` absorbed only the shallowest slice. If a host absorbs it all — the category is won by the idea, and workz remains the cross-host version. | | Symlink fragility keeps burning JS users | `[sync.overrides] node_modules = "copy"` + doctor + a README matrix of "known-good strategy per framework." | | Solo-maintainer bandwidth | v2 *reduces* surface (~2.2k lines and 4 deps deleted); every cut feature is one you never have to fix again. | --- *Full research citations (competitor stars/status, native-docs quotes, HN threads) live in the 2026-07-02 research session; key sources: code.claude.com/docs/en/worktrees, cursor.com/docs/configuration/worktrees, developers.openai.com/codex/app/worktrees, worktrunk.dev, vibekanban.com/blog/shutdown, HN 44116872 / 47866750 / 48355104 / 47372855, github.com/smtg-ai/claude-squad/issues/260.*