skills/zig-best-practices/SKILL.md
Use when reading or writing Zig files (.zig, build.zig, build.zig.zon).
npx skillsauth add awfixers-stuff/opencode-config zig-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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:
const RequestState = union(enum) {
idle,
loading,
success: []const u8,
failure: anyerror,
};
Explicit error sets — documents exactly what can fail; anyerror hides failure modes:
const ParseError = error{ InvalidSyntax, UnexpectedToken, EndOfInput };
fn parse(input: []const u8) ParseError!Ast { ... }
Distinct types for domain IDs — compiler prevents mixing up different ID types:
const UserId = enum(u64) { _ };
const OrderId = enum(u64) { _ };
Comptime validation — catch invalid configurations at compile time, not runtime:
fn 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.fn 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:
zigdoc 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:
ziglint # lint current directory
ziglint --ignore Z001 # suppress specific rule
development
Use when starting dev servers, watchers, tilt, or any process expected to outlive the conversation. Provides zmx session management patterns for long-lived processes.
development
Zig testing skill for writing and running tests. Use when using zig build test, writing comptime tests, using test filters, working with test allocators to detect leaks, or using Zig's built-in fuzz testing (0.14+). Activates on queries about Zig tests, zig test, zig build test, comptime testing, test allocators, Zig fuzz testing, or detecting memory leaks in Zig tests.
development
Zig debugging skill. Use when debugging Zig programs with GDB or LLDB, interpreting Zig runtime panics, using std.debug.print for tracing, configuring debug builds, or debugging Zig programs in VS Code. Activates on queries about debugging Zig, Zig panics, zig gdb, zig lldb, std.debug.print, Zig stack traces, or Zig error return traces.
tools
Zig cross-compilation skill. Use when cross-compiling Zig programs to different targets, using Zig's built-in cross-compilation for embedded, WASM, Windows, ARM, or using zig cc to cross-compile C code without a system cross-toolchain. Activates on queries about Zig cross-compilation, zig target triples, zig cc cross-compile, Zig embedded targets, or Zig WASM.