Commands
One name per command, no aliases. Each command below accepts the global
options --plain/--no-theme, -q/--whisper, and -v/--moan.
harvest
Gather files matching a pattern (default *.md) from a local path or a
repo URL, and concatenate them into one flat artifact with a provenance
header and per-file dividers.
reaper harvest . # every *.md, to stdout
reaper harvest . -p "*.py" -p "*.toml" -o CODE.md # multiple patterns
reaper harvest https://github.com/Textualize/rich --ref main -o RICH.md
reaper harvest . --max-file-size 1MB -x "CHANGELOG.md"
Remote sources are cloned shallow into the catacombs cache and reused on
repeat visits. Binary files and files over --max-file-size are skipped
with a reason; --max-total-size aborts loudly instead of truncating
silently.
limbs
Hierarchical file listing (the tree, limb by limb) for any folder, git or not.
reaper limbs . # ASCII tree, markdown-fenced
reaper limbs . --sizes --lines # annotate files
reaper limbs . -d 2 --dirs-only # shallow, directories only
reaper limbs . --format json # machine-readable
conjure
Bundle a repo into a single LLM-ingestible artifact (schema conjure/v1):
provenance block, file tree, then every text file inlined in deterministic
sorted order. Fences are computed to outlast any backtick run in the
content; end markers gain a nonce when the content fakes them. Binary,
non-UTF-8, and over-cap files are skipped with receipts in the artifact.
reaper conjure . -o PACKED.md
reaper conjure . --sha256 -o PACKED.md # verifiable hashes
reaper conjure . --split-tokens 100000 -o P.md # P.part01.md, P.part02.md, ...
reaper conjure https://github.com/Textualize/rich -x "tests/*" -o RICH.md
reanimate
The inverse of conjure: rebuild the directory tree from a packed
artifact, closing the loop for LLM editing workflows. Writes to an empty
directory by default (--force to overwrite); refuses absolute paths and
.. segments outright. Feed it all the parts of a sharded artifact.
reaper reanimate PACKED.md --out risen/
reaper reanimate P.part*.md --out risen/ --verify
The property that guards the round trip, tested from birth:
reanimate(conjure(tree)) == tree, byte for byte.
census
File-type census: counts, total and per-extension sizes, line counts, language breakdown, token estimate. Size a repo before conjuring it.
reaper census .
reaper census . --format csv > census.csv
reaper census https://github.com/Textualize/rich --format json
unfinished
Scan source for TODO / FIXME / HACK / XXX markers: file, line, text,
author (via git blame when the source is a repo), and --age for how
long each marker has haunted the codebase.
reaper unfinished .
reaper unfinished . --age --format csv
grimoire
Show effective configuration, where each value came from, and the stored
recipes. Configuration layers, weakest first: defaults, [tool.reaper]
in pyproject.toml, .reaperrc (TOML), environment variables.
reaper grimoire
reaper grimoire --format json
cast
Run a saved recipe from the grimoire. Extra arguments pass through as overrides.
# .reaperrc
[recipes.nightly-pack]
command = "conjure"
args = [".", "--sha256", "--out", "PACKED.md"]
reaper cast nightly-pack
reaper cast nightly-pack --split-tokens 50000 # override at cast time
perform
Run a saved rite: a named, ordered chain of steps from the grimoire, each
step a command plus its CLI argument tokens -- run in order against one or
more sources. The literal token {source} in a step's args is replaced with
the source currently being processed; a step without it runs identically for
every source. Each step is captured as JSON and folded into one combined
result, so a step's command must support --format json and --out (most
analysis rituals do; writers like harvest/conjure/veil and multi-arg
commands like scry do not qualify). A step that fails is recorded, not
fatal -- the rest of the rite still runs; check the exit code (nonzero if
any step failed) or read each outcome's ok/error in --format json.
# .reaperrc
[rites.audit]
description = "history plus a size check"
[[rites.audit.steps]]
command = "chronicle"
args = ["{source}", "--changelog"]
[[rites.audit.steps]]
command = "census"
name = "loc"
args = ["{source}"]
reaper perform audit . # one source, markdown status table
reaper perform audit . other-repo/ # the matrix: 2 steps x 2 sources
reaper perform audit . --format json | jq .outcomes # every step's full payload
Necromancy
Mining commit history: who, what, when, and what has died. These rituals
need a git repo (local, or a URL cloned into the catacombs at full depth);
all of them accept --ref to read a branch, tag, or sha.
chronicle
Extract commit history -- sha, author, date, message, files touched,
insertions and deletions. --changelog groups commits under the tag that
heads their release range.
reaper chronicle .
reaper chronicle . -n 50 --format csv > history.csv
reaper chronicle https://github.com/Textualize/rich --changelog -o HISTORY.md
souls
Contributor stats: commits, lines added and removed, first and last seen,
and a bus-factor estimate. --heatmap adds a day-of-week x hour activity
grid -- bucketed by each commit's recorded timezone, so the output never
depends on the machine -- and names the repo's witching hour.
reaper souls .
reaper souls . --heatmap
reaper souls . --format json -o souls.json
haunt
Code churn and hotspots: files ranked by change frequency and churn, the classic bug-risk proxy.
reaper haunt .
reaper haunt . -n 20 --format csv
autopsy
Deep single-file examination: the creation commit, rename history
(followed by default; --no-follow to pin the path), authors over time,
churn totals, and a blame-based line-age summary.
reaper autopsy src/git_reaper/cli.py
reaper autopsy README.md -s https://github.com/Textualize/rich --format json
graveyard
Every file that ever lived and died: path, date of death, the fatal commit, and its author. Renamed-away paths count as deaths.
reaper graveyard .
reaper graveyard . --format csv > graveyard.csv
resurrect
Restore a dead file's last living bytes -- read from the parent of the
commit that removed it -- into the working tree or --out (a directory
keeps the file's path; an exact file target renames it). Absolute paths
and .. segments are refused, same as reanimate; --force overwrites.
reaper graveyard . # find what can be raised
reaper resurrect docs/old-spec.md
reaper resurrect docs/old-spec.md -o attic/ --force
ghosts
Branch hygiene: branches ranked by abandonment, with merged-but-undeleted
and gone-upstream flags, plus a stale flag for branches idle past --than.
reaper ghosts .
reaper ghosts . --than 90d --format csv
rot
Staleness report: surviving files ranked by how long they have gone
untouched, ages derived from a single log pass. The [ward] table can
gate on it (rot = "730d").
reaper rot . -n 30
reaper rot . -x "docs/*" --format json
tombstone
A stats card for demos and READMEs -- born, age, commits, souls, last words, the witching hour -- as ASCII tombstone art, or JSON.
reaper tombstone .
reaper tombstone https://github.com/Textualize/rich --format json
Dark arts
Security and risk mining. exhume and veil share one rules engine
(core/rules.py): regex signatures plus a Shannon-entropy sweep, extended by
[rules.<name>] tables in the grimoire. Neither ever writes a full secret to
any output, log, or error message -- a found secret appears only masked, as
AKIA...MNOP.
exhume
Scan the full history (every reachable blob) for committed secrets. Reports
the commit, path, rule, and a masked preview. --baseline FILE suppresses
known findings (a JSON list of fingerprints, or a previous --format json
report). --fail-on {any,high} gates CI with exit 3.
--since REF bounds the walk to blobs reachable in REF..HEAD -- new blobs
only -- instead of the full object graph. A one-shot local scan doesn't need
it, but a caller that rescans the same repo repeatedly (CI on every push, a
scheduled rescan, a hosted watcher over commune) can pass the ref it last
scanned from and skip re-reading everything before it. The report's
scanned_since field records what was passed, so a JSON report is
self-describing about its scope; omit --since for the full-history scan,
unchanged.
reaper exhume . # report, exit 0
reaper exhume . --fail-on any # one-line CI gate (exit 3)
reaper exhume . --baseline known.json --fail-on high
reaper exhume . --no-entropy --format html -o secrets.html
reaper exhume . --since v1.2.0 # only blobs new since that tag
veil
Scrub secrets and configured patterns from any artifact before it leaves the
crypt, replacing each match with [VEILED:rule-name]. Reads a file or stdin
(-). Also available inline as conjure --veil, and as a ritual in summon
and commune.
reaper conjure . -o PACKED.md
reaper veil PACKED.md -o SAFE.md --report md # veiled artifact + a receipt
cat secrets.log | reaper veil - # scrub a stream
omens
Composite risk prophecy per file: a weighted blend of churn, bug-fix commit
density, recency, and size, each normalized to 0..1. Lenses isolate one
component; weights live in the grimoire's [omens] table. Omens are hints,
not fate.
reaper omens . # the full blend, ranked
reaper omens . --lens churn -n 20 # one lens, top 20
reaper omens . --fail-over 0.8 # exit 3 if any file scores >= 0.8
reaper omens . --format html -o risk.html
# .reaperrc -- tune the blend (defaults shown)
[omens]
churn = 0.35
bugs = 0.30
age = 0.20
size = 0.15
doppelgangers
Find duplicate files by content hash. Reports clusters and reclaimable space. Empty files are convention, not waste, and are ignored by default.
reaper doppelgangers .
reaper doppelgangers . --min-size 4KB --format json
bloat
The largest files in the working tree and, for repos, the blobs deleted from
the tree but still weighing down .git -- the body is still in the walls.
reaper bloat . -n 30
reaper bloat . --format html -o bloat.html
Deeper necromancy
bones
Strip implementation, keep structure: every file's imports, class/function
signatures, and docstring first lines. A compact code map that fits huge repos
into small contexts. Python via the stdlib ast (zero deps); other languages
need the git-reaper[bones] extra (tree-sitter), and are reported as skipped
without it -- never silently dropped.
reaper bones .
reaper bones . --format json
pip install "git-reaper[bones]" # adds JS, TS, Go, Rust, Java, C/C++, ...
scry
Compare two refs: total churn, the most-changed files, contributors active in
the range, and which souls appeared for the first time. Reads git's A..B
range.
reaper scry v1.0.0 v2.0.0
reaper scry v1.0.0 HEAD -s . --format html -o release-delta.html
plague
Opt-in and network-using: read dependency manifests (pyproject, requirements,
package.json) and check the exactly-pinned ones against the OSV database.
--offline degrades gracefully to manifest parsing only. --fail-on any
gates CI with exit 3. This is the only command that ever leaves the crypt.
reaper plague . # consult the OSV oracle
reaper plague . --offline # parse manifests, never touch the network
reaper plague . --fail-on any # exit 3 if any affliction is found
distill
The apprentice: read a repo and emit a portable Agent Skill -- a SKILL.md
bundle (default skills/<name>/) with reference/ files for structure
(the bones map), conventions (layout, languages, tooling, the measured
commit style), commands (real build/test/lint/run invocations lifted from
pyproject.toml, the Makefile, package.json, and CI workflows --
never guessed), gotchas (the files that break most, and the fix themes
that recur), and ownership (top souls and the bus factor; --anon
reduces them to roles). Composed from rituals that already exist,
deterministic by default: zero network, zero model calls. --profile
{repo,stack,onboarding} sets the voice.
Every skill is stamped with the source and sha it was distilled from, and
distill --check DIR exits 3 (cursed) once the code has moved on -- a
one-line CI freshness gate, also foldable into the [ward] table.
--polish CMD is the opt-in escape hatch from the deterministic draft:
each reference file's prose is piped through your own command (stdin to
stdout -- a claude -p wrapper, a local model, anything you trust), while
frontmatter and provenance stamps are held back and reattached, so a
polisher may smooth prose but never rewrite facts of origin.
--format also takes zip, tar, or tar.gz to package the bundle into
a single archive instead of a loose directory (skip --check afterward --
it reads a skill directory, not an archive).
reaper distill . # write skills/<name>/
reaper distill . --profile onboarding --anon -o skills/repo-guide
reaper distill --check skills/repo-guide # exit 3 once stale
reaper distill . --polish "claude -p 'tighten this prose'"
reaper distill . --format tar.gz # skills/<name>.tar.gz
At fleet scale, reaper necropolis distill writes one skill per grave
plus a routing index skill at the library's root.
scavenge
The scavenger: where distill writes a new skill from what it learns,
scavenge steals the ones already interred. Every folder holding a
SKILL.md is lifted whole -- prose, reference/ files, scripts, binary
assets, byte for byte -- and reburied in a library directory (default
skill-crypt/), with a routing SKILL.md at the root that indexes the
loot, so the crypt itself is loadable. Ignore rules hold on the way out:
a gitignored skill folder is never found, and ignored files inside a
taken folder stay buried. The report (and the routing SKILL.md itself)
calls out any binary/non-text assets a skill carries along by name, so a
folder full of reference docs and scripts doesn't look identical to one
that also drags in images or other binary files.
Topmost wins (a SKILL.md nested inside another skill's folder rides
along instead of being lifted twice), two skills sharing a folder name
are numbered instead of clobbered, and re-scavenging refreshes the same
folders rather than accumulating copies. A repo whose root holds the
SKILL.md is taken whole under the source's name. Finding nothing
writes nothing.
--format also takes zip, tar, or tar.gz to package the crypt into
a single archive instead of leaving it as a loose directory -- entries
sorted and deterministic, same discipline as embalm.
reaper scavenge https://github.com/anthropics/skills --out skill-crypt/
reaper scavenge . -x "vendor/*" --format json | jq '.skills[].path'
reaper scavenge . --format zip # skill-crypt.zip
reaper necropolis scavenge --org my-org --out-dir crypt/ # a fleet's loot
At fleet scale, reaper necropolis scavenge gives each grave its own crypt
and a fleet-level routing skill above them: two levels of index, both
readable by an agent.
necropolis
Fan any source-taking reaper command across every grave in a
necropolis.toml manifest (or a GitHub org via --org and the gh CLI).
Writes a per-grave artifact plus a combined INDEX.md that records every
outcome, failures included. A failed grave never stops the fleet.
Necropolis's own --format also takes zip, tar, or tar.gz to
package the whole --out-dir (every grave's artifact plus INDEX.md)
into one archive -- separate from any --format you pass through to the
fanned-out command itself.
reaper necropolis harvest --tag docs --out-dir out/
reaper necropolis exhume --fail-on any --out-dir audit/ # exit 3 if cursed
reaper necropolis census --org my-org --out-dir survey/
reaper necropolis harvest --tag docs --out-dir out/ --format zip
# necropolis.toml
[[grave]]
source = "https://github.com/jmcmeen/observa.git"
tags = ["docs"]
[[grave]]
source = "/local/path/to/repo"
name = "beta"
Last rites
ward
The composite CI gate. A [ward] grimoire table folds the
exhume/omens/plague/rot thresholds and distill --check skill
freshness into one policy; one reaper ward exits 3 if any ward breaks. A
check that crashes fails closed. With nothing inscribed, the default policy
gates committed secrets (exhume = "any").
Like every command, ward reads its grimoire from where you stand -- the
current directory -- not from the source argument. reaper ward /elsewhere
scans /elsewhere under your policy; to gate a repo under its own
[ward] table, run ward from inside it, as CI does.
reaper ward . # the whole policy, one exit code
# .reaperrc
[ward]
exhume = "any" # or "high", or "off"
omens = 0.85 # exit 3 when any omen scores this or worse
rot = "730d" # exit 3 when files sit untouched past this
skills = ["skills/git-reaper"] # distill --check freshness, gated
banshee
Watch mode: poll a directory (ignore rules honored) and scream -- re-run a recipe from the grimoire -- whenever it changes. Portable polling, no new dependencies. Runs the recipe once at the start, then keeps vigil; ctrl+c lays her to rest.
reaper banshee nightly-pack # watch ., recast on change
reaper banshee nightly-pack -s docs/ --interval 5 --once
leech
The inverse of harvest for ordinary markdown: drain fenced code blocks back
into files. Blocks the document names (```python title=app.py or a bare
path info string) keep their name; the rest are numbered by language.
Reanimate's path-traversal guards apply. --format also takes zip,
tar, or tar.gz to package the drained blocks into a single archive.
reaper leech TUTORIAL.md --out src/
reaper leech notes.md --lang python # only the python blocks
cat model-output.md | reaper leech - --out risen/
reaper leech TUTORIAL.md --out src/ --format zip
embalm
Preserve a repo state in a deterministic, provenance-stamped .tar.gz:
sorted entries, zeroed ownership, timestamps pinned to the HEAD commit --
byte-identical across runs. A PROVENANCE block and MANIFEST.sha256 ride
at the archive root, and the receipt prints the archive's own sha256.
reaper embalm . -o snapshot.tar.gz
reaper embalm . -x "*.log" --format json
The number of the bits
wake
Draft a Keep-a-Changelog section from the commits since the last tag (or
--since REF). Conventional-commit prefixes map onto the Keep-a-Changelog
categories, everything else lands under Changed, and a version bump is
suggested (! or BREAKING means major). A draft for a human to edit.
reaper wake .
reaper wake . --since v0.8.0 -o DRAFT.md
lineage
Trace a line's true origin across history with git's pickaxe: every commit
that added or removed the needle (-S, or -G with --regex), plus the
origin -- who first summoned it.
reaper lineage "def resolve_source" -s .
reaper lineage "MAGIC_\w+" --regex --path src/
possession
The ownership and knowledge map: dominant author per file and per top-level
directory, with the share they hold. One soul holding --threshold (default
75%) of a file's commits flags it possessed -- the bus-factor hotspots to
find before they leave. Knowledge, not blame.
reaper possession . -n 20
reaper possession . --threshold 0.9 --format json
revenant
Track what will not stay buried: files deleted and later re-added (deaths,
rebirths, whether it walks today) and repeat offenders that keep collecting
fix commits (--fixes sets the bar).
reaper revenant .
reaper revenant . --fixes 5
prophecy
Omens extended across time: forecast which files will demand attention next
from heat (decayed activity), momentum (this --horizon window vs the one
before it), and fresh fixes. Like omens: hints, not fate.
reaper prophecy . -n 20
reaper prophecy . --horizon 30 --format json
exorcise
Compose bloat's dead blobs (past --min-size) and exhume's findings
into a safe history-purge plan: the exact git filter-repo and BFG
commands, printed beside the warnings that belong with them. It plans and
prints; it never rewrites history itself.
reaper exorcise .
reaper exorcise . --min-size 5MB --no-secrets
effigy
Render the repo as a self-contained SVG poster: a contributor
constellation, the witching-hours heatmap, and a directory treemap strip,
with the provenance riding in the SVG's <desc>. The portrait of the dead,
suitable for a README or a talk.
reaper effigy . -o portrait.svg
reaper effigy . --format json # the measured portrait data
summon (the TUI)
Launch the Sanctum, the interactive Textual TUI (needs the [tui] extra): a
Dracula-themed workbench of chambers over the same core the CLI drives. It
opens on the crypt map; each chamber is a door -- enter opens one, the
number keys 1-6 jump from anywhere, escape walks back to the map, and
Ctrl+P's palette knows every door (and switches themes live). Chambers
keep their state while you roam.
pip install "git-reaper[tui]"
reaper summon . # prefill the source
- The Altar -- run a ritual against one source: pick, tune its options,
reap, preview, save (
rreap -ssave -ccopy -bbrowse -mraw/rendered -?help). Recipes from the grimoire load with one keypress. - The Grimoire -- compose recipes visually and watch the exact CLI
incantation update live; save writes
.reaperrc, so anything built here runs headless later viacast. - The Incantation console -- assisted CLI: type
/for a fuzzy ritual menu, get live flag help, and Enter runs a real, reproduciblereaperinvocation. - The Necropolis board -- the fleet, grave by grave: load a
necropolis.toml, run a ritual across every grave, drill into any artifact. - The Reliquary -- security-and-risk triage on one slab: exhume, omens, plague (offline), and rot merged and sorted most-cursed first.
- The Seance table -- the souls heatmap, a chronicle scrubber, and a
scryref-versus-ref picker in one view.
The ritual catalog (shared by the Altar, the console, and commune), grouped
as in the sidebar: reaping (limbs, harvest, scavenge), packing (conjure, census,
unfinished, bones), necromancy (chronicle, souls, haunt, autopsy, graveyard,
rot, ghosts, tombstone, wake, possession, revenant, lineage), forensics
(doppelgangers, bloat), and dark arts (exhume, veil, omens, plague,
prophecy, exorcise, ward). Git-only rituals are marked * and gray out when
the source is a plain folder. Each ritual exposes its flags as widgets --
including the positional rituals' arguments (autopsy's path, lineage's
needle, veil's file; relative files anchor to the source). plague
--offline stays on by default (no surprise network), and exhume, omens,
and plague light a red cursed badge when the scan turns up what you feared;
previews stay masked.
The commands that write to disk (reanimate, resurrect, leech) or that
emit artifacts rather than reports (embalm, effigy, distill) stay
CLI-only, along with pulse, banish, and banshee. The one exception is
scavenge, which both writes (the library fills as you reap) and reports
(the preview is the routing index it just wrote). Everything else has a
chamber: scry sits at the Seance table, the Necropolis board drives the
fleet, and the Grimoire chamber and the Altar's recipe list cover grimoire
and cast.
commune (the MCP server)
Serve the read-only rituals to agents over the Model Context Protocol (needs
the [mcp] extra). A fourth face on the same engine: every analysis ritual in
the TUI's catalog becomes an agent-callable tool whose input schema mirrors
the ritual's options and whose output is the same provenance-stamped JSON the
CLI prints -- plus scry and grimoire, which take extra arguments.
(autopsy and veil keep dedicated tools: a required path with a follow
toggle, and raw text that never touches disk.)
pip install "git-reaper[mcp]"
reaper commune . # stdio server, read-only, rooted at .
reaper commune --http 127.0.0.1:6666 # shared server for a team
reaper commune . --allow-write # let a trusted agent resurrect/banish
- Transports. stdio by default (for local agent clients); streamable HTTP
with
--http HOST:PORTfor a shared or remote reaper. Off unless asked for, consistent with the no-phone-home posture. - Rooted. Local paths must sit under an allowed root (
--root, repeatable; defaults to the launch source) and remote URLs on an allowed host (--host). An agent cannot point the reaper at arbitrary disk. - Read-only by default. The writing rituals --
resurrect,reanimateandscavenge(whose targets must land inside the allowed roots), andbanish-- appear only with--allow-write.veilis always available: it scrubs artifact text in flight and touches no disk.plagueis forced to offline manifest parsing unless--allow-network.exhumereturns the same masked previews it prints anywhere else -- a full secret never crosses the wire. - Resources and prompts. The effective grimoire, tombstone, and census
are published as MCP resources;
pack-this-repo,audit-this-repo, andexplain-this-repoprompts give an agent a sane default workflow. - Config. A
[commune]grimoire table (roots,hosts,tools,allow_write,allow_network) ships one blessed server config; flags outrank it.
To register with an MCP client, point it at the command -- for example,
claude mcp add reaper -- reaper commune ~/repos/that-cursed-monolith.
pulse
Signs-of-life check: git present and version, optional extras installed, catacombs health, tty/color detection. The first thing to run when a ritual misbehaves.
reaper pulse
reaper pulse --format json
banish
Clear the catacombs (the clone cache).
reaper banish # clear everything
reaper banish --older-than 7d # partial exorcism
The catacombs
Remote clones land in a content-addressed cache:
~/.cache/git-reaper/catacombs/<host>/<owner>/<repo>
Local file:// sources are buried flat as localhost/<name>-<digest>:
mirroring a deep source path under the catacombs would breach Windows'
260-char path limit.
Shallow by default (--depth 1), reused across runs, cleared by banish.
Override the location with the GIT_REAPER_CACHE environment variable.
Ignore rules
The reaper honors, in combination:
- the repo's own
.gitignore - a project-level
.reaperignore(same syntax) - ad-hoc
--excludeglobs .gitis always ignored; symlinks are never followed
Schemas
Every JSON-emitting command publishes its output schema:
reaper limbs --schema
reaper harvest --schema
reaper exhume --schema
Analysis commands add --format html for a self-contained, dark-themed
report (no external requests; styles and the only chart -- a CSS bar per
row -- are inline).
Exit codes
| Code | Meaning |
|---|---|
| 0 | Rest in peace. Success. |
| 1 | The ritual failed. Unexpected error. |
| 2 | Bad incantation. Usage error. |
| 3 | Cursed. The scan succeeded and found what you feared. |
Exit 3 is what makes reaper exhume --fail-on any a one-line CI gate;
omens --fail-over, plague --fail-on, a broken ward, distill --check,
and necropolis (when any grave is cursed) share the semantics. When you
want a single gate, wire in reaper ward and tune the [ward] table.
Plain output
--plain (or --no-theme) produces clean ASCII; NO_COLOR is honored;
non-tty output auto-disables color, animation, and art. Artifacts go to
stdout or --out; all narration goes to stderr, so piping is always safe.