Help us shape the future of Go! Take the 2026 Go Developer Survey

slop-ferret

module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2026 License: MIT

README

Slop Ferret

slop-ferret

CI Release Go

Ferrets AI slop out of a codebase: work that looks finished and is not. A feature nothing calls, a test that cannot go red, a comment describing behaviour the code lacks, a guard whose condition can never be true.

slop-ferret is an audit and reporting tool, not an enforcement mechanism. It does not block merges, fail builds, or prevent releases. It reads a call map, enumerates what a sweep should look at, accounts for what was actually read, and renders the findings as a report. What you do with that report is your decision.

The name is the hunter, not the quarry.

Why

A sweep for slop is mostly reading, and reading is what a model does. But a sweep also has a mechanical half (which files exist, which has anything looked at, what did the map say is unreachable, how much of this repository has actually been read), and that half was being done by hand, in prose, differently each time.

Doing it by hand produced the failure this tool exists to expose: a sweep that reported COMPLETE having read 17 of 25 source files, because what it had completed was its own worklist rather than the repository. The tool's job is to keep those two numbers separate and computed, so that one can never be read as the other.

The split: transforms belong in the tool, judgement belongs in the skill. Enumerating files and computing coverage fractions need no model. Deciding whether a finding clears its pre-filing bar does, and no amount of Go will do it.

Prerequisites

Two, plus a helper for Rust targets:

why get it
magma ≥ 0.2.0 builds the call map ferret plan reads. There is no fallback: without a map, plan refuses. go install github.com/robot-accomplice/magma@latest
magma-rust-helper only for Rust targets. magma shells out to it for rust-analyzer name resolution; without it magma refuses with a message naming this binary. cargo install --path rust-helper from a magma checkout
an agent that reads SKILL.md the skill half is a Claude Code skill. ferret install deploys into ~/.claude/, and the sweep itself is run by an agent reading SKILL.md. The binary alone does not sweep anything. Claude Code

Rust maps are slow: measured 68 minutes for 834 files (rust-analyzer, single pass). Budget for it, and reuse the map; ferret plan refuses a map of a different tree, so a stale one cannot silently be reused.

Install

curl -fsSL https://raw.githubusercontent.com/robot-accomplice/slop-ferret/main/install.sh | sh

Downloads the released binary for your platform, verifies its sha256 against the release's checksums.txt, installs it, and deploys the skill. Pin a release with VERSION=v0.1.0 and choose where the binary lands with BINDIR=~/bin (default: /usr/local/bin, falling back to ~/.local/bin). macOS and Linux, amd64/arm64.

Prefer to let Go manage it, or build from source? That works too, but you must run ferret install yourself afterwards, which the script does for you:

go install github.com/robot-accomplice/slop-ferret/cmd/ferret@v0.1.0
ferret install

ferret install is required, not optional: the H-signal vocabulary lives in the deployed lexicon, not in the binary. Without it ferret plan refuses rather than handing back an empty worklist. Run ferret doctor afterwards; it checks the deployment on its own, with no network. install deploys the skill into ~/.claude/skills/slop-ferret/ and writes both command entries (/slop-ferret and /slop-ferret:report).

macOS and Linux only. Windows builds are not published: install creates symlinks, which needs privilege or developer mode on Windows, and no Windows path in this tool has ever been executed. Publishing a binary nobody has run is the failure class this project exists to find.

Usage

magma --depth 1 <repo> <name> ~/.slop-ferret/maps       # build the call map first
ferret plan ~/.slop-ferret/maps/<name> <sha> <repo> [--since <ref>] > plan.json
#   ... run the sweep, write discharge.json ...
ferret enumerate plan.json discharge.json             # 0 accounted · 3 items open
ferret report plan.json discharge.json findings.json report.html
command does
plan reads the magma map, raises candidates with their pre-filing bars, enumerates the family-H worklist and its complement
enumerate reports two attested fractions and a work queue
report renders the sweep page; every figure derived from the plan and the discharge, never typed
install / update synonyms: acquire the skill and deploy it
doctor drift between the deployed skill and its source, in both directions
records prior sweeps of a repository, newest first
Two fractions, no verdict word
attested.repo   production source files read / total     "was the repo covered"
attested.plan   items dispositioned / items raised       "was the plan worked through"

