@tanisjam/peel
v0.1.1
Published
Ephemeral git worktrees with auto-managed dev servers. Spin up any branch with its own node_modules, env, and free port — and tear it all down on Ctrl+C.
Maintainers
Readme
peel
Ephemeral git worktrees with auto-managed dev servers.
peel lets you spin up any branch in an isolated git worktree with its own
node_modules, a copied .env, and a free port — and tear it all down on Ctrl+C.
Published as @tanisjam/peel (the bare peel name is squatted on npm). The
binary on your terminal is still peel.
peel init # one-time setup per repo
peel # interactive: pick branch, pick mode, go
peel run feature/x dev # direct, no prompts
peel list # show active worktrees
peel clean --stale # cleanup orphansInstall
# Recommended: install globally so the `peel` command is on your PATH
npm install -g @tanisjam/peel
# Or run on demand without installing (uses npx)
npx @tanisjam/peel <command>After npm install -g @tanisjam/peel, peel run feature/x dev works directly. If you only used npx ... init, the bare peel command will not be on your PATH — keep using npx @tanisjam/peel run ... or install globally to drop the prefix.
Usage
peel init # interactive wizard, generates .peel.yml
peel init --yes # non-interactive, uses detected defaults
# or, without a global install:
npx @tanisjam/peel initThe wizard auto-detects:
- Package manager — picks the lockfile present (
pnpm-lock.yaml>bun.lock>yarn.lock>package-lock.json); honors Corepack'spackageManagerfield if set. - Env files — every
.env*in the repo root (excluding*.exampleand*.sample). - Scripts —
dev,build, andstartfrom yourpackage.json.
The output .peel.yml is minimal: only fields that differ from the canonical defaults are written. Two runs over the same answers produce byte-identical files.
Run a branch
peel run feature/x dev # spin up feature/x in a worktree, run dev
peel run feature/x build # build mode
peel run # interactive: type-to-filter branch picker, then pick mode
peel run feature/x dev -k # --keep: don't remove the worktree on exit
peel run --port 4200 # override the base port
peel run --no-fetch # skip the initial git fetchWhat happens on peel run:
- Loads
.peel.yml. Bails if missing. git fetch --prune(best-effort; survives offline).- Lists branches; prompts if no branch given.
- Verifies the port.
fixedstrategy fails fast with a friendly error pointing at the holding PID.auto-findwalks the next 20 ports. - Creates a
git worktreeat<baseDir>/<repoName>-<slug(branch)>. - Copies the configured env files (skips files that already exist at the destination).
- Runs the install command (skipped on
--keepreuse ifnode_modulesexists). - Runs configured pre-run hooks sequentially. Stops on first failure with a friendly error.
- Spawns the dev/build command with stdio inherited.
- On exit (clean or Ctrl+C), removes the worktree unless
--keepis set.
Manage worktrees
peel list # show all peel-managed worktrees
peel clean feature/x # remove a single worktree
peel clean --all # remove all peel-managed worktrees (with confirmation)
peel clean --all --yes # same, no prompt
peel clean --stale # remove worktrees whose branch no longer exists locally or remotelypeel list shows branch, path, age, and status. Status is running when a peel.lock
file in the worktree points at a live PID, idle otherwise.
peel clean defaults to safe behavior: bulk modes (--all, --stale) skip running
worktrees and report them in the summary. Single-target peel clean <branch> warns
but proceeds — explicit user intent.
The --stale mode runs a best-effort git fetch first (unless --no-fetch is passed
or git.fetchOnStart: false in .peel.yml); on fetch failure it computes staleness
from the local view and prints a warning.
Configure
peel config show # print the merged config (defaults + overrides) as YAML
peel config path # print the absolute path of .peel.yml
peel config edit # open .peel.yml in $VISUAL or $EDITORpeel config show prints the merged view — every field with its effective value — so
you see exactly what peel run will use. To inspect the raw file, use
cat $(peel config path).
peel config path always prints a path (the file's location, or where it would be
created). Exit code 0 when the file exists, 1 when it does not — useful for
scripting:
if peel config path > /dev/null 2>&1; then
echo "configured"
fipeel config edit resolves the editor as $VISUAL, then $EDITOR. It refuses to
spawn when .peel.yml is missing (run peel init first) or when no editor is
configured.
Development
Prerequisites: Node ≥ 20, npm.
npm install # install deps
npm run dev # tsup watch mode
npm run build # produces dist/index.js
npm test # vitest: unit + integration
npm run test:unit # unit only
npm run test:integration # integration only (slower; spawns the built binary)
npm run lint # biome check
npm run lint:fix # biome check --write
npm run typecheck # tsc --noEmitReleases
Releases use Changesets:
npx changeset # add a changeset describing your change
# ...PR + merge to main, then:
npm run release # changeset publish (CI or maintainer)License
MIT
