Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

Zero to generated output in about five minutes. The example below uses TypeScript; the same .prim source produces Rust and Python output by adding another [[output]] block.

Install

cargo install primate --locked

That puts a primate binary at ~/.cargo/bin. Verify:

primate --version

Project layout

primate expects a primate.toml at the project root that points at a directory of .prim files and lists the targets to generate.

my-app/
├── primate.toml
├── constants/
│   └── limits.prim
└── (generated output, paths defined in primate.toml)

A minimal config

# primate.toml
input = "constants"

[[output]]
generator = "typescript"
path      = "web/src/generated/constants/"

Each [[output]] entry enables one target. The built-ins are rust, typescript, and python. External plugins plug in here too — see Writing a generator.

path is a directory for typescript and python (one file per namespace); a single .rs file for rust (one pub mod per namespace). See primate build for the rationale.

A first .prim file

// constants/limits.prim

/// How long the app waits before giving up on a slow request.
duration TIMEOUT     = 30s
u32      MAX_RETRIES = 5
u64      MAX_UPLOAD  = 100MiB

enum LogLevel: u8 {
    Debug = 0,
    Info  = 1,
    Warn  = 2,
    Error = 3,
}

A few things to notice:

  • Type-first. The type comes before the name — duration TIMEOUT, not TIMEOUT: duration. There’s no inference; every constant is explicitly typed.
  • Suffixed literals. 30s is a duration, 100MiB is a byte size. primate normalizes durations to nanoseconds and applies byte-size suffix multipliers at lex time, then bounds-checks the result against the declared type.
  • Doc comments. /// attaches to the next declaration and shows up in generated output where the target language supports docs.
  • One declaration per line. Newlines terminate; no semicolons.
  • No namespace line. The namespace defaults to the file’s path relative to input. constants/limits.prim is in namespace limits. For nested folders, dirs become ::-separated segments (e.g. constants/net/limits.primnet::limits). You only need namespace foo::bar as an explicit override; see Declarations for when that’s useful.

Generate

primate build

primate reads primate.toml, parses every .prim file under input, and writes the generated files. You’ll see something like:

Generated: web/src/generated/constants/limits.ts
Generated: web/src/generated/constants/index.ts

What got generated

// web/src/generated/constants/limits.ts
// Generated by primate. Do not edit.

/** Severity, integer-backed for fast filtering. */
export enum LogLevel {
  Debug = 0,
  Info = 1,
  Warn = 2,
  Error = 3,
}

/** How long the app waits before giving up on a slow request. */
export const timeout = 30_000 as const;            // milliseconds
export const maxRetries = 5 as const;
export const maxUpload = 104_857_600 as const;

…and an index.ts re-exporting each namespace, so consumers can write import { limits } from "./generated/constants".

You can also tune each generator through primate.toml — e.g. options.duration = "temporal" on the TypeScript output emits Temporal.Duration values instead of milliseconds. See primate build for everything tunable.

Editor setup

primate ships an LSP server (primate lsp). The dev experience is significantly better with it on:

  • Diagnostics live in your buffer (parse errors, unknown types, length-mismatch on fixed arrays, …).
  • Hover docs on type names, including types in other namespaces.
  • Go-to-definition for enums and aliases, including across files.
  • Find references across the workspace, following use imports.
  • Format on save.

Setup per editor:

  • VS Code — install from the Marketplace.
  • Zed — install from the Zed extensions registry.
  • Vim — drop the syntax/ftdetect files into your runtime path.

Next steps

  • Language overview — the full set of declarations, types, and value literals.
  • Cookbook — common shapes (matrices, lookup tables, platform-specific overrides).
  • Plugins — write a generator for a language the built-ins don’t cover.