Agent Skills: Zig Knowledge Patch

Zig changes since training cutoff (latest: 0.14.0) \u2014 labeled switch, decl literals, @branchHint, DebugAllocator, unmanaged containers, root_module build API. Load before working with Zig.

UncategorizedID: nevaberry/nevaberry-plugins/zig-knowledge-patch

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Nevaberry/nevaberry-plugins/tree/HEAD/plugins/knowledge-patch/skills/zig-knowledge-patch

Skill Files

Browse the full folder contents for zig-knowledge-patch.

Download Skill

Loading file tree…

plugins/knowledge-patch/skills/zig-knowledge-patch/SKILL.md

Skill Metadata

Name
zig-knowledge-patch
Description
Zig

Zig Knowledge Patch

Baseline: Zig through 0.12.x. Covered range: Zig 0.13.0 through 0.15.1.

Use this patch before writing or migrating Zig code in the covered range. Check the reference for the subsystem being changed; many old names were removed rather than soft-deprecated.

Reference index

| Reference | Topics | |---|---| | Language and builtins | Removed syntax, switches, literals, reflection, atomics, pointers, assembly, type-system rules | | Memory and containers | Allocators, page size, ArrayList, queues, linked lists, fixed-capacity and ring buffers | | I/O, formatting, compression, and networking | std.Io, file interfaces, formatting, flate, HTTP, TLS | | Standard library and processes | CRC, string maps, process children, progress, POSIX, ZON, renamed and removed APIs | | Build, packages, and tools | Build graph APIs, LazyPath, modules, packages, watch/fuzz workflows, CLI changes | | Targets, platform, and toolchain | Target triples, OS floors, calling conventions, C interop, backends, sanitizers, libc, SPIR-V |

Breaking language removals

Remove usingnamespace, async, and await

Zig 0.15.1 removes usingnamespace, the async and await keywords, and @frameSize. Replace namespace injection with explicit declarations. Represent an unsupported API as void/{} or a declaration that conditionally emits @compileError; replace mixins with a named zero-bit field and @fieldParentPtr. Async I/O is provided through library interfaces instead of the removed language feature.

const have_feature = true;
pub const feature = if (have_feature)
    123
else
    @compileError("feature is unavailable");

Replace removed atomics and branch annotations

@fence is gone in 0.14.0. Put the required ordering on the relevant atomic operation: for example, turn release decrement plus acquire fence into an .acq_rel decrement. Cross-variable sequential consistency requires .seq_cst on all related operations or an explicit atomic read-modify-write barrier.

@branchHint replaces @setCold. It must be the first statement of the affected conditional block or function and accepts .likely, .unlikely, .cold, .unpredictable, or .none.

if (unlikely_condition) {
    @branchHint(.unlikely);
    handleSlowPath();
}

Update reflection and export code

std.builtin.Type and Pointer.Size tags are lowercase; keyword tags are quoted, for example .int, .pointer, .one, .@"struct", and .@"enum". Opaque reflection fields became default_value_ptr and sentinel_ptr; prefer typed accessors such as StructField.defaultValue() and Pointer.sentinel().

@export takes a pointer in 0.14.0:

const value: u32 = 123;
comptime { @export(&value, .{ .name = "exported_value" }); }

Use @FieldType(Container, "field") instead of std.meta.FieldType.

Allocators and containers

Treat ArrayList as allocator-explicit

The 0.14.0 transition deprecated managed containers in favor of unmanaged forms. In 0.15.1, std.ArrayList itself is unmanaged: initialize with .empty or static storage and pass the allocator to allocating operations and deinit. Use std.array_list.Managed only when allocator-owning behavior is required.

var values: std.ArrayList(u8) = .empty;
defer values.deinit(allocator);
try values.append(allocator, 42);

The aligned managed spelling is std.array_list.AlignedManaged. Keep allocator-free calls such as appendAssumeCapacity allocator-free.

Select current allocators

