Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when reading or writing Zig files (.zig, build.zig, build.zig.zon).
.claude/skills/aiskillstore-zig-best-practices/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 15% | 0% |
| case-16 | ✗→✓ | ▲ Improved | -56% | 0% |
| case-17 | ✗→✓ | ▲ Improved | -6% | 0% |
| case-10 | ✓→✓ | = Same ✓ | 18% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 112% | 0% |
Follows type-first, functional, and error handling patterns from CLAUDE.md. This skill covers Zig-specific idioms only.
Tagged unions for mutually exclusive states — prevents invalid combinations that a struct with multiple nullable fields would allow:
zigconst RequestState = union(enum) { idle, loading, success: []const u8, failure: anyerror, };
Explicit error sets — documents exactly what can fail; anyerror hides failure modes:
zigconst ParseError = error{ InvalidSyntax, UnexpectedToken, EndOfInput }; fn parse(input: []const u8) ParseError!Ast { ... }
Distinct types for domain IDs — compiler prevents mixing up different ID types:
zigconst UserId = enum(u64) { _ }; const OrderId = enum(u64) { _ };
Comptime validation — catch invalid configurations at compile time, not runtime:
zigfn Buffer(comptime size: usize) type { if (size == 0) @compileError("buffer size must be greater than 0"); return struct { data: [size]u8 = undefined, len: usize = 0 }; }
defer resource.deinit() immediately after acquisition — keeps cleanup co-located with creation.errdefer for cleanup on error paths; defer for unconditional cleanup.std.testing.allocator in tests — reports leaks with stack traces.zigfn createResource(allocator: std.mem.Allocator) !*Resource { const resource = try allocator.create(Resource); errdefer allocator.destroy(resource); // runs only on error resource.* = try initializeResource(); return resource; }
const over var; prefer slices over raw pointers.comptime T: type over anytype; explicit types produce clearer errors. Use anytype only for genuinely polymorphic cases (callbacks, std.debug.print-style).switch: include an else returning an error or unreachable for truly impossible cases.std.log.scoped(.module_name) for namespaced logging; define a module-level const log constant.zigdoc — browse std library and dependency docs:
bashzigdoc std.mem.Allocator # std lib symbol zigdoc vaxis.Window # project dependency zigdoc @init # create AGENTS.md with API patterns
ziglint — static analysis with .ziglint.zon config:
bashziglint # lint current directory ziglint --ignore Z001 # suppress specific rule
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 15,091 | 12,768 | -15% | 1 | 1 | 0% | 2,907 | 3,329 | +15% | 0 | 0 | — |
case-10 | pass→pass | 11,156 | 8,743 | -22% | 1 | 1 | 0% | 1,931 | 2,271 | +18% | 0 | 0 | — |
case-02 | pass→pass | 4,871 | 5,993 | +23% | 1 | 1 | 0% | 900 | 1,910 | +112% | 0 | 0 | — |
case-03 | pass→pass | 4,827 | 4,972 | +3% | 1 | 1 | 0% | 731 | 1,626 | +122% | 0 | 0 | — |
case-04 | pass→pass | 11,240 | 8,915 | -21% | 1 | 1 | 0% | 2,014 | 2,515 | +25% | 0 | 0 | — |
case-05 | pass→pass | 11,954 | 7,144 | -40% | 1 | 1 | 0% | 1,961 | 2,084 | +6% | 0 | 0 | — |
case-06 | pass→pass | 8,037 | 5,634 | -30% | 1 | 1 | 0% | 1,308 | 1,682 | +29% | 0 | 0 | — |
case-07 | pass→pass | 5,227 | 5,202 | -0% | 1 | 1 | 0% | 949 | 1,753 | +85% | 0 | 0 | — |
case-08 | pass→pass | 13,036 | 10,052 | -23% | 1 | 1 | 0% | 2,199 | 2,520 | +15% | 0 | 0 | — |
case-09 | pass→pass | 8,249 | 4,858 | -41% | 1 | 1 | 0% | 1,519 | 1,623 | +7% | 0 | 0 | — |
case-11 | pass→pass | 9,385 | 7,110 | -24% | 1 | 1 | 0% | 1,621 | 2,118 | +31% | 0 | 0 | — |
case-12 | pass→pass | 10,231 | 8,225 | -20% | 1 | 1 | 0% | 1,579 | 2,206 | +40% | 0 | 0 | — |
case-13 | pass→pass | 9,952 | 5,495 | -45% | 1 | 1 | 0% | 1,852 | 1,794 | -3% | 0 | 0 | — |
case-14 | pass→pass | 11,022 | 8,054 | -27% | 1 | 1 | 0% | 1,879 | 2,196 | +17% | 0 | 0 | — |
case-15 | pass→pass | 11,539 | 2,117 | -82% | 1 | 1 | 0% | 1,907 | 1,142 | -40% | 0 | 0 | — |
case-16 | fail→pass | 16,469 | 2,587 | -84% | 1 | 1 | 0% | 2,772 | 1,228 | -56% | 0 | 0 | — |
case-17 | fail→pass | 13,023 | 7,172 | -45% | 1 | 1 | 0% | 2,304 | 2,170 | -6% | 0 | 0 | — |
case-18 | pass→pass | 16,611 | 11,485 | -31% | 1 | 1 | 0% | 2,854 | 2,801 | -2% | 0 | 0 | — |
case-19 | pass→pass | 18,680 | 14,700 | -21% | 1 | 1 | 0% | 2,866 | 3,273 | +14% | 0 | 0 | — |
case-20 | pass→pass | 8,328 | 7,828 | -6% | 1 | 1 | 0% | 1,606 | 2,450 | +53% | 0 | 0 | — |
case-21 | pass→pass | 6,584 | 4,302 | -35% | 1 | 1 | 0% | 1,198 | 1,667 | +39% | 0 | 0 | — |
case-22 | pass→pass | 7,016 | 3,808 | -46% | 1 | 1 | 0% | 1,168 | 1,477 | +26% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.