add-fuzz-target
Use when adding a new `Fuzz*` function in remindb — symptoms include "fuzz this function", "find panics in X", "add property-based testing", "harden against malformed input", or any task that creates a `FuzzXxx(f *testing.F)` in a `*_test.go`. Also use when extending an existing fuzz target's seed corpus with new shape coverage.
pinned to #977b31cupdated 2 weeks ago
Ask your AI client: “install skills/add-fuzz-target”.
Requires the metahub MCP server installed in your client. Set up MCP.
mh install skills/add-fuzz-targetmetahub onboarded this repo on the author's behalf.
If you own github.com/radimsem/remindb on GitHub, claim the listing to take over publishing. Your claim preserves the existing eval history and badges; only the curator label is replaced with verified-publisher on your next publish.
Stars
121
Last commit
2 weeks ago
Latest release
published
- #agent-memory
- #ai-agents
- #ast
- #claude-code
- #cli
- #codex
- #developer-tools
- #fts5
- #gemini-cli
- #golang
- #knowledge-base
- #llm-tool
- #mcp
- #mcp-server
- #model-context-protocol
- #openclaw
- #opencode
- #sqlite
- #token-efficiency
About this skill
Pulled from SKILL.md at publish time.
remindb fuzzes parser, query, transformer, compiler, and temperature code. The fuzz harness is whatever Go's `testing.F` gives you — there's no project-specific framework — but the *seed-corpus discipline* is project convention worth getting right. `scripts/fuzz.sh` auto-discovers any `Fuzz*` function via `go test -list='^Fuzz'`, so naming your function `FuzzXxx` is the only registration needed.
Evaluation report
WarningsAutomated checks the publisher passed at publish time — structure, docs, safety, and whether the artifact behaves as claimed.977b31c· 2 weeks ago
Kind-specific
31Skill: SKILL.md present
found at .claude/skills/add-fuzz-target/SKILL.md · frontmatter source: SKILL.md
Skill: body content present
921 words · 6,472 chars · 8 sections · 4 code blocks
Skill: triggers declaredwarn
No `trigger` phrases in SKILL.md frontmatter
Add `trigger:` lines so Claude knows when to activate this skill — e.g. `when building MCP servers` or `for diagram creation`.
Skill: allowed-tools scope
no allowed-tools restriction (Claude may use anything)
Release history
1- releasecurrent977b31cwarn2 weeks ago
Contents
Add a fuzz target
remindb fuzzes parser, query, transformer, compiler, and temperature code. The fuzz harness is whatever Go's testing.F gives you — there's no project-specific framework — but the seed-corpus discipline is project convention worth getting right. scripts/fuzz.sh auto-discovers any Fuzz* function via go test -list='^Fuzz', so naming your function FuzzXxx is the only registration needed.
Where it lands
Two files at most.
| File | What changes |
|---|---|
pkg/<package>/fuzz_test.go | New file or extend existing — FuzzXxx(f *testing.F) |
pkg/<package>/testdata/fuzz/<FuzzXxx>/ | Auto-managed by Go fuzz; commit any minimization corpus crashes find here |
If pkg/<package>/fuzz_test.go already exists (it does for parser, query, transformer, compiler, temperature), append; don't make a second file.
The function shape
Mirror pkg/parser/fuzz_test.go and pkg/temperature/fuzz_test.go. The shape is uniform:
func FuzzExample(f *testing.F) {
// Seed corpus — see "Seed selection" below.
f.Add(input1, input2)
// ... more f.Add lines, each one shape ...
f.Fuzz(func(t *testing.T, input1 T1, input2 T2) {
result, err := YourFunc(input1, input2)
// Invariants — see "Invariant assertions" below.
if err != nil {
return // errors are fine; panics are not
}
if !invariantHolds(result) {
t.Errorf("invariant violated: ...")
}
})
}
Two rules:
- Function name
FuzzXxx.scripts/fuzz.shgreps for^Fuzzingo test -listoutput. Anything else is invisible. - One target per logical surface. Don't multiplex two unrelated functions into one fuzz target — Go's fuzzer mutates the input tuple as a unit, so combined targets dilute coverage.
Seed selection — the discipline
A fuzz seed says "this is a shape worth starting from." The fuzzer mutates from there. The point isn't to enumerate all valid inputs; it's to give the mutator a head start on every category of structural variation. Aim for one seed per shape:
| Shape | Why it matters | Example |
|---|---|---|
| Happy path | Baseline — proves the harness wires up correctly | f.Add("doc.md", []byte("# Hello")) |
| Empty input | Off-by-one and bounds-check guard | f.Add("file.md", []byte{}) |
| Malformed | Decoder error path | f.Add("file.json", []byte("{unclosed")) |
| UTF-8 boundary | Mid-byte slicing, multi-byte boundary | f.Add("file.md", []byte{0xe3}) |
| Structural extreme | Deep nesting, large counts | f.Add("file.json", []byte("{\"a\":{\"b\":{\"c\":\"deep\"}}}")) |
| Numeric extreme (numeric inputs) | Inf, NaN, MaxFloat, MaxInt, negative | f.Add(math.MaxFloat64, 1.0) |
| Boundary value (parameterized) | The threshold/cap/limit value itself | f.Add(1, math.MaxInt) (budget exactly at limit) |
pkg/temperature/fuzz_test.go is the cleanest template for numeric fuzz; pkg/parser/fuzz_test.go is the template for byte-sequence fuzz. Both spend ~10 seed lines each — that's the right density.
Invariant assertions
The default invariant is must not panic. The runtime catches panics and reports them as crashes, so you don't write that one — it's free.
Beyond no-panic, write property assertions, not example-based ones. The mutator generates novel inputs you can't predict:
- Type-level invariants:
len(out) <= len(in),result >= 0,tokensUsed <= budget. - Round-trip invariants:
Decode(Encode(x)) == x. - Conditional invariants: "if input is valid UTF-8, error must be nil".
pkg/parser/fuzz_test.godoes this forErrInvalidUTF8. - Domain invariants: "result is non-NaN when both inputs are non-NaN" (see
FuzzDecayFactorandFuzzScoreinpkg/temperature/fuzz_test.go).
A common pattern: when an input could be invalid, gate the assertion on input validity:
if budget >= 0 && tok1 >= 0 && tok2 >= 0 {
if result.TokensUsed > budget {
t.Errorf("TokensUsed = %d exceeds budget %d", result.TokensUsed, budget)
}
}
This avoids spurious failures from negative-int inputs you've already documented as out-of-domain.
Running it locally
# Run all fuzz targets for 30 seconds each
scripts/fuzz.sh 30s
# Or one target for longer
go test -run='^$' -fuzz='^FuzzExample$' -fuzztime=2m ./pkg/<package>/
A new target should run for at least 30s without crashing before you commit. If a crash surfaces, the crashing seed is saved under pkg/<package>/testdata/fuzz/FuzzExample/<hash> — commit that file along with the fix so future runs replay the regression.
Quick reference
1. pkg/<package>/fuzz_test.go (FuzzXxx with seed corpus + Fuzz callback)
2. scripts/fuzz.sh 30s (must finish without crashes)
3. If a crash file appears in testdata/fuzz/: fix root cause, commit the seed
Common mistakes
- Asserting on a specific output value. The fuzzer's input is unpredictable; specific outputs can't hold. Use property assertions: bounds, types, conditional invariants.
- Returning early on
err != nilwithout checking what kind of error. If the function should return a specific sentinel for a given input class (likeErrInvalidUTF8for invalid UTF-8 in parser), assert that. Otherwise genericreturnon error is correct. - Missing the
f.Add(...)seed for the empty/zero case. The Go fuzzer mutates from seeds — without an empty seed, it may take a long time to discover the empty input naturally. - Long-running invariant checks inside the fuzz body. Each iteration runs thousands of times per second; an O(n²) assertion will throttle the fuzzer and reduce coverage. Keep invariant checks O(n) or O(1).
- Not committing crash seeds from
testdata/fuzz/. The seed file is the regression test for the bug you just fixed. Without it, the same bug can re-emerge silently. - Naming the function
FuzzTestXxxorFuzzCheck.scripts/fuzz.shgreps^Fuzzso any prefix-only-Fuzzname works, but stylistic convention here isFuzzXxxmatching the function-under-test.
Cross-references
.claude/rules/go-concise.md— error sentinel patterns, naming.claude/skills/add-parser/SKILL.md— for the special case of seedingFuzzParseByteswith a new format (you don't add a new fuzz target, you extend an existing one)scripts/fuzz.sh— the auto-discovery loop; read it once if you're curious howgo test -list='^Fuzz'finds your target
Reviews
No reviews yet. Be the first.
Related
orchestration-patterns
>
migration-patterns
>
deployment-sop
>
mh install skills/add-fuzz-target