std.heap.DebugAllocator(options) replaces GeneralPurposeAllocator and starts from .init. std.heap.smp_allocator is the fast process-wide allocator intended for multithreaded ReleaseFast programs.

var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
defer _ = debug_allocator.deinit();
const allocator = debug_allocator.allocator();

Allocator vtables now include remap, which may return relocated storage; resize still promises not to relocate. Alignment parameters use std.mem.Alignment, not u8.

Concrete I/O interfaces

Migrate readers and writers

Zig 0.15.1 replaces generic std.io stream types with non-generic std.Io.Reader and std.Io.Writer. Their buffers are caller-owned and live in the concrete interface. Old writers can temporarily bridge with old_writer.adaptToNewApi(&.{}).

var buffer: [1024]u8 = undefined;
var file_writer = std.fs.File.stdout().writer(&buffer);
const stdout: *std.Io.Writer = &file_writer.interface;
try stdout.print("{s}\n", .{"hello"});
try stdout.flush();

Use File.Reader and File.Writer for seeking, position tracking, file transfer, and streaming versus positional access. posix.sendfile is replaced by File.Reader.sendFile.

Make custom formatting explicit

Use {f} to invoke a value's format method and {any} to bypass it. The method now accepts only the value and *std.Io.Writer, returning std.Io.Writer.Error!void.

pub fn format(value: Value, writer: *std.Io.Writer) std.Io.Writer.Error!void {
    try writer.print("{d}", .{value.number});
}

Build-system migrations

Create artifacts from modules

addExecutable, addTest, and related APIs take root_module. Create a reusable module with b.createModule(...) rather than passing root_source_file, target, and optimize directly to each artifact.

Build APIs for header installation and removal increasingly require LazyPath. For a configured relative removal path use .{ .cwd_relative = path }.

Keep source mutation explicit

WriteFile no longer updates source-tree files. Use b.addUpdateSourceFiles() for copy or update operations whose destination belongs to the source tree.

For generated headers, assign install_artifact.emitted_h = artifact.getEmittedH() when installation needs the -femit-h output. installConfigHeader now gets its destination from include_path and no longer takes a subpath argument.

Watch, fuzz, and incremental workflows

zig build --watch keeps the runner alive and reruns only dirty steps; --debounce <ms> overrides its 50 ms debounce. In 0.15.1 it works on macOS, and --webui --time-report exposes rebuild controls and timing.

Register fuzz targets with std.testing.fuzz(context, function, .{}), then run zig build test --fuzz; --port selects the coverage UI port.

Incremental compilation is experimental and opt-in with -fincremental. It is not compatible with usingnamespace; prefer it with watch mode and a build option that skips binary emission:

zig build -Dno-bin -fincremental --watch

Frequent standard-library migrations

  • Use std.process.Child, not std.ChildProcess; collectOutput takes the allocator plus unmanaged output lists.
  • Use std.StaticStringMap(T).initComptime(kvs), not ComptimeStringMap.
  • Use std.heap.pageSize() at runtime; use page_size_min or page_size_max for comptime alignment bounds.
  • Use std.Random, std.Target.Query, and std.DoublyLinkedList; old aliases including std.rand, std.zig.CrossTarget, and std.TailQueue are removed.
  • Initialize std.posix.iovec with .base and .len.
  • Use CLICOLOR_FORCE to force colored CLI output; the local cache is .zig-cache.

Platform and backend checks

Zig 0.15.1 raises explicit supported OS floors; verify deployment targets before upgrading. Debug x86-64 builds default to the self-hosted backend except on NetBSD, OpenBSD, and Windows. Pass -fllvm or set .use_llvm = true when LLVM is required.

C undefined-behavior sanitization accepts -fsanitize-c=full or -fsanitize-c=trap; build configuration uses ?std.zig.SanitizeC, with .full and .off replacing booleans. See the platform reference for target-triple, cross-libc, calling-convention, and SPIR-V details.