lumberjack
Skill0 starsChanged 24 days agoMITView on GitHub
Worktree and branch rules delivered by lumberjack at session start. Use as a reference when these rules are absent from context before creating, finishing, cleaning up or recovering worktrees or branches.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 15
Do not edit features there.
- Very specific: line 23
Put work documents only in a doc_roots folder named <ticket_prefix><n>-<slug> or the branch slug.
- Very specific: line 24
When you read or extend a bundle for your ticket, add it to the bundle's Tickets: <ids> line (top file).
- Very specific: line 47
When other branches are built on a landed branch, the sweep prints one line per dependent, dependent <b> of <a>: git rebase --onto …
- Very specific: line 79
Before forcing a removal by hand, snapshot the branch: git update-ref refs/archive/<branch> <branch>.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Worktrees, cleanup and the Stop gate
lumberjack keeps one clone tidy: the primary checkout stays on primary_branch, each task gets
a worktree, and a landed one is removed automatically. Settings live in .lumberjack.toml
(or [tool.lumberjack] in pyproject.toml); the README lists the defaults.
Primary checkout
It stays on primary_branch, clean, and only fast-forwards from origin/<primary_branch>.
Do not edit features there. Create a worktree from fresh origin/<primary_branch>
under one of worktree_roots, one per task, so it inherits nothing uncommitted.
Branch names and documents
One of branch_shapes, where <ticket> is <ticket_prefix><n>; empty means <owner>/<ticket>-<slug>
or <owner>/<slug>, <owner> one of owners (empty: any lowercase owner). Throwaway captures use
<prototype_prefix><ticket_prefix><n>-<slug>. Other shapes fail the Stop gate.
Put work documents only in a doc_roots folder named <ticket_prefix><n>-<slug> or the branch slug.
When you read or extend a bundle for your ticket, add it to the bundle's Tickets: <ids> line (top file).
Cleanup rule
Each session start the sweep fetches origin (5 second limit; on failure it says
origin stale and carries on), then removes a worktree only when all of these hold:
- Its tip is verified landed in
origin/<primary_branch>: an ancestor, identical content, or the exact tip of a merged pull request (checked throughgh). Squash and rebase merges count; a guessed match or an unreachableghleaves it unverified. git status --porcelainis empty. Ignored files do not count; untracked ones do.- The tip is pushed (upstream contains it); waived when a merged pull request had this tip.
evidence_diris empty or absent; nodoc_rootsfolder holds an untracked or ignored file.- The branch is not a
prototype_prefixbranch, which is never touched.
A worktree that fails a check stays, and the sweep names the reason: dirty, unpushed, evidence,
docs, tip diverged (the pull request merged a different tip), current checkout (the sweep runs
inside it), locked (git worktree lock) or fresh (added <24h ago, not moved). The local branch is
always kept. Orphan directories in a worktree root holding only caches (node_modules, .venv,
__pycache__) are deleted; other orphans are listed. A post-merge run in another worktree cleans
nothing; with the primary off primary_branch the sweep still runs and the Stop gate reports it. On dirty, ask the maintainer once per group of
stray files (delete, ignore or commit), never file by file; /lumberjack:cleanup has the steps.
When other branches are built on a landed branch, the sweep prints one line per dependent,
dependent <b> of <a>: git rebase --onto <primary> <a-tip> <b>. Run it before pushing <b>, or its pull request carries the squashed commits.
Keys that change the behavior
cleanup = "prune"(default) removes eligible worktrees and, with a saveddoc_strategy, trashes linked ephemeral bundles and purges trash pasttrash_days."report"printslanded <branch> <path>: would remove,doc <class> <path>: would trashandtrash <stamp>: would purge, and keeps them."keep"keeps them silently. Asked what a sweep would remove, runpython "$(git config lumberjack.script)" --preview(any mode, changes nothing) and summarize it; asked for detail, add--files <bundle path or stamp>...(bare--files: all) to list each file.--tally(same--files) counts what was trashed and purged.stop_gate = falseturns the Stop hook off; it then exits 0 without output.- A config error is printed at session start; cleanup does nothing and the Stop gate blocks.
What the sweep prints
sweep: cleaned N, landed N, dependents N, blocked N, unverified N, orphans N, docs N, with
, origin stale appended when the fetch failed, then one line per event: cleaned,
landed, blocked, dependent, orphan, cleared, purged, doc or hint (relay a hint to the maintainer once; report mode adds a sweep would: totals line after the summary). When nothing was swept the only
line says why: a config error, or sweep: ...; skipped. The exit code is always 0.
Paths are relative to the primary's parent directory, or start with ~.
doc <ephemeral|reference> <path>: tickets <ids>; <size> is a linked doc_roots bundle (tickets, none kept live) the sweep leaves, including while it is inside grace_days.
cleared <path>: trashed <stamp> is a linked ephemeral bundle moved to the trash (docs N counts them); purged <stamp> is trash past trash_days deleted.
unverified counts unproven branches; only the maintainer's /lumberjack:cleanup removes them.
Stop gate
At turn end, the Stop hook blocks with a reason when the current branch breaks naming rules or the
primary is off primary_branch: rename with git branch -m, move work to a worktree, return the primary.
A second stop in a turn passes. Plain --gate exits 2 via stderr; the plugin's --hook exits 0 with JSON.
Recovery
Removing a worktree deletes nothing committed: git worktree add <path> <branch> brings it back.
Uncommitted files are not recoverable, which is why a dirty worktree is never removed.
Before forcing a removal by hand, snapshot the branch: git update-ref refs/archive/<branch> <branch>.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

