liminaltrees(1) General Commands Manual liminaltrees(1)

Name

liminaltrees, lt — every git worktree on your machine, at once

Synopsis

liminaltrees
lt scan [--json] [--root dir]
lt gc [--dry-run] [--yes] [--root dir]
lt ui [--root dir]

Install

$ curl -fsSL https://lt.different.productions/install.sh | sh

macOS 15 or later. Universal binary, ~1 MB, no runtime dependencies. The script checks its own SHA-256 before unpacking, and you can read it first — it is served as plain text.

Description

git worktree list shows you one repository at a time, and tells you nothing about what any of the worktrees are for. So they accumulate — the ones you made, the ones your agents made and named after a hash, and the ones whose contents your OS quietly deleted without telling git.

liminaltrees finds all of them, works out what each one is, and removes the ones whose work has already landed. Anything holding work that exists nowhere else gets pushed somewhere safe first, and is only removed once that push is confirmed.

It sees through a squash merge, which git branch --merged cannot: the squashed commit has different parents and a different hash, so the original branch reads as unmerged forever. That is why worktrees for work you shipped weeks ago are still sitting there.

Commands

liminaltrees
Opens the dashboard. Piped, prints a table instead, so | grep still works.
lt gc
Shows you exactly what it would do, grouped by what it intends. Runs only if you type y.
lt gc --dry-run
Shows the plan and stops. Never prompts.
lt scan --json
For the agents that made this mess in the first place. Stable tokens, not prose.

How it decides

Checks run in order. The first one that matches decides, so the order is the whole safety policy.

  1. Detached, on a commit no upstream branch hasheld — nothing to rescue onto, and its registration holds the only ref
  2. Registered, but the directory is goneremove — bookkeeping only; the branch ref outlives it
  3. Anything wrote to it in the last hourheld — something is working in there
  4. Uncommitted filesrescue — those bytes exist in one place on earth
  5. Commits on no remote, and no patch upstreamrescue — still unique
  6. Its pull request merged or closedremove — this is the one that catches squash merges
  7. Every commit's patch is already on the default branchremove — it landed some other way
  8. Clean, pushed, unmergedyour call — safe to delete, but still somebody's plan

It will never

touch a worktree something is writing to
Anything written in the last hour is off limits, and that check outranks the rescue rules — pushing a half-finished state out from under a live agent run is worse than leaving the disk alone.
delete work that exists nowhere else
Uncommitted, unpushed, or reachable from no remote: it gets committed, pushed to a fresh wip/ branch, and confirmed on the remote. Only then is the worktree removed. A rescue that fails cancels that removal and nothing else.
guess
If it cannot reach the forge and cannot prove a branch landed, it says so and leaves the worktree alone. Not knowing is a result, not a reason to delete.
act without showing you first
Every removal is listed, with the single fact that decided it, before anything runs.

Files

~/Developer/.worktrees/project/branch The ones you made on purpose.
repo/.claude/worktrees/agent-* Made by a harness run, named after a hash, never cleaned up.
/private/tmp/claude-uid/session/scratchpad/ The OS reclaims the contents. Git keeps the registration forever.
~/.local/bin/liminaltrees Where the installer puts it. lt is symlinked next to it.

Guarantee

A worktree is removed only when every commit in it is reachable from origin and the working tree is clean. After any run, git fsck reaches everything it reached before.

That is the point of the whole design: a plan you can approve without reading it closely. A cleanup tool you have to read closely every time is a cleanup tool you stop running.

Bugs

Rescue has no automated test coverage — exercising it means creating remote branches. Every classification rule is tested; the push-and-verify sequence has been read and run by hand, not by CI.

macOS only. It shells out to stat -f, which is the BSD spelling.

See also

git-worktree(1), git-cherry(1), and the twenty-three checkouts you forgot about

Different Productions Version 0.1.0 liminaltrees(1)