Zig Tiger Style logo

Zig Tiger Style

Organization
zigcc
zig-tiger-style

TigerStyle Zig coding guidelines — distilled from TigerBeetle's production codebase. Use this skill whenever the user is writing, reviewing, or refactoring Zig code, asking about Zig idioms, best practices, assertions, memory layout, naming conventions, or code style. Also trigger when the user asks how to structure Zig structs, handle errors, write safe loops, or design Zig APIs. Even if the user just says "write me some Zig" or pastes Zig code for review, consult this skill first.

Overview

Publisherzigcc
Repositoryskills
Skill namezig-tiger-style
Stars
53
Forks
3
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by zigcc on GitHub. Read the source before you install it.

Installation

Install the Zig Tiger Style AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/zigcc/skills/tree/main/zig-tiger-style
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/zigcc/skills.git /tmp/skills
mkdir -p .claude/skills
cp -r /tmp/skills/zig-tiger-style .claude/skills/zig-tiger-style
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Zig Tiger Style in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Zig Tiger Style on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Zig Tiger Style is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

TigerStyle: Zig Coding Guidelines

Distilled from TigerBeetle's TIGER_STYLE.md. Design goal priority: Safety > Performance > Developer Experience.


1. Safety

Control Flow

  • Use only simple, explicit control flow. No recursion unless provably bounded.

  • Split compound conditions into nested if/else branches — ensure both the positive and negative spaces are handled or asserted.

  • State invariants positively:

    zig
    // preferred
    if (index < length) { ... } else { ... }
    
    // avoid
    if (index >= length) { ... }
  • Every if branch should prompt the question: does a corresponding else also need to be handled?

Assertions

Assertions detect programmer errors — not expected runtime errors. The only correct response to corrupt state is to crash. Assertions downgrade catastrophic correctness bugs into liveness bugs.

  • A function must not operate blindly on data it has not checked; assert arguments at the entry point.

  • Pair assertions: for any property you want to enforce, add assertions on at least two different code paths (e.g. just before writing to disk, and immediately after reading back).

  • Split compound assertions:

    zig
    // preferred
    assert(a);
    assert(b);
    
    // avoid
    assert(a and b);
  • Use a single-line if to assert an implication: if (a) assert(b);

  • Assert relationships between compile-time constants to verify design integrity before the program even runs:

    zig
    comptime assert(@sizeOf(Header) == 128);
    comptime assert(config.pipeline_max <= config.batch_max);
  • Assert both the positive space (what you expect to be true) and the negative space (what you expect to be false) — the boundary between valid and invalid is where bugs hide.

Memory

  • Initialize large structs in-place via an out pointer to eliminate intermediate copies and guarantee pointer stability:

    zig
    // preferred
    fn init(target: *LargeStruct) !void {
        target.* = .{ ... };
    }
    
    // avoid
    fn init() !LargeStruct {
        return LargeStruct{ ... };
    }

Variable Scope

  • Declare variables at the smallest possible scope to reduce the chance of misuse.
  • Declare variables close to where they are used — do not introduce them before they are needed. This avoids POCPOU bugs (a distant cousin of TOCTOU).

Loops and Queues

  • All loops and queues must have a fixed upper bound to prevent infinite loops or tail-latency spikes. Follow the fail-fast principle.
  • Loops that genuinely cannot terminate (e.g. an event loop) must be explicitly asserted as such.

Error Handling

  • All errors must be handled. Most catastrophic production failures stem from incorrect handling of non-fatal errors.
  • Never discard error return values with _.

Other

  • Use explicitly-sized integer types (u32, i64, etc.), avoid architecture-dependent usize when possible
  • Enable and respect the compiler's strictest warning settings — zero tolerance for warnings.
  • Do not react directly to external events inline; let the program run at its own pace (enables batching and maintains control-flow ownership).
  • Keep functions as small as possible. When splitting, find semantically clean cut points:
    • Centralize all if/switch in the "parent" function; extract pure logic into helpers.
    • Let the parent own all mutable state; helpers compute what to change but don't apply it.
    • Rule of thumb: "push ifs up and fors down".

2. Performance

  • Solve performance in the design phase — the biggest wins (1000x) come from architecture, not post-hoc profiling.

  • Do back-of-the-envelope sketches across the four resources (network, disk, memory, CPU) and their two characteristics (bandwidth, latency).

  • Optimize slowest resources first: network → disk → memory → CPU, weighted by access frequency.

  • Batching is the primary tool: amortize network, disk, memory, and CPU costs.

  • Distinguish control plane from data plane; batching lets both coexist safely and fast.

  • Extract hot-path loops into standalone functions with primitive arguments (no self) so the compiler can cache fields in registers and humans can spot redundant work:

    zig
    // hot loop extracted, no self
    fn process_batch(items: []const Item, result: []Output) void { ... }
  • Be explicit. Do not rely on the compiler to do the right thing.

  • Always pass options explicitly at library call sites — never rely on defaults:

    zig
    // preferred
    @prefetch(a, .{ .cache = .data, .rw = .read, .locality = 3 });
    
    // avoid
    @prefetch(a, .{});

