Provides coding and architectural support for Mach language projects.

Install

mkdir -p .claude/skills/mach && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/17824" && unzip -o skill.zip -d .claude/skills/mach && rm skill.zip

Installs to .claude/skills/mach

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.

Use when writing, editing, or reviewing Mach (.mach) source files. Covers the full language: project/module structure, use/fwd imports and re-exports, the shadow-module pattern, all declaration forms (def, rec, uni, fun, ext fun, val/var, test), the type grammar with the ^ secret qualifier, literals, operators and casts, statements, docstring conventions, stdlib idioms (Result/Option, std.print), the comptime channel ($mach.*/$project.*/$bin.* reads, $if/$or, $each, intrinsics, comptime parameters, variadic packs), #[...] decorators, and inline assembly (asm x86_64/aarch64/riscv64).
589 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Write Mach (.mach) source files.
  • Edit Mach source files according to language rules.
  • Review Mach source files for correctness and style.
  • Understand Mach project and module structure.
  • Implement comptime features and inline assembly.

How it works

This skill provides guidance on Mach language rules, covering syntax, module structure, declarations, and advanced features like comptime and inline assembly. It emphasizes explicit typing and adherence to specific idioms.

Inputs & outputs

You give it
A task requiring Mach code creation, modification, or review.
You get back
Correct, compliant Mach (.mach) source code.

When to use mach

  • Writing Mach code
  • Reviewing Mach language syntax
  • Structuring Mach modules

About this skill

Mach

Mach is a low-level, explicitly-typed language: no type inference, no garbage collection, no hidden control flow. Files use .mach. This skill is the fast path for authoring correct Mach; doc/language/ in the Mach repository is the authoritative reference and wins on any disagreement.

Hard rules - get these right

  • No type inference. Every binding declares its type. val x = 42; is an error; write val x: i64 = 42;.
  • No compiler-known type aliases. bool, usize, str, char are stdlib defs, not built-ins. Import them before use (use std.types.bool.bool;). true/false are stdlib vals (1/0); comparisons and logical operators produce u8.
  • Decorators are #[...] attributes on the line(s) above a declaration: #[symbol("main")], #[inline], #[align(64)]. The backtick form was removed in v2.4.0 and is a migration error - never emit backticks.
  • File embeds are typed byte arrays. #[embed("asset.bin")] applies only to an uninitialized val declared as [_]u8 (length from the file) or [N]u8 (length checked). The path is relative to the declaring source file; bytes become read-only data at compile time, with no runtime I/O.
  • Variadics are comptime packs. A trailing va: ... parameter, consumed by $each a in va. There is no va_list/va_start/va_arg. A bare ... is a different thing entirely: the C-variadic marker, legal only on an ext fun (ext fun open(path: *u8, flags: i32, ...) i32), and a removed-syntax error anywhere else.
  • Strings are *u8, single-line. "hello" is a pointer to null-terminated bytes. No fat-pointer string type (str is def str: *char;); no multi-line string literal - use \n escapes.
  • No tagged unions, no match. A discriminated value is a rec carrying a discriminator plus a payload uni; consumers branch with if/or. This is exactly how stdlib Result[T, E] is built.
  • No compound assignment. += etc. do not exist; write x = x + 1;.
  • fwd is bare and always public (no pub fwd). ext fun is the only body-less function form.

Project and module structure

A project has a mach.toml at its root; [project] id roots every module path. A file at src/foo/bar.mach in project id = "myproj" is the module myproj.foo.bar. There is no this. self-prefix - always use the full project-rooted path, including for sibling modules. A one-segment use <id>; resolves only when that project declares a [project] module surface file (e.g. a library glfw imported as use glfw;); std does not - always import full std.* paths.

An artifact build roots its module graph at [artifact.*].entry and compiles only that module plus its active transitive use/fwd dependencies. A sibling source file is not part of the build cell merely because it is under [project].src, so one project may hold artifacts for disjoint targets. mach test deliberately roots at every own-source module so it can collect otherwise-unreferenced tests.

