Skill: debuggerdragon311/zig-pro-maxx (version 0.1.9)

--- name: zig-pro-maxx description: > Enforces strict API compliance, memory safety, and idiomatic patterns for Zig 0.16.0 — and refuses to generate code for any earlier version. Activate whenever the user asks to write, edit, debug, or test Zig code; mentions memory allocation, SIMD, collections, formatting, file I/O, threading, comptime, C interop, cross-compilation, or low-level performance in Zig; or edits build.zig. Also activate for any Zig build system questions, error set design, tagged union patterns, or architecture of multi-file Zig projects. Created by Soumyajit Bala, an AI-automation and systems engineer. metadata: trigger: Writing zig code files, editing drafts for zig, reviewing content for Zig. author: Soumyajit Bala (https://github.com/debuggerdragon311) version: v0.1.9-beta1 --- # ZIG-PRO-MAXX — 0.16.0 ONLY, NO EXCEPTIONS You are a systems programmer locked to **Zig 0.16.0**. Every line you generate must compile on 0.16.0. If you catch yourself writing `GeneralPurposeAllocator`, `std.io` (lowercase), `async`, `ArrayList.init(allocator)`, or any other pre-0.16 API — stop and rewrite it. --- ## Load these references before you write a single line | Reference file | When to read | |---|---| | `references/code-discipline.md` | **Always follow and must** — before any function, struct, or public API or any code or any comment | | `references/zig-0_16-breaking-changes.md` | **Always** — renamed/removed APIs | | `references/std-debug.md` | Any `print`, `assert`, or `panic` | | `references/std-io.md` | Any file I/O, stdout, stderr, networking | | `references/allocators.md` | Any heap allocation | | `references/std-collections.md` | Any `ArrayList` or `HashMap` usage | | `references/std-fmt.md` | Any `bufPrint`, `allocPrint`, `parseInt`, format specifiers | | `references/build-system.md` | Any edit to `build.zig` | | `references/testing.md` | Any test block | | `references/common-mistakes.md` | **Always** — final review before output | | `references/simd.md` | Any `@Vector`, SIMD, or vectorised data operation | | `references/c-interop.md` | Any `@cImport`, `extern fn`, or FFI boundary | | `references/build-system.md` | Any edit to `build.zig` or cross-compilation | | `references/error-sets.md` | Any custom error set, tagged union, or exhaustive switch | | `references/comptime.md` | Any generic function, `@typeInfo`, or comptime interface | ## Check these examples before you write a single line (Don't mention it on users end, its for grounding with actual code for more better understanding) | Example file | When to read | |---|---| | `examples/hello_from_cli_args.zig` | **Any `args`-related code** | | `examples/sample_0_16.zig` | **Any time you want an overview of basics** | | `examples/fibo.zig` | **Any time you want to know to a teminal i/o works for fibo** | | `examples/factorial.zig` | **Any time you want to know to a teminal i/o works for factorial** | | `examples/swap_strings_of_2.zig` | **Any time you want to know to a teminal i/o works for swap of 2 strings** | | `examples/hello.zig` | **Any time you want to know to a teminal i/o works for a simple greeting program** | --- ## The API swap table — memorise this | Dead (≤ 0.15) | Alive (0.16.0) | |---|---| | `std.io.getStdOut().writer()` | `std.debug.print` (lessons) · `std.Io.File.Writer.init(file, io, &buf)` (prod) | | `std.heap.GeneralPurposeAllocator(.{}){}` | `std.heap.DebugAllocator(.{}) = .init` | | `gpa.deinit()` → `bool` | `gpa.deinit()` → `std.heap.Check` (`.ok` / `.leak`) | | `std.io.Writer` | `std.Io.Writer` (capital I) | | `std.fs.cwd().openFile(path, .{})` | `std.Io.Dir.cwd().openFile(io, path, .{})` | | `std.fs.cwd().readFileAlloc(…)` | `std.Io.Dir.cwd().readFileAlloc(io, path, gpa, .unlimited)` | | `async` / `await` | **Removed** — use `std.Io` concurrency model | | Variable shadowing | **Compile error** — use distinct names | | `@setCold` | `@branchHint(.cold)` | | `std.mem.indexOfScalar` | `std.mem.findScalar` | | `std.ArrayList(T).init(allocator)` | `var list: std.ArrayList(T) = .empty` | | `list.append(item)` | `list.append(allocator, item)` | | `list.deinit()` | `list.deinit(allocator)` | | `std.ArrayListUnmanaged` | `std.ArrayList` (they are now the same type) | | `std.heap.page_allocator` | `std.heap.page_allocator` (unchanged) | | `std.process.argsAlloc` | `init.minimal.args.iterator()` (new `main` signature) | | `std.debug.assert(false)` in release | use `unreachable` for impossible branches | | `@intToFloat` / `@floatToInt` | `@floatFromInt` / `@intFromFloat` | | `@intCast(T, x)` | `@as(T, @intCast(x))` or just `@intCast(x)` with inferred type | | std.mem.trimLeft | std.mem.trimStart | | std.mem.trimRight | std.mem.trimEnd | --- ## Non-negotiable compiler rules Violating any of these is a compile error or runtime panic — there is no "mostly right" in Zig: - **No implicit numeric coercion** — use `@intCast`, `@floatFromInt`, `@intFromFloat`, `@floatCast`, `@truncate` - **No local variable shadowing** — compile error; always use distinct names - **Exhaustive switch on enums** — every variant or an explicit `else` - **`var` that is never mutated** — compile error; use `const` - **Integer overflow in Debug/ReleaseSafe** — runtime panic; use `+%` for intentional wrapping, `+|` for saturating - **`try` on fallible functions** — errors cannot be silently discarded - **ArrayList mutations require allocator** — `append`, `appendSlice`, `insert`, `deinit`, etc. all take `allocator` as first arg in 0.16.0 --- ## Canonical patterns — copy these exactly ### Debug output (all lesson files) ```zig const std = @import("std"); const print = std.debug.print; pub fn main() void { print("value: {d}\n", .{42}); } ``` ### Heap allocation ```zig var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator(); ``` ### ArrayList (0.16.0 — unmanaged, allocator passed per call) ```zig var list: std.ArrayList(u32) = .empty; defer list.deinit(allocator); try list.append(allocator, 42); try list.appendSlice(allocator, &.{ 1, 2, 3 }); for (list.items) |item| { print("{d}\n", .{item}); } ``` ### AutoHashMap ```zig var map = std.AutoHashMap(u32, []const u8).init(allocator); defer map.deinit(); try map.put(1, "one"); if (map.get(1)) |val| print("{s}\n", .{val}); var it = map.iterator(); while (it.next()) |entry| { print("{d} → {s}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); } ``` ### StringHashMap ```zig var map = std.StringHashMap(u32).init(allocator); defer map.deinit(); try map.put("alpha", 1); const val: ?u32 = map.get("alpha"); ``` ### Format into stack buffer (prefer over allocPrint in hot paths) ```zig var buf: [64]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "item_{d}", .{id}); // out is a []u8 slice into buf — no allocator, no defer ``` ### Format into heap (when size is unknown) ```zig const out = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ dir, file }); errdefer allocator.free(out); // only on error path return out; // caller owns; errdefer does NOT run ``` ### Parse an integer from a string ```zig const n = try std.fmt.parseInt(u32, input, 10); // or auto-detect base (0b, 0o, 0x prefix): const n = try std.fmt.parseInt(u32, input, 0); ``` ### Error handling ```zig const result = try fallibleFn(); // propagate const result = fallibleFn() catch 0; // default const result = fallibleFn() catch |err| { // explicit std.debug.print("error: {s}\n", .{@errorName(err)}); return; }; ``` ### Ownership and cleanup ```zig const buf = try allocator.alloc(u8, size); errdefer allocator.free(buf); // only on error path // ... initialize buf ... return buf; // caller owns it; errdefer does NOT run ``` ### Tests ```zig test "description of what is being verified" { const allocator = std.testing.allocator; // leak-detecting try std.testing.expectEqual(@as(u32, 42), result); try std.testing.expectEqualStrings("expected", actual); } ``` --- ## Inlined critical mistakes (check every output against these) 1. **`ArrayList.append` without allocator** — `list.append(item)` is a compile error in 0.16; must be `list.append(allocator, item)`. 2. **`list.deinit()` without allocator** — same; `list.deinit(allocator)`. 3. **Returning a pointer to a stack variable** — the variable is destroyed when the function returns; always heap-allocate what outlives its scope. 4. **`@intCast` without range check** — if the value might not fit, use `std.math.cast(T, x) orelse return error.Overflow` instead. 5. **`defer` inside a loop** — defers run at end of the *enclosing block*, not at end of each iteration. Use explicit cleanup or a nested block. 6. **`errdefer` running on success** — `errdefer` only fires on error return; after `return buf` on the success path it is silent. Document this clearly. 7. **Shadowing a variable name** — compile error in 0.16; always rename. 8. **Mutable `const`** — `const x = 5; x += 1;` is a compile error. 9. **`std.io` (lowercase)** — does not exist in 0.16; it is `std.Io`. 10. **`std.heap.GeneralPurposeAllocator`** — gone; use `std.heap.DebugAllocator`. --- ## Debugging & tooling - **Quick print:** `std.debug.print("val: {any}\n", .{x})` — writes to stderr, no allocator, no flush needed. Use for lessons, quick debugging. - **Structured logging:** `std.log.info("connected {s}", .{addr})` — routed through `std.options.logFn`; respect log levels and scopes. Prefer over `debug.print` in libraries so callers can silence it. ```zig const log = std.log.scoped(.my_lib); log.warn("retrying: {s}", .{reason}); ``` - **`@panic` vs `unreachable`:** - `unreachable` — tells the compiler this path *cannot* be reached; in ReleaseFast it becomes undefined behaviour. Use only when you can *prove* the condition. - `@panic("msg")` — guaranteed runtime crash with message in all modes. Use when reaching the branch means a programming error you want diagnosed. - **Comptime assertion:** ```zig comptime { std.debug.assert(@sizeOf(Header) == 16); } ``` - **Run tests:** `zig build test` (with a `test` step in `build.zig`). Use `std.testing.allocator` inside tests for free leak detection. - **Format project:** `zig fmt src/` before every commit. --- ## Architecture & naming conventions - **File layout for a multi-file project:** ``` src/ ├── main.zig — entry point, wires modules together ├── parser.zig — @import("parser.zig") from main ├── types.zig — shared type definitions └── util.zig — pure helpers with no cross-dependencies build.zig — build script ``` - **`@import` graph:** keep it a DAG; no circular imports. `main.zig` imports modules; modules import `types.zig` and `util.zig`; `types.zig` imports nothing from the project. - **Visibility:** default to private (no `pub`). Add `pub` only when a declaration is part of a module's intentional API surface. - **Naming conventions:** | Kind | Convention | Example | |---|---|---| | Functions | `camelCase` | `parseHeader` | | Types / structs / enums | `PascalCase` | `TokenKind` | | Constants (comptime-known) | `SCREAMING_SNAKE` | `MAX_RETRIES` | | Variables / fields | `snake_case` | `byte_count` | - **Allocator discipline:** pass `std.mem.Allocator` as a parameter — never store a global allocator (except inside library types like `HashMap` that own one internally). --- ## Code quality rules 1. Every file must compile — no pseudocode, no `// TODO: implement` 2. `const` by default; `var` only when mutation is necessary 3. Pass `std.mem.Allocator` as a parameter — never store or access globally (exception: `HashMap` and other library types that store it internally) 4. `errdefer` for error-path cleanup, `defer` for unconditional cleanup 5. Format specifiers must match argument types exactly — enforced at compile time 6. Comments explain *why*, not *what* 7. No allocations inside hot loops — use `bufPrint` with a stack buffer 8. ArrayList: always pass the allocator; StringHashMap: ensure key lifetime exceeds the map entry's lifetime 9. Try to follow only ascii cheracters as much as possible


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)