They are different numbers and the gap between them is the point. A COMPLETE / PARTIAL / INCOMPLETE verdict was removed because one token cannot carry two quantities: a real sweep scored 10/10 on the plan and 17/25 on the repo and reported COMPLETE, having never enumerated the highest-consequence file in the tree.

Both fractions are attested: the discharge is the auditor's own record of what they read and dispositioned, and nothing corroborates it. The tool settles the accounting; it cannot do the reading. Treat the output as a report to act on, not a guarantee to rely on.

exit means
0 nothing raised is undispositioned
2 misuse: wrong arity, unreadable file
3 items still open; read the work queue
4 a refusal: wrong tree, unknown contract, missing map. Nothing was measured.

3 and 4 are separate so that an unfinished sweep is distinguishable from a map of the wrong tree; those want opposite responses. None of the exit codes says whether the repository was covered, because that is a fraction and a fraction does not fit in a byte.

Waivers

A waiver settles the accounting and does not raise attested.repo. Deciding not to read a file is a normal, correct move and costs nothing to record, but a waived file genuinely was not read, and the fraction exists to tell you what you actually looked at. No coverage floor is enforced: there is no defensible number, and punishing a sweep for reading 67% instead of 90% would only teach you to waive to clear it.

Two artifacts, two cadences

The skill is not welded to the binary. SKILL.md and the lexicon are prose; they change far more often than the code, and usually for reasons the code does not care about.

No prose is compiled into the binary. That makes the two cadences structural rather than conventional: a binary that cannot carry prose cannot quietly re-couple them, and what gets deployed stays reviewable as files.

source command who uses it
repo @ this binary's version ferret install the normal case: a downloaded binary, no checkout
repo @ a ref ferret install --ref main tracking a branch, or an older skill against a newer binary
a checkout ferret install --from . development

The default is self-pinning: a 0.3.0 binary installs the v0.3.0 skill, the prose that version was tested with, without the user needing to know a ref exists. Before the first tag it says so and names the alternatives rather than falling back to HEAD.

Releases also publish slop-ferret-skill_<tag>.tar.gz checksummed alongside the binaries: a supported acquisition path, not a required one.

doctor reports the binary version and the deployed skill's version separately, with the provenance of the deployed copy, and works with no source reachable. Downloads are staged to a temp dir before anything is deployed: a half-applied update is worse than a stale one.

Sweep records

ferret enumerate plan.json discharge.json ~/code/target   # writes a record
ferret records ~/code/target                           # prior sweeps, newest first

Records live in ~/.slop-ferret/records/<repo>/<sha>.json, never inside the repository being swept. They carry a computed half the tool derives and an attested half the discharge supplies, including classes checked clean with the method used, because "clean" with no method is not checkable, and an unchecked clean is how a later sweep skips ground nobody covered.

Writing refuses a sha that does not resolve: a boundary nobody can re-derive leaves the next sweep unable to scope itself.

Symbiosis: magma, architext, slop-ferret

Three tools over one derived artifact. magma parses the repository once and emits a versioned call graph; the other two consume it rather than re-deriving it.

                 ┌───────────────────────────────┐
   repository ──►│ magma: parse once             │
                 │ reachability (RTA), dead code │
                 │ test-only code, call graph    │
                 └──────┬─────────────────┬──────┘
      codemap-rows/1    │                 │   magma-code-graph/1
                        ▼                 ▼
                 ┌──────────────┐   ┌──────────────┐
                 │ slop-ferret  │   │  architext   │
                 │ audit order, │   │ architecture │
                 │ coverage     │   │ docs, C4     │
                 └──────────────┘   └──────────────┘

Viewing the sweep in Architext. After running ferret enumerate, point Architext at the sweep artifacts:

architext slop-ferret . --plan plan.json --discharge discharge.json --findings findings.json
architext serve .

Architext writes docs/architext/data/slop-ferret.json and renders the sweep coverage and findings as a "Slop Ferret" mode alongside the architecture data and Magma code graph.

