Install
mkdir -p .claude/skills/zig && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16532" && unzip -o skill.zip -d .claude/skills/zig && rm skill.zipInstalls to .claude/skills/zig
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Up-to-date Zig programming language patterns for version 0.16.0. Use when writing, reviewing, or debugging Zig code, working with build.zig and build.zig.zon files, or using comptime metaprogramming. Critical for avoiding outdated patterns from training data - especially std.net→std.Io.net (requires Io instance), std.time timestamps removed (use clock_gettime), std.Thread.Mutex/Condition/sleep removed (use pthreads), std.crypto.random removed, build system APIs (root_module, Compile methods→Module methods), I/O APIs (buffered writer pattern), container initialization (.empty/.init), allocator selection (DebugAllocator), ArrayList now unmanaged by default, @typeInfo lowercase fields (.@"struct" not .Struct), and removed language features (async/await, usingnamespace).Key capabilities
- →Enforce type-first development by defining types and signatures before implementation
- →Prevent invalid states at compile time using tagged unions and explicit error sets
- →Structure modules with related code together for idiomatic Zig
- →Manage memory ownership by passing allocators explicitly and using `defer`
- →Migrate from `usingnamespace` to explicit re-exports
- →Adapt networking code from `std.net` to `std.Io.net` with `Io` instances
How it works
The skill provides guidelines and migration notes for Zig 0.16.0, detailing changes in language features, standard library modules, and best practices. It helps adapt existing code to the current version and write new code following modern patterns.
Inputs & outputs
When to use zig
- →Write modern Zig code
- →Debug Zig compilation issues
- →Follow Zig 0.16.0 build conventions
About this skill
Zig Language Reference (v0.17.0-dev)
Zig evolves rapidly. Training data contains outdated patterns that cause compilation errors. This skill documents breaking changes and correct modern patterns.
Version coverage: 0.17.0-dev (current master) — every 0.16.0 stable pattern below still holds, with migration notes from 0.15.x and 0.14.x and the 0.17 deltas in the section directly below.
Design Principles
Type-First Development
Define types and function signatures before implementation. Let the compiler guide completeness:
- Define data structures (structs, unions, error sets)
- Define function signatures (parameters, return types, error unions)
- Implement to satisfy types
- Validate at compile-time
Make Illegal States Unrepresentable
Use Zig's type system to prevent invalid states at compile time:
- Tagged unions over structs with optional fields — prevent impossible state combinations
- Explicit error sets over
anyerror— document exactly which failures can occur - Distinct types via
enum(u64) { _ }— prevent mixing up IDs (user_id vs order_id) - Comptime validation with
@compileError()— catch invalid configurations at build time
Module Structure
Larger cohesive files are idiomatic in Zig. Keep related code together — tests alongside implementation, comptime generics at file scope, visibility controlled by pub. Split files only for genuinely separate concerns. The std library demonstrates this with files like std/mem.zig containing thousands of cohesive lines.
Memory Ownership
- Pass allocators explicitly — never use global state for allocation
- Use
deferimmediately after acquiring a resource — cleanup next to acquisition - Name allocators by contract:
gpa(caller must free),arena(bulk-free at boundary),scratch(never escapes) - Prefer
constovervar— immutability signals intent and enables optimizations - Prefer slices over raw pointers — bounds safety
Critical: 0.17.0-dev changes (in progress)
Status: 0.17.0 is unreleased as of mid-2026 — master/-dev only, no official release notes yet (0.17.0/release-notes.html 404s). The only migration source is the devlog. Every 0.16.0 pattern in the rest of this skill still applies — the items below are the additional deltas, verified against 0.17.0-dev.1158. Pin a dev build in build.zig.zon (.minimum_zig_version = "0.17.0-dev.NNN+hash"); anyzig fetches it.
Unchanged from 0.16 (verified present in 0.17-dev.956): std.Io.net, std.Io.Threaded, std.ArrayList (unmanaged default), std.debug.lockStderr, and the time/thread/crypto shims — all 0.16 sections below still hold.
b.args REMOVED → run_cmd.addPassthruArgs()
The one change nearly every project needs. build.zig no longer observes CLI args (they now bypass build-script recompilation):
// WRONG (0.17) — error: no field named 'args' in struct 'Build'
if (b.args) |args| run_cmd.addArgs(args);
// CORRECT (0.17)
run_cmd.addPassthruArgs(); // forwards `zig build run -- a b c` to the spawned process
Build system reworked: configurer / maker split
build.zig is now compiled in debug mode into a "configurer" that serializes the build graph to a binary file; a separately-cached "maker" executes it in release mode. Net effect: zig build invocation ~90% faster (zig build --help ~150ms → ~14ms) and changing build args no longer rebuilds build.zig. Mostly transparent — but it's why b.args had to go.
std.gpu → std.spirv
GPU/shader namespace renamed (std/gpu.zig is gone, std/spirv.zig replaces it). std.gpu.executionMode() removed — execution modes now ride on the calling convention, and @SpirvType (new builtin) expresses samplers/images/runtime-arrays:
// SPIR-V entry points carry execution mode in the calling-convention payload (0.17)
export fn comp() callconv(.{ .spirv_kernel = .{ .x = 8, .y = 8, .z = 1 } }) void {}
// also: .spirv_vertex / .spirv_fragment / .spirv_task / .spirv_mesh
@bitCast semantics redesign — logical bit layout (proposal #19755)
@bitCast now reinterprets a type's logical bits, not its in-memory bytes — so it is endian-agnostic (aggregates behave as little-endian on every target). Newly enables casts like [2]u3 → @Vector(3, u2); now allowed on enums; now disallowed on vectors-of-pointers. Code that relied on big-endian in-memory @bitCast of arrays/structs changes behavior.
Package layout: zig-pkg/ + --fork
Fetched dependencies now land in a visible zig-pkg/ at project root (previously hidden in the global cache) — add it to .gitignore. New zig build --fork=<path> temporarily overrides a dependency without editing build.zig.zon.
std.Io.Evented (experimental)
Event-driven Io backends added — io_uring (Linux) and Grand Central Dispatch (macOS) — alongside std.Io.Threaded. Still experimental.
Critical: Removed Features (0.15.x)
usingnamespace - REMOVED
// WRONG - compile error
pub usingnamespace @import("other.zig");
// CORRECT - explicit re-export
const other = @import("other.zig");
pub const foo = other.foo;
async/await - REMOVED
Keywords removed from language. Async I/O support is planned for future releases.
std.BoundedArray - REMOVED
Use std.ArrayList with initBuffer:
var buffer: [8]i32 = undefined;
var stack = std.ArrayList(i32).initBuffer(&buffer);
std.RingBuffer, std.fifo.LinearFifo - REMOVED
Use std.Io.Reader/std.Io.Writer ring buffers instead.
std.io.SeekableStream, std.io.BitReader, std.io.BitWriter - REMOVED
std.fmt.Formatter - REMOVED
Replaced by std.fmt.Alt.
Undefined Behavior Restrictions (0.15.x)
Arithmetic on undefined is now illegal. Only operators that can never trigger Illegal Behavior permit undefined as operand.
// WRONG - compile error in 0.15.x
var n: usize = undefined;
while (condition) : (n += 1) {} // ERROR: use of undefined value
// CORRECT - explicit initialization required
var n: usize = 0;
while (condition) : (n += 1) {}
// OK - space reservation (no arithmetic)
var buffer: [256]u8 = undefined;
Critical: Networking Removed — std.net → std.Io.net (0.16)
std.net is completely removed in 0.16. Replaced by std.Io.net, which requires an Io instance.
Accept Loop
// WRONG (0.15) — std.net removed
const addr = std.net.Address.parseIp4(host, port) catch unreachable;
var server = addr.listen(.{ .reuse_address = true }) catch unreachable;
const conn = server.accept() catch continue;
defer conn.stream.close();
// CORRECT (0.16) — std.Io.net with Io instance
const addr = try std.Io.net.IpAddress.parse(host, port);
var server = try addr.listen(io, .{ .reuse_address = true });
const stream = try server.accept(); // returns Stream directly, no .stream wrapper
defer stream.close(io); // close() now takes io
Io Runtime Setup
// Create Io instance at startup, thread it through your program
var threaded = std.Io.Threaded.init(std.heap.c_allocator);
var io: std.Io = threaded.io();
Stream Changes
// stream.handle → stream.socket.handle
std.posix.setsockopt(stream.socket.handle, ...);
// Io.net.Stream has NO .read() or .writeAll() — use raw C calls for blocking I/O:
extern "c" fn write(fd: c_int, buf: [*]const u8, n: usize) isize;
fn writeAll(stream: std.Io.net.Stream, data: []const u8) !void {
var rem = data;
while (rem.len > 0) {
const n = write(stream.socket.handle, rem.ptr, rem.len);
if (n <= 0) return error.BrokenPipe;
rem = rem[@intCast(n)..];
}
}
// std.posix.read() still works for reading
Removed Convenience Functions
// connectUnixSocket, tcpConnectToHost — removed, use C externs:
extern "c" fn socket(domain: c_int, typ: c_int, proto: c_int) c_int;
extern "c" fn connect(fd: c_int, addr: *const anyopaque, len: u32) c_int;
// IMPORTANT: don't name local variables "socket" or "connect" — shadows extern
// std.net.has_unix_sockets → std.Io.net.has_unix_sockets
// std.posix.close → std.c.close (posix.close removed)
// std.posix.write/connect/socket — removed, use std.c.* or extern "c"
See std.net reference for complete networking documentation.
Critical: Time APIs Removed (0.16)
std.time.timestamp(), milliTimestamp(), microTimestamp(), nanoTimestamp() are removed. Use std.c.clock_gettime:
// WRONG (0.16) — removed
const secs = std.time.timestamp();
const ms = std.time.milliTimestamp();
// CORRECT — clock_gettime replacement
fn timestampSec() i64 {
var ts: std.c.timespec = undefined;
_ = std.c.clock_gettime(.REALTIME, &ts);
return ts.sec;
}
fn milliTimestamp() i64 {
var ts: std.c.timespec = undefined;
_ = std.c.clock_gettime(.REALTIME, &ts);
return @as(i64, ts.sec) * 1000 + @divTrunc(@as(i64, ts.nsec), 1_000_000);
}
Note: ts.nsec is signed — use @divTrunc, not / (0.16 enforces this for signed division).
std.time.ns_per_s, Instant, Timer — still present.
Critical: Thread Primitives Removed (0.16)
std.Thread.Mutex, std.Thread.Condition, std.Thread.sleep are removed. The 0.16 replacements (std.Io.Mutex/std.Io.Condition) require an Io instance. For library code without Io, use POSIX shims:
// WRONG (0.16)
var mutex: std.Thread.Mutex = .{};
mutex.lock();
// CORRECT — pthread shim (works without Io)
const PthreadMutex = struct {
inner: std.c.pthread_mutex_t = std.c.PTHREAD_MUTEX_INITIALIZER,
pub fn lock(m: *@This()) void { _ = std.c.pthread_mutex_lock(&m.inner); }
pub fn unlock(m: *@This()) void { _ = std.c.pthread_mutex_unlock(&m.inner); }
pub fn tryLock(m: *@This()) bool {
return @intFromEnum(std.c.pthread_mutex_trylock(&m.inner)) == 0;
}
};
// std.Thread.sleep →
---
*Content truncated.*
When not to use it
- →When using `usingnamespace` keyword
- →When using `async`/`await` keywords
- →When using `std.net` for networking in Zig 0.16.0
Limitations
- →`usingnamespace` keyword is removed
- →`async`/`await` keywords are removed
- →`std.net` module is completely removed and replaced by `std.Io.net`
How it compares
This skill specifically addresses breaking changes and modern patterns in Zig 0.16.0, providing direct migration paths for deprecated features, unlike general Zig documentation.
Compared to similar skills
zig side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| zig (this skill) | 0 | 4mo | Review | Advanced |
| deepwiki-rs | 25 | 9mo | Review | Intermediate |
| arm-cortex-expert | 29 | 4mo | No flags | Advanced |
| port-c-module | 2 | 2mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
deepwiki-rs
sopaco
AI-powered Rust documentation generation engine for comprehensive codebase analysis, C4 architecture diagrams, and automated technical documentation. Use when Claude needs to analyze source code, understand software architecture, generate technical specs, or create professional documentation from any programming language.
arm-cortex-expert
sickn33
Senior embedded software engineer specializing in firmware and driver development for ARM Cortex-M microcontrollers (Teensy, STM32, nRF52, SAMD). Decades of experience writing reliable, optimized, and maintainable embedded code with deep expertise in memory barriers, DMA/cache coherency, interrupt-driven I/O, and peripheral drivers.
port-c-module
RediSearch
Guide for porting a C module to Rust
compiler-development
gmh5225
Expertise in compiler development using LLVM infrastructure including frontend design, IR generation, optimization passes, and code generation. Use this skill when building custom programming languages, implementing DSL compilers, or working on compiler internals.
domain-web
actionbook
Use when building web services. Keywords: web server, HTTP, REST API, GraphQL, WebSocket, axum, actix, warp, rocket, tower, hyper, reqwest, middleware, router, handler, extractor, state management, authentication, authorization, JWT, session, cookie, CORS, rate limiting, web 开发, HTTP 服务, API 设计, 中间件, 路由
rust-symbol-analyzer
actionbook
Analyze Rust project structure using LSP symbols. Triggers on: /symbols, project structure, list structs, list traits, list functions, 符号分析, 项目结构, 列出所有, 有哪些struct