# 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
```bash
cargo install primate --locked
```
That puts a `primate` binary at `~/.cargo/bin`. Verify:
```bash
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.
```text
my-app/
├── primate.toml
├── constants/
│ └── limits.prim
└── (generated output, paths defined in primate.toml)
```
## A minimal config
The fastest path is the wizard:
```bash
primate init
```
It walks you through the source directory, which target languages to
generate, the output path for each, and any external plugins. The
resulting `primate.toml` is heavily commented and lists every option
each picked generator accepts at its default — so you discover what's
tunable without leaving the editor. See [`primate init`](./cli/init.md)
for the full flow.
Hand-writing it is fine too; the minimum is:
```toml
# 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](./plugins/writing-a-generator.md).
`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`](./cli/build.md) for the rationale.
## A first `.prim` file
```primate
// 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.prim` → `net::limits`). You only need
`namespace foo::bar` as an explicit override; see
[Declarations](./language/declarations.md) for when that's useful.
## Generate
```bash
primate build
```
primate reads `primate.toml`, parses every `.prim` file under `input`,
and writes the generated files. You'll see something like:
```text
Generated: web/src/generated/constants/limits.ts
Generated: web/src/generated/constants/index.ts
```
## What got generated
```typescript
// 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`](./cli/build.md) 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](./editors/vscode.md)** — install from the Marketplace.
- **[Zed](./editors/zed.md)** — install from the Zed extensions registry.
- **[Vim](./editors/vim.md)** — drop the syntax/ftdetect files into your runtime path.
## Next steps
- [Language overview](./language/overview.md) — the full set of
declarations, types, and value literals.
- [Cookbook](./cookbook/enums.md) — common shapes (matrices, lookup
tables, platform-specific overrides).
- [Plugins](./plugins/writing-a-generator.md) — write a generator for a
language the built-ins don't cover.