zig
Zig Development Skill
Zig is a systems programming language emphasizing explicit memory management, compile-time evaluation, and C interoperability. This skill enables effective Zig development by encoding patterns that LLMs commonly get wrong.
Core Philosophy
Zig's design principles that must inform all code generation:
- No hidden control flow - No operator overloading, no hidden allocations
- No hidden memory allocations - Allocators are explicit parameters
- Explicit is better than implicit - Side effects are visible at call sites
- Errors are values - Error unions, not exceptions
- Comptime over runtime - Move work to compile time when possible
Toolchain Management
Version Strategy
- Use
master(nightly) for latest features until Zig 1.0 - ZLS must match Zig version exactly (nightly↔nightly, tagged↔tagged)
- ZVM's
--zlsflag keeps them in sync automatically
Common Operations
# First-time setup
zvm i master --zls
# Update to latest nightly
zvm i master --zls -f
# Switch versions
zvm use 0.13.0
# Check health
/zig-doctor
Auto-Checks (Before Any Zig Task)
When working in a Zig project, automatically verify:
zig versionsucceeds- ZLS responds (if editing in Zed)
- build.zig exists and parses
If any fail, run /zig-doctor before proceeding.
Quick Reference
Project Structure
project/
├── build.zig # Build configuration (Zig code)
├── build.zig.zon # Package manifest (declarative)
├── src/
│ ├── main.zig # Application entry point
│ ├── lib.zig # Library root (if applicable)
│ └── module/ # Submodules
└── test/ # Integration tests (unit tests in src/)
Allocator Selection Decision Tree
Is this a short-lived operation with bounded size?
├─ Yes: ArenaAllocator (bulk free, fast alloc)
├─ No: Is this for debugging/development?
│ ├─ Yes: GeneralPurposeAllocator (leak detection, use-after-free detection)
│ └─ No: Is memory size known at compile time?
│ ├─ Yes: FixedBufferAllocator (zero heap, embedded-friendly)
│ └─ No: Is this performance-critical production code?
│ ├─ Yes: c_allocator or page_allocator (system allocator)
│ └─ No: GeneralPurposeAllocator with safety checks
Error Handling Patterns
// Returning errors - use error union
fn riskyOperation(allocator: Allocator) !Result {
const data = try allocator.alloc(u8, size); // propagate error
errdefer allocator.free(data); // cleanup on error
return processData(data) catch |err| {
log.err("Processing failed: {}", .{err});
return error.ProcessingFailed;
};
}
// Optional values - use ?T, not sentinel
fn findItem(items: []const Item, key: u32) ?*const Item {
for (items) |*item| {
if (item.key == key) return item;
}
return null;
}
Comptime Fundamentals
// Type-level programming
fn GenericList(comptime T: type) type {
return struct {
items: []T,
allocator: Allocator,
const Self = @This();
pub fn init(allocator: Allocator) Self {
return .{ .items = &.{}, .allocator = allocator };
}
};
}
// Compile-time string processing
fn comptimeHash(comptime str: []const u8) u32 {
comptime {
var hash: u32 = 0;
for (str) |c| hash = hash *% 31 +% c;
return hash;
}
}
Common Anti-Patterns to Avoid
Memory Management
❌ Wrong: Allocating without considering ownership
fn badPattern() []u8 {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
return gpa.allocator().alloc(u8, 100) catch unreachable;
// gpa goes out of scope, allocator invalidated!
}
✅ Correct: Allocator passed as parameter
fn goodPattern(allocator: Allocator) ![]u8 {
return allocator.alloc(u8, 100);
}
Error Handling
❌ Wrong: Using catch unreachable for recoverable errors
const file = std.fs.cwd().openFile(path, .{}) catch unreachable;
✅ Correct: Propagate or handle explicitly
const file = std.fs.cwd().openFile(path, .{}) catch |err| {
return switch (err) {
error.FileNotFound => error.ConfigMissing,
else => err,
};
};
Comptime
❌ Wrong: Runtime operations in comptime context
fn badComptime(runtime_val: usize) type {
// runtime_val is not comptime-known!
return [runtime_val]u8;
}
✅ Correct: Comptime parameter or inline
fn goodComptime(comptime size: usize) type {
return [size]u8;
}
// Or use slices for runtime-sized arrays
fn runtimeSized(allocator: Allocator, size: usize) ![]u8 {
return allocator.alloc(u8, size);
}
Resources
Detailed guidance available in reference files:
Core Concepts
- references/allocators.md: Deep dive on allocator patterns, arena strategies, custom allocators
- references/comptime.md: Type-level programming, @typeInfo, @Type, comptime algorithms
- references/build-system.md: build.zig mastery, cross-compilation, C integration
- references/error-handling.md: Error sets, errdefer, error traces, panic handling
- references/c-interop.md: translate-c, C types, calling conventions, building C code
- references/testing.md: Test blocks, expect, fuzz testing, test allocator
Toolchain & Editor
- references/zvm.md: ZVM installation, version management, troubleshooting
- references/zls.md: ZLS configuration, editor integration, diagnostics
- references/zed-integration.md: Zed-specific setup for ZVM-managed ZLS
Templates
Project scaffolding for common patterns:
- templates/cli-app - Command-line application with argument parsing, GPA leak detection, proper error handling
- templates/library - Reusable library with tests and documentation structure
Copy and customize for new projects:
cp -r templates/cli-app my-new-app
cd my-new-app
# Edit build.zig to rename "myapp" to your project name
zig build run
MCP Server Integration
When the zig-mcp MCP server is available, use these tools:
Build Tools
zig_build- Runzig buildwith optional target/step, returns structured errors with file/line/columnzig_test- Runzig build test, returns pass/fail/skip counts and any compile errorszig_check- Fast syntax/type checking without full build (uses ast-check for single files)zig_fmt- Format code or check formatting, returns list of affected files
Project Tools
zig_version- Check if Zig is installed, get version with parsed componentszig_init- Initialize a new Zig project with standard structurezig_fetch- Add dependency to build.zig.zon usingzig fetch --savezig_translate_c- Convert C headers to Zig declarations
Toolchain Tools (ZVM/ZLS)
zvm_install- Install Zig version with optional matching ZLSzvm_use- Switch active Zig versionzvm_list- List installed versions and show activezls_status- Check ZLS installation and version compatibility
Workflow Integration
For multi-step development workflows, see:
- TDD Loop:
workflows/tdd-loop.md- Red-green-refactor with zig test - C Wrapper:
workflows/c-wrapper.md- Systematic C library wrapping