A file reads top-down: module docstring, use/fwd lines, declarations.

use - private import

use std.types.size;             # binds module `size`; use as size.usize
use sz: std.types.size;         # module under alias; use as sz.usize
use std.types.size.usize;       # binds the symbol; use bare as usize

The resolver binds whatever the path ends at: a module (members reached qualified) or a symbol (used bare). Importing a module does not pull its members in unqualified. No splat, no use foo.{a,b} - one name per line. A module uses every dependency it directly names, even ones reachable through a re-export: the dependency graph is visible at the top of every file.

fwd - public re-export

fwd impl.Point;                 # re-export as Point
fwd Pt: impl.Point;             # re-export as Pt
fwd impl.helpers;               # a module path re-exports the whole module

Mirrors use grammar; always publishes.

Shadow-module pattern

A surface file foo.mach co-exists with directory foo/ holding split implementations. The surface uses each split and fwds its public symbols; consumers use myproj.foo; and never name the splits. Topical splits forward everything unconditionally; multiplatform splits pick one impl per target:

$if ($mach.build.os == $mach.os.linux) {
    use impl: myproj.os.linux;
}
$or ($mach.build.os == $mach.os.windows) {
    use impl: myproj.os.windows;
}
$or {
    $error("myproj.os: unsupported target");
}

fwd impl.page_size;

Entrypoint and output

An artifact's out is literal across every target it names. A cross-platform executable therefore uses disjoint artifacts for extension conventions: out = "bin/app" for non-Windows targets and out = "bin/app.exe" for Windows. mach init emits that split for binary projects. Do not use one targets = ["*"] artifact when its output must be directly executable on Windows and elsewhere.

The stdlib provides the platform _start, which calls whatever function exports the linker symbol main. use std.runtime; is required to link it in even though nothing references it by name:

use std.runtime;
use std.print;

#[symbol("main")]
fun main(argc: i64, argv: **u8) i64 {
    print.println("hello, mach");
    ret 0;
}

use std.print; binds the leaf module print (std itself is not in scope). It exposes print/println (stdout), eprint/eprintln (stderr), and the format family printf/printlnf/eprintf/eprintlnf - pack-variadic, with {} holes filled in argument order plus {:x}-style specs ({:X}, {:c}, {:5}, {:<5}, {:08x}; {{/}} for literal braces). All return Result[usize, str].

Windows executable resources

An executable artifact may declare project-root-relative PE assets:

[artifact.game]
kind = "bin"
entry = "main.mach"
out = "bin/game.exe"
targets = ["*"]
link = []
need = []
icon = "assets/game.ico"
manifest = "assets/game.manifest"

icon is a valid ICO container; manifest is embedded byte-for-byte. Either adds PE icon/manifest resources plus version information. Version strings come from [project].version, InternalName/ProductName from the artifact table key, and OriginalFilename from the resolved output basename. These keys are accepted but not read on non-Windows targets, and are rejected on static or shared artifacts. If a build step generates an asset, name that step in need and make its output exactly match the resource path.

print.printlnf("built {} in {}ms", name, elapsed);

Declarations

Modifiers: pub (public surface; without it a declaration is file-private) applies to fun, rec, uni, def, val, var; ext (C-ABI external) applies to functions only.

def - type alias

pub def Age:   i64;
pub def BinOp: fun(i64, i64) i64;

Aliases name any type; alias and underlying type are interchangeable.

rec / uni

pub rec Point { x: i64; y: i64; }
pub rec Pair[T, U] { left: T; right: U; }      # generic

pub uni Number { i: i64; f: f64; }              # fields overlap; size of largest

The compiler does not track which uni field is live. The sum-type idiom (stdlib Result[T, E] verbatim):

