Skip to main content

Documentation 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.

pi-napkin registers three slash commands into your pi session. These commands give you direct control over knowledge distillation: triggering a run on demand, pausing or resuming the automatic timer for a session, and inspecting in-flight background processes. All three commands are available in any pi session where pi-napkin is installed — no additional configuration is required to use them.

/distill

Trigger a manual distill of the current conversation into the vault right now.
/distill
This command takes no arguments. It forks the current session, spawns a detached pi -p subprocess, and asks a model to extract structured notes from the conversation. Progress is shown in the status bar while the distill runs.

Routing

The /distill command automatically chooses a spawn path based on your vault’s setup:
ConditionPath used
Git present + distill.enabled: true + subdir vault layoutWorktree path — concurrency-safe, conflict-resolving
Git absent or distill.enabled: false or legacy-embedded layoutLegacy tmpdir path — simple fork, no git side effects
Manual /distill does not require distill.enabled: true or a git repo. The legacy path handles git-less and disabled-but-valid vaults transparently. Only the worktree path (used when all three conditions above are met) requires git and the subdir layout.

Behavior

  • Resets size deduplication — sets lastSessionSize = 0 to force a re-distill even if the session file hasn’t changed since the last run. This is the key difference from the automatic timer, which skips runs when nothing new has been written.
  • Guard against concurrent runs — if a distill is already in flight (isRunning is true), the command shows a warning and returns immediately:
    Distill already running
    
  • Status bar — while running, the status bar shows a live elapsed-seconds counter (● distill Xs). On the worktree path, the underlying wrapper drives the full distill→merge→squash→push lifecycle; on the legacy path, a bare pi -p fork runs against a temp dir.
  • Completion notification — when the distill finishes, pi surfaces a notification whose severity matches the outcome class:
    Outcome classNotification
    merged-content✓ info — “Distillation complete (Ns)“
    merged-local⚠ warning — “Distillation complete locally; not pushed to origin”
    no-content⚠ warning — “Distillation ran but saved no content”
    failed:<reason>✗ error — “Distillation failed: <reason>” with recovery hint

Implementation detail

The /distill command handler (from extensions/distill/index.ts):
  1. If isRunning is true: calls ctx.ui.notify("Distill already running", "warning") and returns.
  2. Sets lastSessionSize = 0 to bypass the size-dedup check.
  3. Calls runDistill(ctx) to route and spawn.

Full-level health check

When /distill routes to the worktree path, it first runs a full-level health check on the vault. Auto-recoverable findings (managed .gitignore block drift, untracked config.json, orphaned worktrees, stale distill/* branches) are fixed in place and surfaced as info notifications. Error-level findings (legacy embedded layout, malformed config.json, gitignored config, tracked distill dir, unwritable cache root) abort the spawn before it starts.

/distill-auto-this-session

Pause or resume the automatic distill timer for the current session without changing vault-level config.
/distill-auto-this-session [on|off|status]

Arguments

argument
string
Optional. One of on, off, or status. If omitted, the current state is toggled.
The command supports tab completion. getArgumentCompletions returns ["on", "off", "status"] filtered by any prefix already typed, so pressing Tab after /distill-auto-this-session will offer all three values.

Behavior

  • Persisted across restarts — state changes are written to the session file as a CustomEntry with customType: "napkin-distill-session-state" (the SESSION_STATE_CUSTOM_TYPE constant) via appendCustomEntry. Unlike appendCustomMessageEntry, CustomEntry records do not participate in LLM context, so they never affect the agent or prompt caching.
  • Resume notification — when resuming a session where auto-distill was previously paused (via resume, fork, or startup event reasons), pi surfaces a one-time info notification:
    Auto-distill is off for this session. Run /distill-auto-this-session on to turn on.
    
  • Re-enable resets the timer — running /distill-auto-this-session on after a pause resets lastDistillTimestamp to now. This prevents an immediate fire if the interval had already elapsed while distill was suppressed.
  • Does not affect manual /distill — suppression only stops the interval timer. You can still call /distill explicitly at any time.
  • Vault-disabled warning — if distill.enabled: false in vault config, toggling the session flag has no practical effect. The command shows a warning:
    distill is disabled in vault config — set distill.enabled=true in .napkin/config.json

Examples

# Pause auto-distill for this session
/distill-auto-this-session off

# Resume auto-distill (resets the timer interval from now)
/distill-auto-this-session on

# Check current state and time until next run
/distill-auto-this-session status

# Toggle current state (no argument)
/distill-auto-this-session

/distill-status

Show active background distill processes and unmerged distill branches for the current vault.
/distill-status
This command takes no arguments. It reads the vault’s git worktree registry and meta.json sidecars to produce a live snapshot of every in-flight distill subprocess.

Output format

The output from formatDistillStatus() follows this structure:
Active distills (N):
  [PID] Xs  branch=distill/abc-123  session=<basename>
  ...
Unmerged branches (M):
  distill/xyz-456  (no active process)
When there are no active distills and no unmerged branches:
No active distills.
When there are no active distills but there are unmerged branches, the "No active distills." line is still followed by the Unmerged branches (M): block.

Output fields

[PID]
number
The wrapper process PID for this distill. Shown as -1 when meta.json is unreadable (e.g. the worktree was cleaned up mid-read).
Xs
string
Elapsed wall-clock seconds since the distill started, derived from the startedAt timestamp in meta.json.
branch=
string
The git branch name for this distill, in the form distill/<id>.
session=
string
The basename of the parent session .jsonl file that was forked to produce this distill. Shows unknown if the path is unavailable.
(dead)
string
Appended to the entry when process.kill(pid, 0) confirms the PID is no longer alive. The worktree may still exist as a cleanup remnant.
Unmerged branches are distill/* branches that exist in the vault’s git repo but have no live worktree pointing at them. These are candidates for manual cleanup — they were either produced by a crashed distill or by a distill that completed but whose branch was not deleted. The next session start automatically prunes stale worktrees; full-level health checks (on /distill and each auto-distill tick) prune stale branches older than 24 hours.
/distill-status requires a napkin vault resolvable from the current directory (or the global fallback at ~/.config/napkin/config.json). If no vault is found, pi shows a warning: "No napkin vault resolved from current directory."

Cleanup

If you need to forcibly reset all distill state for a vault (stuck lock, corrupted meta):
rm -rf ~/.cache/napkin-distill/<vault-hash>/
This is safe — anything valuable is either already committed to the vault’s main branch or was never going to commit.

Build docs developers (and LLMs) love