AgentSkillsCN

Kelley

Kelley

SKILL.md

Andrew Kelley — Zig Philosophy

Write Zig code in the style of Andrew Kelley, creator of Zig. Emphasizes simplicity, explicit behavior, compile-time metaprogramming, and being a better C.

Core Philosophy

1. Simplicity Over Cleverness

Zig's goal is to be simple to read and write. Avoid abstractions that hide what's happening.

zig
// BAD: Clever, hard to follow
fn process(comptime T: type, items: []T) !void {
    inline for (std.meta.fields(T)) |f| { ... }
}

// GOOD: Explicit, obvious
fn processCredential(cred: *Credential) !void {
    try validateHost(cred.host);
    try validateToken(cred.token);
}

2. No Hidden Control Flow

  • No exceptions (use error unions)
  • No hidden allocations
  • No operator overloading
  • No implicit type coercion
zig
// Errors are values, explicitly handled
const result = doSomething() catch |err| {
    log.err("failed: {}", .{err});
    return err;
};

3. Explicit is Better Than Implicit

zig
// BAD: What allocator? What happens on OOM?
var list = ArrayList(u8).init();

// GOOD: Allocator is explicit
var list = ArrayList(u8).init(allocator);
defer list.deinit();

4. Compile-Time Over Runtime

Use comptime to eliminate runtime overhead:

zig
// Compile-time string formatting
const endpoint = comptime std.fmt.comptimePrint(
    "https://api.github.com/users/{s}",
    .{username},
);

// Compile-time type validation
fn Command(comptime name: []const u8) type {
    comptime {
        if (name.len == 0) @compileError("command name required");
    }
    return struct { ... };
}

Memory Management

Allocator Discipline

zig
pub fn main() !void {
    // Use GeneralPurposeAllocator for debug builds
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    
    const allocator = gpa.allocator();
    
    try run(allocator);
}

Ownership is Explicit

zig
// Caller owns the returned memory
fn readFile(allocator: Allocator, path: []const u8) ![]u8 {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    return file.readToEndAlloc(allocator, max_size);
}

// Usage: caller must free
const data = try readFile(allocator, "config.toml");
defer allocator.free(data);

Arena Allocators for Request Scope

zig
fn handleCommand(gpa: Allocator, args: []const []const u8) !void {
    var arena = std.heap.ArenaAllocator.init(gpa);
    defer arena.deinit();
    const allocator = arena.allocator();
    
    // All allocations freed at once when arena is deinited
    const config = try loadConfig(allocator);
    const result = try execute(allocator, config, args);
    try output(result);
}

Error Handling

Error Sets are Types

zig
const CredentialError = error{
    NotFound,
    Expired,
    InvalidFormat,
    PermissionDenied,
    NetworkError,
};

fn getCredential(host: []const u8) CredentialError!Credential {
    ...
}

Errors Propagate Explicitly

zig
// Use `try` to propagate
fn sync() !void {
    const cred = try getCredential("github.com");
    try pushToTarget(cred);
}

// Use `catch` to handle
fn syncWithFallback() !void {
    const cred = getCredential("github.com") catch |err| switch (err) {
        error.NotFound => try createCredential(),
        else => return err,
    };
    try pushToTarget(cred);
}

errdefer for Cleanup on Error

zig
fn createSecureStore(allocator: Allocator) !*Store {
    const store = try allocator.create(Store);
    errdefer allocator.destroy(store);
    
    store.key = try deriveKey();
    errdefer zeroMemory(store.key);
    
    store.db = try openDatabase();
    // No errdefer needed - we're returning success
    
    return store;
}

Structs and Data

Prefer Structs Over Classes

zig
const Credential = struct {
    host: []const u8,
    username: []const u8,
    token: []const u8,
    expires_at: ?i64,
    
    pub fn isExpired(self: Credential) bool {
        const now = std.time.timestamp();
        return if (self.expires_at) |exp| now > exp else false;
    }
    
    pub fn format(
        self: Credential,
        comptime fmt: []const u8,
        options: std.fmt.FormatOptions,
        writer: anytype,
    ) !void {
        try writer.print("{s}@{s}", .{ self.username, self.host });
    }
};

Tagged Unions for Variants

zig
const CredentialSource = union(enum) {
    github_cli: struct { config_path: []const u8 },
    git_credential: struct { helper: []const u8 },
    keychain: struct { service: []const u8 },
    environment: struct { var_name: []const u8 },
    
    pub fn name(self: CredentialSource) []const u8 {
        return @tagName(self);
    }
};

Build System

build.zig is Code

zig
pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    
    const exe = b.addExecutable(.{
        .name = "corey",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    
    // Link system libraries
    exe.linkSystemLibrary("secret-1");  // libsecret for Linux keyring
    exe.linkLibC();
    
    b.installArtifact(exe);
    
    // Test step
    const tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
    });
    const run_tests = b.addRunArtifact(tests);
    const test_step = b.step("test", "Run tests");
    test_step.dependOn(&run_tests.step);
}

When to Apply This Skill

  • Designing data structures
  • Implementing error handling
  • Writing allocation-aware code
  • Creating compile-time abstractions
  • Building the project structure
  • Optimizing for readability and debuggability