3. Naming

  • In general, functions are camelCase, types are PascalCase, variables are lowercase_with_underscores. One exception to those rules is functions that return types. They are PascalCase:

    zig
    pub fn ArrayList(comptime T: type) type {
      return ArrayListAligned(T, null);
    }
  • Normally, file names are lowercase_with_underscore. However, files that expose a type directly should be PascalCase.

  • Do not abbreviate variable names (except primitive integer loop indices in sorts/matrices).

  • Acronyms are fully capitalized: VSRState, not VsrState.

  • Append units and qualifiers to names, ordered by descending significance, so the most important word comes first:

    zig
    latency_ms_max    // not max_latency_ms
    latency_ms_min    // aligns nicely with the above
    message_size_max
  • Choose related names with the same character count so they align visually:

    zig
    source         // same length as target
    target
    source_offset
    target_offset
  • Name helper/callback functions with the caller's name as a prefix: read_sector() → read_sector_callback()

  • Callbacks go last in the parameter list (mirrors invocation order).

  • Infuse names with meaning: gpa: Allocator and arena: Allocator are far more informative than allocator: Allocator.

  • Functions that take two or more arguments of the same type must use a named options: struct parameter to prevent argument confusion.

Struct and File Layout

zig
// Struct order: fields → type definitions → methods
time: Time,
process_id: ProcessID,

const ProcessID = struct { cluster: u128, replica: u8 };
const Tracer = @This();

pub fn init(gpa: std.mem.Allocator, time: Time) !Tracer { ... }
  • The main function goes at the top of the file — readers see the most important thing first.
  • Promote complex nested types to top-level structs.

4. Comments

  • Comments are full sentences: space after //, capital letter, ending with a period (or colon when introducing something). Inline end-of-line comments may be phrases without punctuation.
  • Always say why. Code shows what and how; comments explain the reasoning behind decisions.
  • Add a description at the top of tests explaining the goal and methodology.
  • On occasion, use an obviously-true assertion instead of a comment to document a critical, surprising invariant — the assertion is stronger documentation.

5. Formatting

  • Always run zig fmt.

  • Use 4 spaces of indentation (more visually obvious than 2 at a distance).

  • Hard limit of 100 columns per line, no exceptions. Add a trailing comma and let zig fmt handle the wrapping.

  • Always add braces to if statements unless the whole thing fits on one line:

    zig
    // single-line ok without braces
    if (ok) return;
    
    // multi-line always needs braces
    if (condition) {
        do_something();
    }

Division — be explicit about rounding intent

zig
@divExact(a, b)   // asserts no remainder
@divFloor(a, b)   // rounds toward negative infinity
div_ceil(a, b)    // rounds toward positive infinity

6. Off-by-One Errors

index (0-based), count (1-based), and size (= count × unit) are distinct types with clear conversion rules:

  • index → count: add 1
  • count → size: multiply by the unit size
  • Include units and qualifiers in variable names (see Naming) to make these conversions visible.

7. Dependencies and Tooling

  • Zero-dependencies policy: no external dependencies beyond the Zig toolchain.
  • Write scripts as scripts/*.zig instead of *.sh — cross-platform, type-safe, more reliable.
  • Standardize on Zig for tooling to reduce dimensionality as the team grows.

Pre-Commit Checklist

Before submitting, verify:

  • All lines are <= 100 columns; zig fmt has been run
  • All errors are handled (no _ discards)
  • Variable names include units/qualifiers and are not abbreviated
  • Compound conditions are split into nested if/else
  • All loops have an explicit upper bound
  • Comments explain why, not just what
  • Compile-time constant relationships are verified with comptime assert

Frequently asked questions

What does the Zig Tiger Style AI skill do?

TigerStyle Zig coding guidelines — distilled from TigerBeetle's production codebase. Use this skill whenever the user is writing, reviewing, or refactoring Zig code, asking about Zig idioms, best practices, assertions, memory layout, naming conventions, or code style. Also trigger when the user asks how to structure Zig structs, handle errors, write safe loops, or design Zig APIs. Even if the user just says "write me some Zig" or pastes Zig code for review, consult this skill first.

Why use Zig Tiger Style on TypingMind?

Because you install it once and use it with any model. Zig Tiger Style is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Zig Tiger Style in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/zigcc/skills/tree/main/zig-tiger-style. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Zig Tiger Style?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Zig Tiger Style?

As many as you like. As long as a model supports skills, you can use Zig Tiger Style with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Zig Tiger Style AI skill free?

It is published on GitHub by zigcc. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