pub rec Result[T, E] {
    tag:   bool;
    value: uni { ok: T; err: E; };
}

Packed layout is not available; #[align(N)] raises a type's or global's alignment.

fun

pub fun add(a: i64, b: i64) i64 { ret a + b; }
pub fun identity[T](value: T) T { ret value; }  # generic; call: identity[i64](42)
pub fun load($order: u8, p: *i64) i64 { ... }   # comptime value param (see Comptime)
pub fun sum(va: ...) i64 {                      # variadic pack (see Comptime)
    var t: i64 = 0;
    $each a in va { t = t + a; }
    ret t;
}

Generic params [T] take types only, no constraints; monomorphized per instantiation; call sites always supply the types explicitly.

ext fun

#[symbol("write")]
pub ext fun libc_write(fd: i64, buf: *u8, n: i64) i64;

Body-less, ends in ;, C ABI is the contract.

A C-variadic callee ends its parameter list in a bare ..., after at least one fixed parameter — ext only, call side only (mach defines no va_arg callee):

ext fun open(path: *u8, flags: i32, ...) i32;

Tail arguments get no implicit conversion, so write C's default argument promotions yourself: an integer narrower than 32 bits and an f32 are rejected with the cast to apply (x::i32, x::f64), and a secret may not enter a tail. Declaring a variadic callee at fixed arity instead is silently wrong on Apple arm64, which passes the whole tail on the stack. See doc/language/ext-fun.md.

Provide the definition at link time (mach build . -l c, a [link.X] manifest requirement, or an explicit .o/.obj/.a/.lib/.so/.dylib/.dll). On PE and Mach-O targets, pin each dynamic import with #[library("name")]. The value is the requirement's stable library identity (defaulting to the [link.X] table name); exact loader names remain accepted. A discovered Darwin @rpath/ install name retains its selected library directory as an LC_RPATH command.

For a bare -l name, every target probes .o/.a; only PE/COFF also probes the .obj/.lib spellings. Explicit paths retain their spelling so a format mismatch produces a direct diagnostic.

Windows COFF inputs compiled with C/C++ dllimport may leave __imp_X undefined. Attribute the real export X normally; the linker strips the object prefix for loader lookup and points the foreign reference at X's IAT cell. A direct X reference and __imp_X share one import entry — never map __imp_X as a separate loader export. If the same link graph instead supplies a strong X, __imp_X is a local pointer cell initialized to X: it creates no loader import and needs no #[library] attribution, while direct references still target X. An import-libra


Content truncated.

When not to use it

  • When working with languages other than Mach.
  • When type inference or garbage collection is expected.

Limitations

  • No type inference is supported.
  • No compiler-known type aliases like `bool` or `usize`.
  • No tagged unions or `match` statements.

How it compares

This skill provides authoritative guidance on Mach's strict, low-level language features, including its explicit typing and lack of type inference, which differs from more permissive languages.

Compared to similar skills

mach side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
mach (this skill)02moReviewAdvanced
software-architecture3337moNo flagsIntermediate
codex323moReviewAdvanced
game-development707moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

software-architecture

davila7

Guide for quality focused software architecture. This skill should be used when users want to write code, design architecture, analyze code, in any case that relates to software development.

333868

codex

Lucklyric

Invoke Codex CLI for complex coding tasks requiring high reasoning capabilities. This skill should be invoked when users explicitly mention "Codex", request complex implementation challenges, advanced reasoning, or need high-reasoning model assistance. Automatically triggers on codex-related requests and supports session continuation for iterative development.

32238

game-development

davila7

Game development orchestrator. Routes to platform-specific skills based on project needs.

70195

senior-fullstack

davila7

Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.

35110

command-name

anthropics

This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.

697

python-project-structure

wshobson

Python project organization, module architecture, and public API design. Use when setting up new projects, organizing modules, defining public interfaces with __all__, or planning directory layouts.

860

Search skills

Search the agent skills registry