An ORCA-like lightweight git worktree + AI agent run manager — spin up multiple AI coding CLIs side-by-side, each in its own isolated git worktree with a persistent re-attachable terminal, and steer them all from a minimal Web UI.
- 中文说明: README.zh-CN.md
- Docs: PRD · Architecture · API
curl -fsSL https://raw.githubusercontent.com/linletian/myworktree/main/scripts/install.sh | bashmacOS and Linux · ~/.local/bin · no sudo · see Install (full reference) for the full options.
- Isolated workspaces, kept apart by git — every worktree is its own git checkout (typically one per branch or working context), so half-finished changes, dependency installs, and experiments never collide. A worktree can run multiple managed instances side-by-side (PTY + opencode-web + reasonix); you decide the granularity.
- Persistent, re-attachable terminals — every agent runs in a managed instance that survives page reloads and browser closes; reopen anytime, scroll back the full output, and keep going.
- Output replay without disk writes — every keystroke lands in a bounded in-memory ring buffer, so you can scrub back through what an agent did while you were away.
- Bring your own agents — OpenCode and Reasonix run out of the box (Reasonix even with its native web chat UI embedded in the sidebar); for everything else, drop a Tag template (
command/env/preStart/cwd) and bring up Claude Code, Codex, GLM, Qwen, or any other CLI. - One place to see what's running — worktrees, instances, output, and PTY state in a single minimal Web UI — no IDE, no editor, no context switch.
- Single Go binary, zero runtime deps — no desktop app, no bundled editor; just
mwand a browser tab. - Headless-friendly by design — drop it on a server, a VM, or a CI box; everything is reachable over Tailscale.
- Portal Dashboard — a single shared entry port auto-discovers running instances across every repo on the host.
- Global auth & CSRF out of the box — HttpOnly Cookie + double-submit CSRF, plus an auto-generated 32-char hex token on first run.
- Hot config reload —
mw config regenrotates the auth token and reapplies settings without restarting the daemon. - File preview & diff in the Changes panel — click any changed or untracked file for a line-numbered, diff-aware preview.
- Reasonix web-chat instances — tick one box to run
reasonix servein a worktree, with its web chat UI embedded in the same sidebar. - Branch divergence badge — see at a glance when a branch is ahead of or behind its upstream, with scheduled refresh.
When you’re juggling multiple coding tasks in the same repo (often with multiple AI coding CLIs working in parallel on different tasks), it’s easy to end up with:
- One working directory polluted by half-finished changes, dependency installs, and temporary scripts
- Too many terminals to track (build/test/search/review), with no single place to see what’s still running
- Long-running CLI processes that die when you close a window, or that you can’t easily reattach to later
A common workflow looks like: GPT/GLM drafts docs, Claude/MiniMax implements changes, and Qwen does review — each tool runs in its own worktree with its own persistent, re-attachable terminal; you switch between them from the Web UI. (myworktree does not orchestrate the agents — it isolates and runs them; you stay in the driver’s seat.)
myworktree is a thin management layer that:
- Uses git worktrees to give you an isolated working directory (typically one per branch or work context, so half-finished changes, dependency installs, and temporary experiments never collide)
- Runs multiple managed instances per worktree (PTY / opencode-web / reasonix can run side-by-side) and keeps them alive on the backend
- Provides a minimal Web UI to list worktrees/instances and replay/follow output
- Supports Tag templates (
command/env/preStart/cwd) to start instances with the right setup, without baking project-specific logic into the manager
- Create/list/import/delete managed worktrees (strict delete: refuses if dirty)
- Start/list/stop managed instances per worktree via Tag templates
- Instance restart support (keeps worktree/tag-or-command and links old/new instance records)
- Web UI can be closed/reopened; instances keep running; WebSocket Web TTY is default (with SSE/HTTP fallback)
- UI shows transport status (
websocket/sse/polling) and provides WS reconnect action - Startup reconcile: stale persisted
runninginstances are auto-markedstoppedafter mw restart - Optional built-in HTTPS (
--tls-cert/--tls-key) and token auth for non-loopback - Stored backlog redaction for common secrets (e.g.
sk-...) - MCP tool endpoints (
/api/mcp/tools,/api/mcp/call) - Portal Dashboard with shared entry port, auto-discovery of running instances across repos
- Global auth token (HttpOnly Cookie, CSRF protection, tailscale serve integration)
- Sidebar main workspace shows a GitHub icon next to the project name when the repo's git remote points at
github.com; clicking opens the canonicalhttps://github.com/<owner>/<repo>URL in a new tab. GitHub Enterprise and non-GitHub remotes are intentionally not surfaced. - Reasonix web chat instances (MVP) — check Reasonix (web chat UI) when starting an instance to run a
reasonix serveagent in that worktree and render its web chat UI in an iframe (/rx/<id>/, same-origin reverse proxy with token cookie injection and URL-prefix rewrite). The serve uses the user's real~/.reasonix(no per-instance isolation): sessions/history/config/credentials are shared per project exactly like a terminal-runreasonix, so the same project's history (including terminal sessions) is visible/switchable in the embedded sidebar. Each Start opens a fresh session (no--resume); deleting an instance never touches the shared session pool. Requires areasonixbinary onPATH; the reasonix UI sidebar (project switching) is intentionally left visible in this MVP. - In-memory PTY log ring buffer — per-instance PTY logs live in a bounded in-memory ring buffer (default 32 MB per instance, hard ceiling 256 MB, total budget capped at 25% of system RAM) instead of on-disk log files, eliminating disk write amplification on long-running PTY-heavy sessions.
LogBufferBytesoverrides the per-instance cap; a start that would exceed the global budget returns503with a structuredlog_buffer_budget_exceededbody. - File preview in the Changes panel — click any changed or untracked file to preview it with line numbers, a formatted view, and a diff view (synthetic diff for untracked files,
quotePathhandled). - Branch divergence badge — the sidebar shows a diverge badge when a branch is ahead of / behind its upstream, backed by scheduled refresh.
mw config regen& hot auth reload — regenerate the config from the CLI; auth token / config changes take effect without restarting the daemon.- Tags config directory — open the tags config directory straight from the UI, with sensible default tags out of the box.
- Daemon resource monitoring — the resource stats API now includes the mw daemon process itself in global totals, shown as a dedicated row in the UI.
- macOS 12+ or Linux (amd64 / arm64; arm64 covers Raspberry Pi 4/5, AWS Graviton, Apple Silicon under Rosetta 2)
gitzshscript(used to host managed interactive shells)- Go toolchain to build (Go modules are statically linked at compile time; zero runtime dependencies)
curl -fsSL https://raw.githubusercontent.com/linletian/myworktree/main/scripts/install.sh | bashInstalls myworktree (and an mw alias) to ~/.local/bin — no sudo required.
PATH is auto-appended to ~/.zshrc / ~/.bashrc (open a new shell to pick it up).
Pin a version, change the install location, or skip PATH modification:
curl -fsSL .../install.sh | bash -s -- -v v0.4.2 # pin a version
INSTALL_ALIAS=mwt bash install.sh # avoid the Debian/Ubuntu `mw` clash
INSTALL_DIR=~/bin bash install.sh # install elsewhere
curl -fsSL .../install.sh | bash -s -- --no-modify-path # do not touch rc filesThe script verifies the SHA256 of the downloaded archive against
checksums.txt from the GitHub release. See
scripts/install.sh for the full implementation.
If you just want to use myworktree, download the latest release assets from GitHub Releases:
- macOS (Apple Silicon):
myworktree_vX.Y.Z_macOS_arm64.tar.gz - macOS (Intel):
myworktree_vX.Y.Z_macOS_amd64.tar.gz - Linux (amd64):
myworktree_vX.Y.Z_Linux_amd64.tar.gz - Linux (arm64, e.g. Raspberry Pi 4/5, AWS Graviton):
myworktree_vX.Y.Z_Linux_arm64.tar.gz - Integrity file:
checksums.txt
Example:
# Pick the archive that matches your platform, then verify and unpack it.
# macOS Apple Silicon:
curl -LO https://github.com/linletian/myworktree/releases/download/v0.4.2/myworktree_v0.4.2_macOS_arm64.tar.gz
# macOS Intel (replace arch in the filename):
# curl -LO .../myworktree_v0.4.2_macOS_amd64.tar.gz
# Linux amd64:
# curl -LO .../myworktree_v0.4.2_Linux_amd64.tar.gz
# Linux arm64:
# curl -LO .../myworktree_v0.4.2_Linux_arm64.tar.gz
curl -LO https://github.com/linletian/myworktree/releases/download/v0.4.2/checksums.txt
shasum -a 256 -c checksums.txt --ignore-missing
tar -xzf myworktree_v0.4.2_macOS_arm64.tar.gz
# Optional: install into PATH
sudo install -m 755 ./mw /usr/local/bin/mw
sudo install -m 755 ./myworktree /usr/local/bin/myworktree
# Verify the downloaded binary
mw --versionmacOS Gatekeeper troubleshooting (Apple Silicon & Intel): macOS may quarantine downloaded binaries and silently prevent execution. If the binary does not respond or shows "cannot be opened":
xattr -d com.apple.quarantine ./mw ./myworktreeOr open System Settings → Privacy & Security and click "Allow Anyway" for the blocked binaries.
Start from v0.4.2 or newer for public release binaries. The earlier v0.1.0 GitHub Release assets were withdrawn after post-release validation uncovered severe terminal interaction issues, and v0.4.2 is the current recommended public release.
Each release archive contains mw, myworktree, README.md, LICENSE, and CHANGELOG.md.
If you need a platform we do not publish, follow the source build steps below.
# Build (in the myworktree source repo)
cd /path/to/myworktree
go build -o myworktree ./cmd/myworktree
# Optional: build alias command `mw` (equivalent to `myworktree`)
# (`mw` auto-opens browser by default; disable with `-open=false`)
go build -o mw ./cmd/mwStrongly recommended: install built binary into your user/system PATH (example for macOS):
# Optional: install into PATH (pick ONE approach)
# A) user-local bin
# mkdir -p ~/bin
# mv /path/to/myworktree/myworktree ~/bin/myworktree
# mv /path/to/myworktree/mw ~/bin/mw
# B) system-wide (usually already in PATH)
# NOTE: install expects a *built binary*, not the Go source directory (so NOT cmd/mw).
# cd /path/to/myworktree && go build -o mw ./cmd/mw && go build -o myworktree ./cmd/myworktree
# sudo install -m 755 ./myworktree /usr/local/bin/myworktree
sudo install -m 755 ./mw /usr/local/bin/mw
# Alternative: go install (installs into GOBIN/GOPATH/bin)
# go install ./cmd/mw
# go install ./cmd/myworktreeCheck the build metadata:
myworktree --version
mw version# Run (inside target git repository)
cd /path/to/target/git/repo
# Run via absolute path if PATH is not configured
# /path/to/myworktree/mw -listen 127.0.0.1:0
# `-listen` is optional; using port `0` means auto-select and persist a repo-bound port.
# For the same repo, future runs will reuse that port when available.
# myworktree prints the full URL with actual port.
# /path/to/myworktree/myworktree -listen 127.0.0.1:0
# /path/to/myworktree/mw -listen 127.0.0.1:0
mw
# Optional: use a fixed port
# /path/to/myworktree/myworktree -listen 127.0.0.1:50053
# /path/to/myworktree/myworktree -open=trueWhen startup succeeds, mw opens the web page automatically at the serving URL by default.
myworktree prints the URL without opening a browser unless you pass -open=true.
When Portal is enabled, the startup output includes:
[portal] Portal dashboard at: http://0.0.0.0:12345/
[portal] Tailscale URL: https://my-machine.tail-scale.ts.net/
myworktree uses the current working directory to detect the target repo (git root) and derives an isolated per-project data dir from it, so you can manage other projects by running the same binary in a different repo directory.
By default, newly created worktrees are placed next to your repo:
<repo-parent>/<repo-name>-myworktree/<worktree-name>/.
Use -worktrees-dir=data to use the legacy location under the per-project data dir, or set -worktrees-dir to a custom path.
# version
myworktree --version
mw version
# worktrees
myworktree worktree new "fix login 401 and add tests"
myworktree worktree list
myworktree worktree delete <worktreeId>
# tags
myworktree tag list
# instances
myworktree instance start --worktree <worktreeId> --tag <tagId>
myworktree instance start --worktree <worktreeId> --cmd "echo hello && ls"
myworktree instance start --worktree <worktreeId> # starts an interactive shell instance
myworktree instance list
myworktree instance stop <instanceId>
# config (global auth token)
mw config # interactive guided setup (set/view/clear/regen token)
mw config set-auth # set token directly
mw config get-auth # view token (masked)
mw config clear-auth # clear token
mw config regen # regenerate token (with confirmation)
# start with remote access & Portal (IPv6 is explicitly disabled)
mw start --listen 0.0.0.0:0 # LAN access, auto-inherits global token
mw start --listen 0.0.0.0:0 --portal-port 12346 # custom Portal port
mw start --listen 0.0.0.0:0 --portal-port 0 # disable PortalNote: command starts are executed inside the instance shell, and you can continue sending input to the same running instance from the UI.
Tags are loaded from:
- Global:
$(os.UserConfigDir())/myworktree/tags.json - Project:
$(os.UserConfigDir())/myworktree/<repoHash>/tags.json
Example:
{
"tags": [
{
"id": "backend-dev",
"command": "npm run dev",
"preStart": "npm install",
"cwd": "apps/backend",
"env": {
"NODE_ENV": "development"
}
}
]
}Run local checks before opening a PR:
test -z "$(gofmt -l .)"
go test ./...
go build -o myworktree ./cmd/myworktree
go build -o mw ./cmd/mwGitHub Actions (.github/workflows/go-ci.yml) runs on:
- pushes to
developandmain - pull requests targeting
developandmain(opened,synchronize,reopened,ready_for_review)
The workflow verifies gofmt, runs go test ./..., and builds both binaries on Ubuntu and macOS.
Tagged releases (v*) run .github/workflows/release.yml, which produces darwin amd64 / arm64 archives plus SHA256 checksums.
Configure a global auth token once, and all instances automatically inherit it:
mw config
# → Interactive guided setup: [1] set token [2] view token [3] clear token [4] regen token [q] quit
# Token stored in ~/.config/myworktree/auth.json (0600 permissions)When --auth is not provided and no token exists in auth.json, the CLI automatically generates a random 32-character hex token and persists it. This ensures instances always have authentication enabled by default. Instance-level --auth override takes precedence over the global token.
mw start --listen 0.0.0.0:0 starts a Portal Dashboard on port 12345 (configurable via --portal-port). The dashboard:
- Lists all running instances across repos with auto-discovery
- Click an instance to jump to its Web UI (directly via instance port — Portal reverse proxy
/s/<repo-hash>/is planned but not yet implemented) - Uses HttpOnly Cookie (
mw_token) for authentication — embedded iframe documents never receive the token in their own URL; the portal's address-bar?token=(portal jump) is accepted by the server and synced into the cookie on the response, so panels authenticate via the cookie alone - CSRF protection via double-submit cookie pattern on login/logout endpoints
- Cookie has 24-hour sliding expiration (refreshed on each auth-successful request)
Set --portal-port 0 to disable the Portal.
Note: Automatic
tailscale serveconfiguration is currently disabled due to a Tailscale 1.98 CLI bug on macOS wheretailscale serve --bgreports success but does not actually configure the proxy. The relevant code exists ininternal/portal/portal.gobut is not wired into the production code paths. Users can still securely access Portal via Tailscale IP (http://100.x.x.x:12345) over the WireGuard tunnel. Automatictailscale servemanagement will be re-enabled once Tailscale fixes the upstream bug.
| Access Path | Protocol | Encryption Layer |
|---|---|---|
| Instance direct (local/LAN IP) | http://192.168.1.18:PORT → instance |
None (LAN only) |
| Instance direct (Tailscale IP) | http://100.x.x.x:PORT → instance |
WireGuard tunnel |
| Dashboard + proxy (local/LAN) | http://host:12345 → proxy http://127.0.0.1:PORT |
None (LAN only) |
| Dashboard + proxy (Tailscale IP) | http://100.x.x.x:12345 → proxy http://127.0.0.1:PORT |
WireGuard tunnel |
tailscale serve domain |
https://machine.ts.net → proxy http://127.0.0.1:PORT |
Let's Encrypt TLS + WireGuard |
Note: Tailscale's WireGuard tunnel provides network-layer encryption. Application-layer HTTPS is only used when accessing via
tailscale servedomain (Let's Encrypt certificate).
Reasonix instances run reasonix serve without a REASONIX_HOME override, so the embedded web UI uses your real ~/.reasonix — exactly like a terminal-run reasonix. The driver strips any REASONIX_HOME / REASONIX_STATE_HOME inherited from the host environment (logging a hint), so the instance and your terminal always share the same per-project session pool; project isolation is done by reasonix itself, per cwd.
Consequence to be aware of: if your shell exports a custom REASONIX_HOME (e.g. ~/.custom-reasonix), a terminal-run reasonix uses that custom home while myworktree instances use the default ~/.reasonix — the two will not see each other's history. This is deliberate. To point an instance at a custom home, set REASONIX_HOME via the instance tag's env (applied after stripping).
Instance lifecycle never touches the shared session pool: Start / Stop / Restart / Delete only manage the serve subprocess and its management files (token/port/pid/serve.log in the instance state dir). Sessions live in ~/.reasonix/projects/<cwd-slug>/sessions, so restarting an instance opens a fresh session (no --resume) while your history stays available in the sidebar.
MIT. See LICENSE.