The contracts are the seam and they are not interchangeable: codemap-rows/1 (row files, the only one this accepts), codemap-graph/1 (graph.json), magma-code-graph/1 (the architext emit). plan refuses a map whose contract_version it does not know, and refuses a map of a different tree by sha, so a stale map fails loud rather than seeding rows from the wrong commit.

The signal vocabulary is a reading-order hint, not a completeness signal. Measured across five real repositories on 2026-08-02: 59% label precision, 20% of production files matched, and 0-of-6 recall on the files that actually produced findings, including the one this tool exists because of. It guesses semantics from names the target's authors chose, so it works when they happen to have used one of its words and not otherwise.

What makes that safe is not the vocabulary's quality. It is that a file no signal reaches is reported as unread, never as clean. The ranking can be wrong without the report becoming wrong.

It is part of the lexicon (skill/references/ai-slop-lexicon.md), not the binary. The tables there define what a class is, the signals define where it tends to live, and one version: now covers both. So it iterates from usage without a binary release: add a word after a sweep that missed something, reinstall the skill, done. Extend per-repo with a .slop-h-signals file in the target, same reason: regex format. It is expected to improve by accumulation, and the tier split it feeds is pinned by a committed fixture so a change to it is a deliberate re-measurement rather than a silent drift.

Where consequence ranking is going. Into magma, which holds the call graph and the types: "does this file reach os/exec, net/http, os.OpenFile, crypto/*" is a graph query over imports and a real signal. No vocabulary of names will ever be one.

See docs/architecture/ for C4 diagrams and the dataflow walkthrough.

Development

just            # list recipes
just ci         # full local validation, mirroring the GitHub Actions checks
just test       # go test ./... -race
just cover      # coverage + the 80% check
just doctor     # is the deployed skill in sync with this checkout?

Requires Go 1.26 and just; golangci-lint for just lint.

Correctness
  • Coverage is checked at 80% in CI and in just cover.
  • The checkout's skill tree must deploy cleanly in CI. A deployed skill missing its lexicon produces a sweep with no vocabulary, which is indistinguishable from a real one and is not one.
  • Stale prose fails the build. TestNoStaleCommandNamesOrRemovedFeatureClaims scans every tracked file for command names that no longer exist and claims about removed features. Prose describing behaviour the code lacks is this tool's own subject, and it shipped here four times in one day because each manual sweep covered fewer places than the last. When it was first written it found seven more instances, in files a by-hand pass had just been declared clean.
  • The release workflow parses --version positionally, so both field offsets are pinned by a test. Reword that line and the tag check silently starts comparing the wrong token, which is how a release stops being verified without anything going red.
  • Constants in internal/gate (signal anchoring, the tier split, the defer floor) were each measured against a real repository; the measurements live in comments beside the tests that pin them, because a refactor is the easiest place to lose one.

Releasing

Tags exist so that users who want to pin can. Pushing a semver tag re-runs the CI checks, verifies the tag matches the binary version, checks the skill stamp is date-style and was bumped if skill/ changed, cross-compiles every target, and publishes a GitHub Release with checksummed archives, including the skill tree as its own artifact.

Release checklist
  1. just ci green locally.
  2. Bump binVersion in main.go to the version being released.
  3. just release-dry vX.Y.Z: confirm the archives build.
  4. Land on main; run the ABORT go/no-go review.
  5. git tag vX.Y.Z && git push origin vX.Y.Z.
  6. Confirm the Release workflow published assets and checksums.

Licence

MIT -- Copyright (c) 2026 Jonathan Machen

Directories

Path Synopsis
cmd
ferret command
Command ferret is the tool half of the slop-ferret method.
Command ferret is the tool half of the slop-ferret method.
internal
gate
Package gate is the coded seam between the magma code map and a slop sweep.
Package gate is the coded seam between the magma code map and a slop sweep.
install
Package install deploys the slop-ferret skill from this binary into ~/.claude, and reports drift between the two.
Package install deploys the slop-ferret skill from this binary into ~/.claude, and reports drift between the two.
report
Package report renders a sweep report to a self-contained HTML file.
Package report renders a sweep report to a self-contained HTML file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL