API reference
The typed core, straight from the source.
Models
Result models. Every core function returns these, never formatted strings.
Formatting is a separate layer (formatters/); the CLI and TUI only present.
RepoRef
dataclass
Where the data came from: a local path or a remote clone.
Provenance
dataclass
Stamp carried by every combined or packed artifact.
FileEntry
dataclass
One file the reaper looked at. Paths are POSIX-style and relative.
HarvestResult
dataclass
The flagship: gathered files ready to be concatenated.
TreeNode
dataclass
One node in a hierarchical listing.
TreeResult
dataclass
A hierarchical file listing. Works on any folder, git or not.
PackedFile
dataclass
One file inlined into a conjured bundle.
PackResult
dataclass
A repo conjured into an LLM-ingestible bundle.
ReanimatedFile
dataclass
One file reconstructed from a conjured bundle.
ReanimateResult
dataclass
The inverse of conjure: what rose from the artifact.
ExtensionStat
dataclass
Census row: one file extension.
CensusResult
dataclass
File-type census: what is buried here, and how much of it.
Marker
dataclass
One TODO/FIXME/HACK/XXX haunting the codebase.
UnfinishedResult
dataclass
Every unfinished thing the scan turned up.
ConfigValue
dataclass
One effective grimoire setting and where it came from.
Recipe
dataclass
A named bundle of flags stored in the grimoire.
RiteStep
dataclass
One step of a rite: a command and its CLI argument tokens.
The literal token {source} anywhere in args is replaced with the
source currently being processed; a step without it ignores the rite's
source loop and runs identically for every source.
Rite
dataclass
A named, ordered sequence of steps stored in the grimoire.
StepOutcome
dataclass
One step's result against one source.
RiteResult
dataclass
A rite's combined outcome across every step and source.
combined()
Nest outcomes as {source: {step: output}} for export/display.
GrimoireResult
dataclass
Effective configuration: values, origins, and stored recipes and rites.
PulseCheck
dataclass
One signs-of-life check.
PulseResult
dataclass
Doctor report: is this corpse fit for necromancy?
CommitEntry
dataclass
One commit in the chronicle.
ChangelogSection
dataclass
Commits gathered under one tag (or the unreleased head).
ChronicleResult
dataclass
Commit history, newest first, optionally grouped into a changelog.
Soul
dataclass
One contributor's ledger.
SoulsResult
dataclass
Contributor stats, a bus-factor estimate, and an optional heatmap.
Hotspot
dataclass
One file ranked by how often it changes and how much.
HauntResult
dataclass
Code churn and hotspots: the classic bug-risk proxy.
AuthorShare
dataclass
One author's slice of a single file's history.
AutopsyResult
dataclass
Deep single-file examination.
DeadFile
dataclass
A file that lived and died: path, fatal commit, and its author.
GraveyardResult
dataclass
Every file that ever lived and died in the repo.
ResurrectResult
dataclass
A dead file brought back from the graveyard.
Branch
dataclass
One branch's hygiene report.
GhostsResult
dataclass
Branch hygiene: activity, merged-but-undeleted, gone remotes.
StaleFile
dataclass
One file ranked by how long it has gone untouched.
RotResult
dataclass
Staleness report: files untouched the longest.
TombstoneResult
dataclass
A stats card for demos and READMEs.
SecretFinding
dataclass
One secret the exhumation turned up. Never carries the full secret.
ExhumeResult
dataclass
Secrets dug out of the full history.
VeilCount
dataclass
How many times one rule fired during a veiling.
VeilResult
dataclass
A redaction pass: what was hidden, never what it was.
Omen
dataclass
One file's risk prophecy. Scores are 0..1; omens are hints, not fate.
OmensResult
dataclass
Composite per-file risk, ranked most-cursed first.
CloneCluster
dataclass
Files that are byte-for-byte the same soul in different bodies.
DoppelgangersResult
dataclass
Duplicate files by content hash.
BloatEntry
dataclass
One heavy body: a working-tree file or a blob still in the walls.
BloatResult
dataclass
The largest files, and the blobs deleted from the tree but not the past.
SkeletonEntry
dataclass
One structural bone: an import, class, function, or method.
SkeletonFile
dataclass
One file stripped to its structure.
BonesResult
dataclass
Implementation stripped, structure kept: the compact code map.
ScryDelta
dataclass
One file's churn between the two refs.
ScryResult
dataclass
What changed between two refs: churn, files, and contributors.
Dependency
dataclass
One dependency read from a manifest.
Affliction
dataclass
One known vulnerability afflicting a pinned dependency.
PlagueResult
dataclass
Dependency manifests checked against the OSV database (opt-in network).
CommandHint
dataclass
One real command lifted from the repo's own tooling files, not guessed.
Gotcha
dataclass
One file that keeps breaking: churn plus bug-fix density.
DistillResult
dataclass
A repo distilled into the facts an Agent Skill bundle is built from.
ScavengedSkill
dataclass
One skill folder lifted whole from the source.
ScavengeResult
dataclass
Existing Agent Skill folders scavenged into a library directory.
GraveOutcome
dataclass
One repo's fate in a necropolis fan-out.
NecropolisResult
dataclass
A command fanned across every grave in the manifest.
WardCheck
dataclass
One ward in the composite CI gate: a ritual run against its threshold.
WardResult
dataclass
The composite gate: every configured ward, and whether any broke.
LeechBlock
dataclass
One fenced code block pulled out of a markdown document.
LeechResult
dataclass
Fenced code blocks drained from a document back into files.
EmbalmResult
dataclass
A repo state preserved in a provenance-stamped tarball.
WakeSection
dataclass
One Keep-a-Changelog category in the drafted section.
WakeResult
dataclass
A changelog section drafted from the commits since the last tag.
LineageResult
dataclass
Every commit that added or removed a needle, back to its first summoning.
FileOwnership
dataclass
One file's dominant author and how tightly they hold it.
DirOwnership
dataclass
One top-level directory's dominant author.
PossessionResult
dataclass
The knowledge map: who holds each file, and where one soul holds all.
Revenant
dataclass
A file that died and rose again (at least once).
RepeatOffender
dataclass
A file that keeps getting 'fixed'.
RevenantResult
dataclass
What will not stay buried: resurrections and repeat offenders.
Prophecy
dataclass
One file's forecast. Like omens: a hint, never fate.
ProphecyResult
dataclass
Omens extended across time: which files will demand attention next.
ExorciseTarget
dataclass
One thing the purge plan would expel from history.
ExorciseResult
dataclass
A safe purge plan: it plans and prints, it never rewrites history.
EffigySlice
dataclass
One top-level directory's share of the effigy treemap.
EffigyResult
dataclass
The portrait of the dead: everything the SVG poster is drawn from.
CacheEntry
dataclass
One interred repo in the catacombs.
BanishResult
dataclass
What the exorcism removed.
Core
Resolve a source argument: local path, or remote URL via the catacombs.
resolve_source(source, ref=None, depth=1, backend=None)
Turn a path or URL into a readable local directory.
Local paths are used in place. Remote URLs are cloned (shallow by default) into the catacombs and reused on repeat visits.
The flagship: gather files matching patterns and prepare them for concatenation. Returns a HarvestResult; rendering lives in formatters/.
CapExceeded
Bases: RuntimeError
The total size cap was hit. The message says exactly where.
harvest(repo, patterns=DEFAULT_PATTERNS, excludes=None, max_file_size=None, max_total_size=None, include_binary=False, invoked='reaper harvest', generated=None)
Gather every matching file under the resolved source.
Skips are never silent: each skipped file is recorded with its reason so the report can show exactly what was left in the ground.
Hierarchical file listing. Works on any folder, git or not.
tree(repo, max_depth=None, dirs_only=False, with_sizes=False, with_lines=False, excludes=None, invoked='reaper limbs', generated=None)
Build the hierarchy, honoring ignore rules and the depth limit.
The shared secret/PII rules engine behind exhume and veil.
One engine, two rituals: exhume detects (full history, masked previews),
veil redacts (any artifact, [VEILED:rule-name]). Neither ever writes a
full secret to any output, log, or error message - a found secret appears
only as AKIA...9X2Q (masked).
Built-in signatures cover the common key formats plus a Shannon-entropy sweep for the ones that have no format. The grimoire extends the set:
[rules.internal-hostname]
pattern = "[a-z0-9-]+\.corp\.example\.com"
severity = "medium"
veil_only = true # redacted by veil, never reported by exhume
Rule
dataclass
One signature: a name, a compiled pattern, and how loudly to scream.
RuleMatch
dataclass
One raw hit inside a text: which rule, where, and the matched span.
RuleError
Bases: ValueError
A custom rule is miswritten. Message names the rule and the sin.
VeiledText
dataclass
A redacted text and the tally of what was hidden.
load_rules(custom=None)
The built-ins plus grimoire extensions (see config.custom_rules).
shannon_entropy(text)
Bits per character; random base64 sits near 6, English near 4.
mask(secret)
First/last 4 chars only, per the contract: never the full secret.
fingerprint(rule, secret)
Stable id for a finding that does not store the secret itself.
scan_text(text, rules=None, with_entropy=True)
Every rule hit in a text, ordered by position. Overlaps: first rule wins.
load_baseline(path)
Fingerprints to suppress: a JSON list of strings, or a previous
exhume --format json report (fingerprints are pulled from findings).
exhume(repo, rules=None, with_entropy=True, baseline=None, since_ref=None, invoked='reaper exhume', generated=None, backend=None)
Scan every reachable blob in history for secrets.
Each unique blob is read once; findings are attributed to the oldest
commit that introduced the blob at its recorded path. since_ref bounds
the walk to blobs reachable in since_ref..HEAD -- new blobs only --
instead of the full object graph; a blob already scanned in a prior run
(anything reachable from since_ref) is never read again.
cursed(result, fail_on)
CI gate: does this report warrant exit 3?
veil_text(text, rules=None, with_entropy=True)
Replace every rule hit with [VEILED:rule-name].
veil(text, source, repo, rules=None, with_entropy=True, invoked='reaper veil', generated=None)
Veil an artifact's text; returns (result, redacted text).
scrub(message, rules=None)
Veil a log/debug line. --shriek output goes through this.
Omens: a composite risk prophecy per file.
The score blends four classic proxies - churn, bug-fix density, recency,
and size - each normalized to 0..1, weighted by the grimoire's [omens]
table. Lenses isolate one component (--lens churn) or blend them all.
Honest framing, per the plan: omens are hints, not fate. A high score says "look here first", never "this file is broken".
omens(repo, lens='all', weights=None, limit=None, backend=None, invoked='reaper omens', generated=None, now=None)
Score every surviving file and rank the cursed ones first.
doomed(result, fail_over)
The omens at or above the CI threshold (exit 3 when non-empty).
Doppelgangers and bloat: the same bytes twice, and the heavy bytes.
doppelgangers finds working-tree files that are byte-for-byte identical
(content sha256), reporting clusters and the space a cleanup would reclaim.
bloat ranks the largest working-tree files and, in a repo, the blobs that
were deleted from the tree but still weigh down .git - the body is still
in the walls.
doppelgangers(repo, excludes=None, min_size=1, invoked='reaper doppelgangers', generated=None)
Cluster identical files by content hash.
Size is compared first so only same-sized files get hashed; empty files are ignored by default (min_size=1) because a thousand empty init.py are convention, not waste.
bloat(repo, limit=DEFAULT_LIMIT, excludes=None, invoked='reaper bloat', generated=None, backend=None)
The largest files in the tree, and dead blobs still haunting .git.
Works on plain folders too - the walls section is simply empty when there is no history to hide bodies in.
Bones: strip implementation, keep structure.
Emits every file's imports, class/function signatures, and docstring first lines - a compact code map that fits huge repos into small contexts.
Python parses with the stdlib ast (zero deps, exact). Other languages go
through tree-sitter when the git-reaper[bones] extra is installed; without
it they are reported as skipped, never silently dropped.
bones(repo, excludes=None, invoked='reaper bones', generated=None)
Walk the tree and reduce every recognized source file to its bones.
Scry: gaze between two refs and read what changed.
Graduated from the back of the crypt once omens stabilized. The vision covers the commits reachable from B but not A (git's A..B range): total churn, the most-changed files, who did the changing, and which souls appeared for the first time inside the range.
scry(repo, ref_a, ref_b, limit=None, backend=None, invoked='reaper scry', generated=None)
Compare two refs: churn, files, and contributors in A..B.
Plague: check dependency manifests against the OSV database.
Manifest parsing is pure and offline. The network hop is injectable (and
lives in net/osv.py), so --offline degrades gracefully to manifest
parsing and tests never touch the wire.
Only exactly-pinned dependencies are queried - a range like >=2.0 has no
single version to ask about - and every skip is counted, never silent.
plague(repo, offline=False, query_batch=None, vuln_summary=None, invoked='reaper plague', generated=None)
Read every manifest under the root; consult the oracle unless offline.
The necropolis: fan one reaper command across every grave in a manifest.
Graves come from a necropolis.toml manifest or, with --org, from the
gh CLI. Each grave gets its own artifact in the out dir; a combined
INDEX.md records every outcome, including the failures - a fan-out that
hides a failed grave is worse than none.
The runner is injectable: the CLI passes a closure that re-invokes the
Typer app (the same trick cast uses), and tests pass a fake.
FleetError
Bases: ValueError
The manifest is miswritten or the org lookup failed.
Grave
dataclass
One repo in the necropolis.
load_manifest(path)
Parse necropolis.toml: [[grave]] tables with source, name?, tags?.
derive_name(source)
A grave's name from its source: last path segment, .git shroud removed.
org_graves(org, limit=200)
Every repo in a GitHub org, via the gh CLI (which owns the auth).
artifact_extension(args)
Match the per-grave artifact suffix to any --format in the args.
necropolis(command, args, graves, out_dir, runner, tag=None, archive=None)
Run reaper <command> <grave> <args> --out <dir>/<name>.<ext> per grave.
archive, one of fsutil.ARCHIVE_FORMATS, packages the whole out_dir (every grave's artifact plus INDEX.md/SKILL.md) into a single file afterward; this is separate from any --format a fanned-out sub-command carries in args, which only affects that sub-command's own per-grave artifact.
render_index(result)
The combined index: one row per grave, failures included.
render_index_skill(result, out_dir)
The routing skill at the library's root: one row per harvested skill.
An agent loads this first and follows the row to the right repo's skill; each row's description is read back from the skill it routes to.
fleet_exit_code(result)
1 if any grave failed outright, else 3 if any is cursed, else 0.
Cache
The catacombs: the clone cache.
Remote clones land in a content-addressed cache under
~/.cache/git-reaper/catacombs/<host>/<owner>/<repo>, shallow by default,
reused across runs, and cleared by banish. Local file:// sources are
buried flat as localhost/<name>-<digest> to stay inside Windows path
limits.
catacombs_root()
Cache root, overridable via GIT_REAPER_CACHE for tests and CI.
grave_path(url)
Map a remote URL to its plot in the catacombs.
list_graves()
Every interred repo, oldest first.
mark_grave(repo_path, url)
Record the source URL and refresh the last-used stamp.
banish(older_than_seconds=None)
Clear the catacombs. With older_than, a partial exorcism.
parse_age(text)
Parse '7d', '12h', '90m' into seconds. Raises ValueError.
Schemas
JSON schema export for every result model.
Every JSON-emitting command publishes its schema (--schema) so notebooks
and models can consume reaper output without guessing. Schemas are derived
from the dataclasses in models.py; keeping them mechanical keeps them honest.
schema_for(cls)
Build a JSON schema for a result model dataclass.
artifact_schema(command)
The provenance schema string for a command's artifacts, e.g. 'harvest/v1'.