numi
A modern SwiftGen replacement
numi

Type-safe code from your
Apple resources.

A blazingly fast Rust CLI that turns asset catalogs, localization files, and file lists into generated accessors. Swift and Objective-C built in — or write your own Minijinja templates to target any language.

View on GitHub
Written in
Rust · 2024
License
MIT
Runtime
Zero
Quickstart

Three commands. Generated code you can trust.

  1. Step 01 1
    Scaffold
    $ numi init

    Drops a starter numi.toml into your project root, preconfigured for common asset layouts.

  2. Step 02 2
    Generate
    $ numi generate

    Parses your resources, renders templates, and writes output files — only when they changed.

  3. Step 03 3
    Verify
    $ numi check

    Exits non-zero if committed files are stale. Wire it into CI and never merge drift again.

Why numi

Built for repos that take generated code seriously.

01

Deterministic outputs

Byte-stable generation. Unchanged inputs never rewrite files — commit the output and trust it.

02

CI-safe with numi check

Exit 0 when fresh, exit 2 when stale. Drop it into any workflow and fail the build on drift.

03

Swift + Obj-C built-ins

Ship-ready templates for SwiftUI assets, localization, and file catalogs in both languages.

04

Minijinja templates

Bring your own templates with a stable context schema. Full access to jobs, inputs, and metadata.

05

Workspace orchestration

One manifest at the repo root, or many across modules. numi --workspace runs them coherently.

06

Cached incremental parses

Asset catalogs and strings files are parsed once, cached on disk, and skipped when untouched.

Config

One manifest in. Type-safe code out.

Declare jobs in numi.toml. Point at inputs, pick a built-in template, and commit the generated file. That's the whole loop.

numi.toml
version = 1

[defaults]
access_level = "internal"

[jobs.assets]
output = "Generated/Assets.swift"

[[jobs.assets.inputs]]
type = "xcassets"
path = "Resources/Assets.xcassets"

[jobs.assets.template.builtin]
language = "swift"
name = "swiftui-assets"

[jobs.l10n]
output = "Generated/L10n.swift"

[[jobs.l10n.inputs]]
type = "xcstrings"
path = "Resources/Localization"

[jobs.l10n.template.builtin]
language = "swift"
name = "l10n"
// Generated by numi. DO NOT EDIT.
import SwiftUI

public enum Asset {
  public enum Image {
    public static let appIcon = ImageResource(name: "AppIcon", bundle: .module)
    public static let heroBanner = ImageResource(name: "HeroBanner", bundle: .module)
    public static let emptyState = ImageResource(name: "EmptyState", bundle: .module)
  }

  public enum Color {
    public static let brandPrimary = ColorResource(name: "BrandPrimary", bundle: .module)
    public static let surface = ColorResource(name: "Surface", bundle: .module)
    public static let onSurface = ColorResource(name: "OnSurface", bundle: .module)
  }
}
Built-in templates

Ship-ready. Or bring your own.

Every built-in is a Minijinja template backed by a stable context schema. Fork one, or write your own — the same data is available either way.

swiftui-assets Swift

Strongly-typed accessors for image and color resources, ready to drop into SwiftUI views.

Input .xcassets
l10n Swift · Obj-C

Generates localization enums with argument-preserving helpers for parameterized strings.

Input .strings · .xcstrings
files Swift · Obj-C

Emits Bundle.url helpers for arbitrary resource files — fonts, fixtures, seed data, anything.

Input file lists
CI-safe

Gate drift at the pull request.

numi check exits 0 when committed files are up to date and 2 when they're stale. Drop it into any workflow and your CI will fail the build before reviewers do.

  • Deterministic output — no timestamps, no ordering noise.
  • Workspace mode checks every manifest in one pass.
  • No-op writes: unchanged files never get rewritten.
.github/workflows/verify.yml
name: verify

on: [push, pull_request]

jobs:
  numi-check:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - run: cargo install numi
      - name: Verify generated files are up to date
        run: numi check --workspace

Generate once. Trust forever.

numi is MIT licensed, on Homebrew and crates.io. One command to install, one to try.