agent-environment-retr…
Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.
Use when planning an end-to-end fuzzing program for a project: engine and target selection, corpus management, and CI or nightly wiring. Not for harness design: use fuzz-harness-writing. Not for engine operation or triage: use libfuzzer. Not for sanitizer flag reference: use
$ npx -y skills add OutlineDriven/odin-claude-plugin --skill fuzzing --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/fuzzingContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when planning an end-to-end fuzzing program for a project: engine and target selection, corpus management, and CI or nightly wiring. Not for harness design: use fuzz-harness-writing. Not for engine operation or triage: use libfuzzer. Not for sanitizer flag reference: use
name: fuzzing description: 'Use when planning an end-to-end fuzzing program for a project: engine and target selection, corpus management, and CI or nightly wiring. Not for harness design: use fuzz-harness-writing. Not for engine operation or triage: use libfuzzer. Not for sanitizer flag reference: use sanitizers.'
| Field | Bound contract | |---|---| | Trigger | Coverage-guided fuzz testing for a parser, deserializer, codec, or API boundary: harness writing, libFuzzer or AFL++ setup, corpus management, crash reproduction, or CI runs. | | Authority | Reversible local. Writes are limited to fuzz binaries, corpora, dictionaries, findings, and logs under the project tree; rollback is deleting those directories. No remote mutation. | | Side effect | Built fuzz targets, corpus directories, crash artifacts, and coverage measurements. | | Done | A fuzz target runs against a seeded corpus, the crash or clean verdict is reproduced on demand, and the CI or nightly plan is written down. |
1. Target code (required): the library or entry point to fuzz, ideally a parse or I/O boundary. 2. Seeds (required when they exist): known-good inputs from tests or real traffic. 3. Toolchain (required): Clang for libFuzzer; AFL++ installed for fork-mode fuzzing. Grounded channels: Clang 23.1.0, AFL++ v5.03c (AGPL 3.0+ since v5.00c, mixed licensing in the repo). 4. Time budget (optional): seconds for CI regression runs, hours for nightly.
1. Write the target as a function of arbitrary bytes. The harness owns every guarantee:
// fuzz_parser.c
#include <stdint.h>
#include <stddef.h>
#include "myparser.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
MyParser *p = parser_create();
if (p) {
parser_feed(p, (const char *)data, size);
parser_destroy(p);
}
return 0;
}Rules: return 0 for uninteresting input instead of exiting; never call `abort` or `exit`; never read or write outside `[data, data + size)`; keep no state between calls; stay fast, since the fuzzer calls it millions of times. Done when: the harness passes a review against each rule. 2. Build with libFuzzer and the sanitizer set. `-fsanitize=fuzzer` links libFuzzer and supplies `main`, so the target must not define one:
clang -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parserDone when: the binary links without a duplicate `main` and runs `-help=1` cleanly. 3. Seed and run:
mkdir -p corpus cp tests/inputs/* corpus/ # real seeds sharply cut time to coverage ./fuzz_parser corpus/ -max_len=65536 -timeout=10 ./fuzz_parser corpus/ -max_total_time=3600 ./fuzz_parser corpus/ -jobs=4 -workers=4
Defaults worth knowing: `-max_len` 4096 when unset, `-timeout` 1200 seconds, `-rss_limit_mb` 2048, `-error_exitcode` 77, `-len_control` 100. Workers default to half the core count when unset. Done when: the run starts consuming the corpus and reporting new coverage. 4. Reproduce and minimize every finding. Artifacts land as `crash-<hash>`, `oom-<hash>`, or `timeout-<hash>` in the artifact prefix directory:
./fuzz_parser crash-abc123 # reproduce ./fuzz_parser -minimize_crash=1 -max_total_time=60 crash-abc123
Re-run the minimized case under gdb (`gdb --args ./fuzz_parser crash-min`) to name the faulting frame. Done when: one small input reproduces the bug deterministically. 5. Add AFL++ where process-level isolation or non-library targets are needed:
afl-clang-fast -g -O1 -o prog_afl main.c myparser.c afl-fuzz -i afl-input -o afl-output -- ./prog_afl @@ # @@ = input file path afl-fuzz -i afl-input -o afl-output -- ./prog_afl # stdin target: drop @@
Persistent mode avoids a fork per input and raises throughput for library targets; `__AFL_LOOP(1000)` bounds each iteration batch. Scale out with `-M main` plus one `-S name` instance per spare core, and read status with `afl-whatsup afl-output`. Done when: at least one AFL++ instance reports stable cycles with new paths. 6. Manage the corpus as an asset. Merge runs to the coverage-unique subset, and keep the corpus in version control or CI cache:
./fuzz_parser -merge=1 corpus_min/ corpus/ run1/ run2/ afl-cmin -i afl-output/default/queue -o corpus_min -- ./prog_afl @@ ./fuzz_parser corpus/ -runs=0 -print_coverage=1 # coverage of the corpus
Done when: one minimized corpus exists and reproduces the union of coverage. 7. Guide mutation with a dictionary when the format has tokens:
# parser.dict kw1="<" kw2=">" null_byte="\x00" magic1="\x89PNG"
./fuzz_parser corpus/ -dict=parser.dict afl-fuzz -i corpus/ -o out/ -x parser.dict -- ./prog_afl @@
For structured formats that checksum or length-prefix, implement `LLVMFuzzerCustomMutator` and repair the invariant after `LLVMFuzzerMutate`, or the fuzzer never passes the header. Done when: deep paths are reached without human-crafted inputs. 8. Wire CI as a fixed-time regression, not an open-ended run:
- name: Build fuzz target
run: |
clang -fsanitize=fuzzer,address,undefined -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
- name: Fuzz regression (60 seconds)
run: |
./fuzz_parser corpus/ -max_total_time=60 -error_exitcode=1 \
-artifact_prefix=artifacts/
- name: Reproduce known crashes
run: |
for f in known_crashes/*; do ./fuzz_parser "$f" || exit 1; doneLonger campaigns go to scheduled jobs with `-max_total_time=3600` or to OSS-Fuzz infrastructure. Done when: a pull request cannot merge with a target that regresses. 9. Add Python targets with Atheris, and Zig targets through the built-in fuzzer (Zig 0.13 and later):
import atheris, sys
with atheris.instrument_imports():
import myparser
def TestOneInput(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
try:
myparser.parse(fdp.ConsumeString(sys.maxsizeFormerly the ODIN Claude Plugin. The repository URL is unchanged. Outline-Driven Development, nicknamed ODIN, is a highly opinionated code-agent skill library: principles-first engineering, surgical editing, and workflow automation, published as installable
Repo: OutlineDriven/odin-claude-plugin
Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.
Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential,…
Use when a human explicitly asks for a full repository agent-compatibility pass returning a scored report with prioritized fixes. Not for tasks that require…
Use when setting up a project, auditing agent command permissions, or asking which read-only bash commands and domains to allow. Not for remote, credential,…
Use when asked to build or review a CLI intended for coding agents and return flag-driven, pipeline-safe, idempotent design advice. Not for running or…
Use when the user asks to make the skills framework work in a new harness, IDE, or CLI. Not for remote, credential, publish, deploy, or irreversible changes.