stubbedev / treeman
Per-worktree development databases, snapshots and test clones, distributed as verified native binaries
Requires
- php: >=8.1
- composer-runtime-api: ^2.2
- ext-curl: *
- ext-pcntl: *
- ext-zlib: *
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-21 12:18:40 UTC
README
Per-worktree development environment helper. Spin up isolated databases, search indices, and parallel test clones for each git worktree — torn down on delete, kept in sync as your migrations and fixtures change. Language- and framework-agnostic.
Pure wire-protocol DB access (Go database/sql for MySQL +
PostgreSQL, the official Mongo / Redis / Elasticsearch SDKs) — no
shelling out to mysql / psql / mongosh / redis-cli. A single
user-mode daemon, a thin CLI client, and a SQLite-backed event log.
Why treeman
A git worktree gives every branch its own checkout — but a working
tree also needs its own database, N test-runner clones fanning out
from a cached template, migrations applied, .env-style config patched
to the per-worktree DB names, install hooks run, and teardown that drops
every namespace on delete. treeman owns that lifecycle:
treeman worktree create FOO and treeman worktree delete FOO are the only
commands you type.
Supported engines
| Engine | Variants | Per-worktree isolation |
|---|---|---|
| MySQL | MariaDB, TiDB | Separate database |
| PostgreSQL | — | Separate database |
| MongoDB | — | Separate database |
| Redis | Valkey, DragonflyDB | Key-prefix in DB 0 (cluster-safe, no 16-DB cap) |
| Elasticsearch | OpenSearch | Index-name prefix |
Variants are first-class aliases — declare engine: mariadb, tidb,
valkey, dragonfly, or opensearch and treeman routes it to the
parent engine's driver (Valkey/DragonflyDB ride the Redis wire
protocol).
Features
- Snapshot cache — repeated
wt createon the same migrations + dump hits a cached template DB; LRU eviction with a per-repo cap (default 8), per-source retention, age + size sweeps bound disk use;treeman doctorflags (and--fixreclaims) orphaned templates left behind by crashes. - Spare-clone pre-warming —
databases[].prewarm: N(Postgres) keeps N clones pre-restored from the cached template; a cache-hitwt createclaims one viaALTER DATABASE … RENAMEin milliseconds regardless of database size, and the pool refills in the background. - Hook lifecycle — declarative create / delete / checkout /
file-change trigger lists; actions in a list run in parallel, the
run:steps within an action chain sequentially. - Parallel test runner support —
clones: autodetects the test framework (paratest, pytest-xdist, jest / vitest, cargo-nextest, …) and pre-warms one clone per CPU when that runner parallelizes per-worker, else one. - File watcher — fsnotify re-fingerprints affected databases on
input edits and picks
auto | delta | rebuild. - MCP server —
treeman mcpexposes config authoring/validation, event-log + hook-output queries, live engine state, and snapshot inspection to Claude Code / Desktop / Cursor. Runs over stdio (per-client) or, with--http, as one shared daemon every client connects to, each request scoped to its own worktree. - Desktop notifications — opt-in
notifications:block firesnotify-send(Linux) / native banners (macOS) when a worktree turns ready, fails, or starts/finishes preparing; configurable per status bucket, hot-reloaded without a restart. - Single static binary per platform — no CGo, no system libraries;
CI cross-builds
{linux,darwin}×{amd64,arm64}.
See docs/ for the deep dives — CLI reference, configuration schema, AI integration, internals.
Requirements
- git —
git worktreeis the substrate treeman manages. - One of:
systemd --user(Linux) orlaunchd(macOS) for auto-start. Without one,treeman daemon startstill works; the daemon just won't survive a reboot. - Your database server(s) — treeman manages namespaces on
existing MySQL / Postgres / Mongo / Redis / Elasticsearch
instances; it does not run them. Local server, remote server,
or container-hosted server (auto-discovered via
docker inspect/compose ps) all work. - Go 1.25+ — only if building from source.
Native releases need no Python, Node, or language-specific tooling.
The optional Composer bootstrap requires Composer 2.2+, PHP CLI 8.1+,
and the curl, pcntl (with pcntl_exec enabled), and zlib extensions.
Install
Via Homebrew (macOS + Linux):
brew tap stubbedev/tap brew install stubbedev/tap/treeman
Composer (PHP dev dependency)
Published on Packagist as stubbedev/treeman:
composer require --dev stubbedev/treeman vendor/bin/treeman --version vendor/bin/treemand --version
Commit composer.json and composer.lock in your application. Composer's
installed package metadata (populated from the lock on composer install)
selects the exact release, never latest. Each new patch tag works
without updating a version constant in this package. Development branches
and branch aliases are rejected; use a published tag with release assets.
This is a normal library with transparent Composer bin bootstraps, not
a plugin: no plugin approval or dependency install scripts are needed.
composer install does not download the native binaries. The first
invocation of either bin announces a lazy download of both binaries from
that tag's GitHub release, verifies its published SHA256, and extracts only
allowlisted regular files. Subsequent invocations verify the cached binary
hashes and execute directly, preserving arguments, working directory, signals,
and exit status. The verified exact-version cache entry is prepended to PATH
so daemon startup finds its matching treemand; the original PATH follows
unchanged, and other environment variables are preserved. Linux/macOS amd64 and arm64 are supported;
Windows and 32-bit platforms are not.
First use needs HTTPS access to GitHub release assets (including GitHub's
asset redirect host), plus a writable executable cache directory. The default
is $XDG_CACHE_HOME/treeman/composer, or $HOME/.cache/treeman/composer.
Set TREEMAN_COMPOSER_CACHE to an absolute path to override it. Entries are
keyed by exact version and platform, serialized with a file lock, and published
atomically. The cache root, entry directory, metadata, and binaries must not be
group/world writable; symlinks at those locations are rejected. Keep the cache
owned by the executing user, and trust every ancestor directory (including any
ancestor symlink targets): other users must not be able to replace or redirect
the cache through its ancestry. Ancestor permissions and ownership are not
validated by the bootstrap. Restored caches must come from a trusted source;
hashes detect corruption, not an attacker who can rewrite both binaries and
cache metadata.
Published checksums protect against corrupt downloads, not a compromised
GitHub release publisher; they are not independently signed attestations.
For offline/air-gapped jobs, warm the cache online with
vendor/bin/treeman --version, then preserve the complete version/platform
entry with executable permissions (or the entire cache). Set
TREEMAN_COMPOSER_OFFLINE=1 to forbid bootstrap downloads. Valid cached entries
also work offline without this setting, including from a read-only cache.
A missing/corrupt entry fails clearly; no other version is substituted. Remove
an invalid entry and warm it online again. Composer's own package cache/vendor
files must also be available for an offline composer install; the native
binary cache does not replace them. No binaries are vendored in this package.
Native releases
Prebuilt tarballs for every tagged release. The asset filename embeds the version, so resolve the latest tag first:
# linux/amd64 example — substitute the platform (darwin-amd64, # darwin-arm64, linux-arm64) you need. VER=$(curl -fsSL https://api.github.com/repos/stubbedev/treeman/releases/latest | grep '"tag_name":' | cut -d'"' -f4 | sed 's/^v//') curl -L -o /tmp/treeman.tgz \ "https://github.com/stubbedev/treeman/releases/download/v${VER}/treeman-${VER}-linux-amd64.tar.gz" tar -xzf /tmp/treeman.tgz -C /tmp install /tmp/treeman-*-linux-amd64/treeman ~/.local/bin/ install /tmp/treeman-*-linux-amd64/treemand ~/.local/bin/
From source (Go 1.25+):
git clone https://github.com/stubbedev/treeman cd treeman just install # → $GOBIN/treeman + $GOBIN/treemand
Via Nix (flake):
nix profile install github:stubbedev/treeman
Shell completion (optional but recommended):
source <(treeman completion bash) # or zsh / fish / pwsh
Quick start
# 1. Bootstrap a config in your repo. treeman init detects the # package manager + framework markers and emits a tailored # .treeman.yaml. cd ~/code/my-app treeman init # 2. Install + start the user-mode daemon (one-time). treeman daemon install # systemd --user on Linux, launchd on macOS treeman daemon start # idempotent — uses systemctl/launchctl when installed # Sanity check whenever something feels off: treeman doctor # probes daemon, config, schema, git ↔ registry drift treeman repos # every enrolled repo: worktrees, snapshots, last activity # 3. Spin up a worktree end-to-end. treeman worktree create proj-123 # ↳ git worktree add .worktrees/proj-123 -b proj-123 origin/HEAD # ↳ brings in worktrees.copies (e.g. .env) + worktrees.links (e.g. node_modules) # ↳ patches `patches:` entries (.env.testing, settings.py, # phpunit.xml, etc.) to point at per-worktree DB names # ↳ runs create hooks (parallel groups, detached) # ↳ prepare: ensure_db → load dump → migrate → snapshot → N test clones # 4. Get the path of an existing worktree for `cd` integration: cd "$(treeman worktree go proj-123)" # (CI flow: block on the daemon's finalize before running tests.) treeman worktree wait proj-123 # exits 0 on success, non-zero on failure treeman worktree show proj-123 # dossier + recent events + hook runs # 5. Done with the branch: treeman worktree delete proj-123 # ↳ runs predelete hook (DB drops, FLUSHDB, ES index delete) # ↳ git worktree remove # 6. Cd back to the main checkout (with optional auto-remove if clean): cd "$(treeman worktree back --remove)"
CI without a daemon
Use prepare --no-daemon in an existing checkout to force preparation in
process and block until complete, without a user session or daemon. Bare
prepare may use daemon RPC; --foreground starts a daemon rather than
forcing inline preparation. Do not use daemon-backed worktree lifecycle
commands as a substitute. A writable per-build directory isolates SQLite
(including WAL/SHM sidecars) and scratch files; do not point concurrent builds
at one TREEMAN_DB_PATH.
composer install --no-interaction export TREEMAN_COMPOSER_CACHE="$HOME/.cache/treeman/composer" vendor/bin/treeman --version export TREEMAN_COMPOSER_OFFLINE=1 TREEMAN_BUILD_STATE=$(mktemp -d "$PWD/.treeman-ci.XXXXXXXX") export TREEMAN_DB_PATH="$TREEMAN_BUILD_STATE/treeman.db" export TMPDIR="$TREEMAN_BUILD_STATE/tmp" mkdir -p "$TMPDIR" cat > "$TREEMAN_BUILD_STATE/config.yaml" <<'YAML' snapshots: cap_per_repo: 8 YAML export TREEMAN_CONFIG="$TREEMAN_BUILD_STATE/config.yaml" vendor/bin/treeman prepare --no-daemon --repo "$PWD" --worktree "$PWD" vendor/bin/phpunit
TREEMAN_CONFIG (or --config /absolute/path/config.yaml, which wins over
the environment variable) replaces the default global config layer.
Repository .treeman.yaml still loads afterward and takes precedence for
repo-scoped settings. Global-only settings such as snapshots, daemon,
and logs belong in that replacement global file, not the repo file.
This selects configuration for foreground/local execution; it does not
reconfigure an already-running daemon handling RPC commands.
Snapshot registry state lives in TREEMAN_DB_PATH; actual template snapshots
live in your database engines, not a configurable snapshots.path directory.
Keep SQLite's parent and TMPDIR writable, and provision writable engine
storage with sufficient space/permissions for snapshots and clones. Isolating
SQLite alone does not isolate shared database namespaces: concurrent builds
also need distinct configured database/template names or isolated engine
instances. Clean up engine resources and the per-build state directory after
the job. Daemon periodic snapshot/log retention sweeps do not run in this mode.
Git workflow
treeman git bundles the daily git verbs with a built-in interactive
picker (no fzf needed), worktree-aware branch routing, and shell
completions. Everything renders to stderr, so the cd "$(…)" shims
stay clean.
treeman git commit # message prompt, auto ticket prefix from the branch treeman git commit fix login # same, prompt pre-filled (or commits directly when scripted) treeman git push # guards protected branches + upstream divergence treeman git add # multi-select stage: M → add -p, D/A → add treeman git switch # picker: live worktrees first (* dirty, ! unpushed), then branches treeman git switch KON-1234 # checkout-or-create, worktree-aware; prints dest path for cd treeman git log # interactive log: show / cherry-pick / revert / copy hash treeman git diff --pick # three-dot diff vs a picked branch (--patch writes a .diff file) treeman git stash pop # pick a stash treeman git amend|undo|discard|branch-delete|sync-branch|fixup
Picker keys: type to filter, Enter accepts, Tab marks (multi), Ctrl+C
cancels the step (opens the branch wizard in switch), Esc always
quits the whole command with no action. List height:
TREEMAN_PICKER_HEIGHT (default 10); colors respect NO_COLOR.
Worktree navigation pairs with a 2-line shell shim, since a child
process can't cd its parent shell:
gwt() { local p; p=$(treeman worktree switch "$@") && [ -n "$p" ] && cd "$p"; } gcb() { local p; p=$(treeman git switch "$@") && [ -n "$p" ] && cd "$p"; }
A ready-to-source zsh shim that wraps worktree go / worktree back
for cd-into-worktree UX lives at contrib/tm.zsh (exposes a tm
shell function):
# In ~/.zshrc: source /path/to/treeman/contrib/tm.zsh # Then: tm proj-123 # cd into existing worktree (or report missing) tm proj-123 -c # create + cd to new worktree tm new proj-123 # same as `tm proj-123 -c` tm - # cd back to main repo tm - --remove # cd back + drop current worktree if clean tm list # passthrough to `treeman worktree list`
Documentation
| Page | What you'll find |
|---|---|
| docs/cli.md | Full command reference, log filters, completion, output/color/paging, env vars |
| docs/configuration.md | .treeman.yaml guide — every block, per-stack examples, templated names, hooks, credential resolution, container DBs |
| docs/config-reference.md | Generated field-by-field .treeman.yaml reference (from the Go types) |
| docs/advanced.md | Snapshot cache + GC, framework presets |
| docs/mcp.md | MCP / AI integration — Claude Code, Claude Desktop, Cursor, security model |
| docs/mcp-tools.md | Generated MCP tool + prompt reference (from the registry) |
| docs/events.md | Generated event-type reference (from the store.Evt* constants) |
| docs/frameworks.md | Generated migration-framework preset table (from the detector registry) |
| docs/rpc-reference.md | Generated RPC method / task / kind reference (from internal/rpc) |
| docs/internals.md | Storage layout, daemon model, init parity, RPC envelope, development |
License
Dual-licensed under Apache-2.0 OR MIT.