hole-driven-development — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited hole-driven-development (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
REQUIRED BACKGROUND: hole-driven-development-core
Drive implementation through the compiler's typed hole diagnostics. Write holes, compile, read what the compiler tells you, fill one hole, repeat until it compiles.
Core principle: The compiler is the oracle. Every fill decision is grounded in diagnostics, not memory.
_, _name in Haskell; sorry / _ in Lean; todo!() in Rust)1. Write type signature + stub with hole(s) in the file
2. COMPILE — run the compiler
3. READ diagnostics: expected type, bindings in scope, valid hole fits
4. PICK the most constrained hole (fewest valid fits)
5. FILL exactly one hole — guided by diagnostics, not memory
- If the fill is complex, introduce sub-holes
6. VERIFY semantic correctness against previously filled holes:
- Does shared state flow correctly between this fill and prior fills?
- Are resource scopes (locks, handles, channels) consistent?
- Do error paths compose correctly?
The compiler catches type errors but not logic bugs.
7. COMPILE again — go to 3
8. When compilation succeeds (no holes remain):
REVIEW-ALL — re-read the complete implementation holistically:
- State transitions that span multiple fills
- Resource acquired in one fill, released in another
- Error paths that cross fill boundaries
- Loop invariants depending on multiple fills
Fix any systemic bug the per-hole VERIFY could not catch.
9. EXITOne hole per compile cycle. Fill one, compile, read. Do not batch-fill.
Use named holes. When introducing multiple holes:
_name (e.g., _base, _recursive) instead of bare _.sorry with a preceding comment (e.g., -- HOLE: base case then sorry), or bind with let _base := sorry.todo!("hole_name") (e.g., todo!("base_case")).Named holes make diagnostics easier to read and holes easier to track across compile cycles.
Diagnostics over memory. Even if you "know" the answer, compile first and let the diagnostics confirm or correct you. The compiler may reveal constraints you missed.
When NOT to decompose further. Some algorithms are inherently monolithic — dual-cursor walks, complex FSMs, coroutine-style loops. If the state machine's transitions are tightly coupled, keep it as one hole with internal structure via comments. The compiler catches type errors at hole boundaries but not logic bugs from split state.
Auto-detect from project structure:
| Language | Hole syntax | Compile command | Detection |
|---|---|---|---|
| Haskell | _, _name | cabal build if .cabal file exists; otherwise ghc <file> -fno-code | .cabal, .hs |
| Lean 4 | sorry, _ | lake build if lakefile.lean or lakefile.toml exists; otherwise lean <file> | lakefile.lean, lakefile.toml, .lean |
| Rust | todo!() | cargo build if Cargo.toml exists; otherwise rustc <file> | Cargo.toml, .rs |
When using nix develop, prefix commands: nix develop -c <compiler> ...
Run the loop autonomously. Stop only when:
GHC's typed hole output gives you:
Use all three. Valid fits narrow the search. Relevant bindings show what you can compose. The expected type is the constraint.
Beware misleading fits. GHC may suggest a value that type-checks but is semantically wrong (e.g., z instead of a recursive call). Cross-reference with the function's purpose.
Lean 4's sorry and _ output gives you:
sorry or _`sorry` vs `_`. sorry silences the error and allows compilation to continue — useful for incremental HDD. _ forces the elaborator to infer and report what's needed. Prefer sorry for skeleton stubs, switch to _ when you want the elaborator to narrow the type.
Rust's todo!() compiles successfully (it satisfies any return type via !), so diagnostics come from type mismatches in surrounding code, not from the hole itself. To get useful diagnostics:
()) to force a type error showing "expected X, found ()"Rust holes don't report like GHC. Since todo!() has type ! (never), it type-checks in any position. You won't get "valid hole fits." Instead, rely on the surrounding type context and intentional type mismatches to extract constraints.
If you catch yourself doing any of these: STOP. Compile. Read. Then proceed.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.