# primate
A small DSL for cross-language constants. Write your shared values once,
generate typed Rust, TypeScript, and Python — with documentation, enums,
type aliases, and bounds-checked numeric literals carried through to each
target.
```text
constants/ ┌────────────────────────────┐
└── limits.prim ─────────► │ primate build │
└────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
src/generated/constants.rs web/src/generated/limits.ts scripts/generated/limits.py
```
## Why
If you ship a backend, a web client, and a script, you've already written
`MAX_UPLOAD_SIZE = 100 * 1024 * 1024` three times — and at least one of
them is wrong. primate makes that one declaration produce one number per
target, in the form each language wants:
```primate
// constants/limits.prim
//! Application-wide limits.
/// Maximum upload size for a single request.
u64 MAX_UPLOAD_SIZE = 100MiB
/// Time after which an idle session is considered offline.
duration OFFLINE_THRESHOLD = 20min
/// Severity level. Integer-backed for fast filtering.
enum LogLevel: u8 {
Debug = 0,
Info = 1,
Warn = 2,
Error = 3,
}
LogLevel DEFAULT_LEVEL = Info
```
Generated **Rust** (`pub mod` per namespace, `std::time::Duration`,
`#[repr(u8)]` enums):
```rust
pub mod limits {
pub const MAX_UPLOAD_SIZE: u64 = 104857600;
pub const OFFLINE_THRESHOLD: std::time::Duration = std::time::Duration::from_nanos(1200000000000);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum LogLevel {
Debug = 0,
Info = 1,
Warn = 2,
Error = 3,
}
pub const DEFAULT_LEVEL: LogLevel = LogLevel::Info;
}
```
Generated **TypeScript** (one `.ts` per namespace + `index.ts`,
`Temporal.Duration` available, real ES enums):
```typescript
// generated/constants/limits.ts
export enum LogLevel {
Debug = 0,
Info = 1,
Warn = 2,
Error = 3,
}
export const maxUploadSize = 104857600 as const;
export const offlineThreshold = 1200000 as const; // milliseconds
export const defaultLevel = LogLevel.Info as const;
```
Generated **Python** (package directory, `IntEnum`, `timedelta`):
```python
# generated/constants/limits.py
from enum import IntEnum
from datetime import timedelta
class LogLevel(IntEnum):
DEBUG = 0
INFO = 1
WARN = 2
ERROR = 3
MAX_UPLOAD_SIZE: int = 104857600
OFFLINE_THRESHOLD: timedelta = timedelta(seconds=1200)
DEFAULT_LEVEL: LogLevel = LogLevel.INFO
```
## Highlights
- **Unit-suffixed literals.** `30s`, `100MiB`, `5%`, `1w` — readable in
source, normalized in generated code.
- **Bounds-checked.** `u32 X = 5GiB` is a compile-time error.
- **Cross-namespace `use`.** Files in `constants/auth/*.prim` can
`use logging::LogLevel`; the right import is emitted in each target.
- **One canonical formatter.** `primate fmt` — no flags.
- **Editor support.** A real LSP server (`primate lsp`) ships with the
binary: diagnostics, hover, go-to-definition, find-references, format
on save, and contextual completion (enum variants, unit suffixes).
Editor integrations for Zed and VS Code are in [`editors/`](./editors).
- **Plugin protocol.** Add a target language by writing any executable
that reads JSON on stdin and writes JSON on stdout — see
[docs/plugins](./docs/src/plugins/protocol.md).
## Install
```bash
cargo install primate --locked
```
This puts a `primate` binary in `~/.cargo/bin`. Verify:
```bash
primate --version
```
## Quick start
```bash
mkdir my-app && cd my-app
cat > primate.toml <<'EOF'
input = "constants"
[[output]]
generator = "typescript"
path = "web/src/generated/constants/"
[[output]]
generator = "rust"
path = "src/generated/constants.rs"
EOF
mkdir constants
cat > constants/limits.prim <<'EOF'
duration TIMEOUT = 30s
u32 MAX_RETRIES = 5
u64 MAX_UPLOAD = 100MiB
EOF
primate build
```
You'll see one file per target appear under the configured paths.
## Project status
**v0.1** — usable, but evolving. The language is stable enough to depend
on, generators produce idiomatic output for the three built-ins, and the
LSP works in real editors. Things still on the roadmap: `@deprecated`
attributes, configurable formatter rules, plugin distribution. See
[`docs/src/roadmap.md`](./docs/src/roadmap.md).
## Documentation
The full book is at [`docs/`](./docs/), browsable via mdBook:
```bash
cd docs && mdbook serve --open
```
Top-level pages:
- [Getting started](./docs/src/getting-started.md)
- [Language overview](./docs/src/language/overview.md)
- [`primate build`](./docs/src/cli/build.md)
- [Cookbook](./docs/src/cookbook/enums.md)
- [Plugin protocol](./docs/src/plugins/protocol.md)
## License
MIT — see [LICENSE](./LICENSE).