Before every distill spawn — whether triggered by the interval timer, a manualDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/cad0p/pi-napkin/llms.txt
Use this file to discover all available pages before exploring further.
/distill, or session shutdown — pi-napkin runs a layered health check to confirm the vault is in a state that worktree-based distill can actually run against. The check is split into two cadences so the cost of routine session-start probes stays near-zero while the rare, slower git-state probes only fire when a worktree is about to be spawned.
Two cadences
| Cadence | When | What it covers | Typical cost |
|---|---|---|---|
| Fast-level | Every session_start (every pi launch in the vault) | Subdir vs legacy embedded layout, managed .gitignore block matches canonical content (auto-recover if drift), auto-init git init + initial commit if .git/ is missing | Sub-second (a handful of file probes) |
| Full-level | Before every worktree-based spawn: manual /distill, each interval-timer fire, and session shutdown | Everything fast-level covers, plus: .napkin/config.json is git-tracked, HEAD resolves to a commit, .napkin/config.json not gitignored outside the managed block, .napkin/distill/ not tracked in git, cache root writable, no orphaned worktree registry entries, no stale distill/* branches past the grace period | A few extra git probes; runs only when a worktree spawn is imminent |
Auto-recover findings
These are drift states the health check repairs in place. Each produces a singleinfo-level notification and distill proceeds normally afterward.
-
Managed-block drift — the markers in
.gitignorewere reordered, content inside the block drifted from canonical, or canonical lines leaked outside the block into user territory. Resolution: the bracketed region is rewritten to canonical content and any leaked lines outside the markers are removed. -
Untracked
.napkin/config.json(full-level only) — the config file exists on disk but is not yet in git’s index. Worktrees are checked out viagit worktree add HEAD, which only copies tracked files; an untrackedconfig.jsonwould never reach the worktree and distill would silently break. Resolution: the file is staged (git add) and committed so every subsequent worktree checkout includes it. -
Vault HEAD resolves to a commit (full-level only) — the vault has a
.git/directory (from a handgit init) but has never had a commit, sogit rev-parse --verify HEADfails. Without a commit to pin to,git worktree add HEADfails withfatal: invalid reference: HEAD. Resolution: an empty initial commit is seeded (git commit --allow-empty) so HEAD is valid before the worktree spawn. -
Orphaned distill worktrees (full-level only) — a previous distill crashed and left a
git worktree listregistry entry pointing at a directory that no longer exists on disk. Stale entries accumulate if pi instances crash before cleanup. Resolution:git worktree prune --expire=nowremoves all registry entries pointing at missing directories. -
Stale
distill/*branches (full-level only) — adistill/*branch whose committerdate is older than 24 hours AND has no live worktree pointing at it. These are branches from distills that completed (or failed) but whose cleanup step didn’t delete the branch ref. Resolution:git branch -D <branch>. The reflog grace period gives you a recovery window — the branch tip remains reachable viagit reflogfor approximately two weeks.
Loud-error findings
These are conditions where auto-distill cannot safely proceed. Each produces anerror-level notification and the distill spawn is aborted before any git work starts.
-
Subdir-layout violation — the vault uses napkin’s legacy embedded layout (
config.jsonat<vault>/config.jsonwith no.napkin/subdir, whereconfigPath === contentPath). Worktree-based concurrency requires the subdir layout because the worktree branch must track a.napkin/config.jsonthat napkin’sfindVaultcan resolve. Fix: follow the migration steps in the README to move the config into a.napkin/subdir. Manual/distillcontinues to work on the legacy layout; only auto-distill requires migration. -
.napkin/config.jsongitignored outside managed block (full-level only) — a rule in user territory (outside theBEGIN/ENDmarkers, or in a parent-directory.gitignore, or in a global git ignore file) excludesconfig.json. Worktrees checked out from git would have no config to read, and future distills would silently break. Fix: find the rule withgit check-ignore -v .napkin/config.jsonand remove it. Rules inside the managed block are reset automatically by the gitignore-block invariant and never trigger this error. -
.napkin/distill/tracked in git (full-level only) — the per-worktree session fork directory has been committed into the git index. This typically happens when someone rangit add -f .napkin/distill/explicitly, or from a stale commit made before the managed.gitignoreblock was installed. Fix: untrack the directory withgit rm --cached -r .napkin/distill/and commit the result. pi-napkin does not auto-untrack becausegit rm --cached -rcan discard staged changes without warning. -
Cache root unwritable (full-level only) —
$XDG_CACHE_HOME/napkin-distill/<vault-hash>/(typically~/.cache/napkin-distill/…) cannot be created or written to. Worktrees are placed under this directory, so a non-writable cache root prevents any worktree spawn. Fix: check disk space and filesystem permissions on your home directory or~/.cache, or pointXDG_CACHE_HOMEat a writable path and restart pi.
Opting out
Setdistill.enabled = false in .napkin/config.json:
.gitignore block, and never probes git state at session start. Manual /distill still works — it has no concurrency-safety prerequisites and requires neither git nor the subdir vault layout.