A living template for new Rust projects: a real, buildable, CI-green Cargo
workspace under the placeholder identity acmex, carrying a complete quality
machine from day one. Create a copy, run the init ceremony, and start working
inside a fully armed pipeline instead of assembling one.
Extracted from the production workspace of UFFS: Ultra Fast File Search, and battle-tested there first. Built and maintained by Robert S.A. Nio.
Vibe-code a serious Rust project without it turning into slop: the guardrails catch what you and the AI miss.
Thirty seconds of honesty before you invest an hour. The axis is intent, not experience: you do not need to be a veteran.
Skip it (use cargo new instead) if:
- learning the language itself is the goal right now (a tutorial, book chapter, Rustlings, Advent of Code): the machinery enforces engineering discipline, which is a distraction from learning syntax and the borrow checker
- you are writing a throwaway script, a one-evening experiment, or a quick prototype whose whole point is speed over rigor
- you are allergic to process: this repo rejects commits, rejects pushes, and argues back, by design
Use it if you are building something meant to live: a tool, service, or library that others (including future-you) will depend on. At any level:
- Newer to Rust but serious? This is a safety net that lets you build above your raw skill level: the guardrails plus your AI assistant carry the rigor you could not yet set up or enforce yourself. Fair warning, stated plainly: the guardrails are a two-way street: they WILL reject your (and your AI's) first draft, and satisfying them is exactly how the leveling-up happens. This is not zero-effort "vibe and ship"; it is vibe-coding with a spotter.
- Veteran? You are skipping roughly two days of wiring lints, hooks, CI, supply-chain checks, and release plumbing, arriving at the posture you would have built anyway.
Either profile, the same reasons apply:
- you want excellent Rust posture forced, not aspired to: ~200 deny-level
lints (no
unwrap, nopanic!, notodo!, everything documented, every exception carries a written reason), so quality is machine-enforced from commit one instead of debated in review - you want the delivery machine pre-built: commit/push gates in seconds, PR CI, weekly deep checks (miri, mutation testing), supply-chain vetting, license compliance, and release/publishing lanes that already exist and switch on with a variable when you are ready
- you know strictness is only affordable on day one: the donor project measured what retrofitting costs: a single lint had ~1,766 violations by the time it was considered, and 341 supply-chain exemptions had to be grandfathered; starting strict costs nothing
- you code with an AI assistant and want guardrails that make generated code prove itself: the gates hold everything (and everyone) to the same standard, and bypassing them is mechanically blocked
| Resource | What you need |
|---|---|
| Machine | 8 GB RAM minimum (16 GB comfortable once the project grows; fat-LTO release builds are hungry); a few CPU cores (gates run parallel); SSD strongly recommended |
| Disk | ~2 GB pinned toolchain + ~1 GB gate tools + 1-2 GB build dir for the skeleton, growing with your code; plan for 10 GB+ per project over time |
| Network | First setup downloads roughly 3-4 GB (toolchain, tools, crate index) |
| Accounts & keys | A GitHub account, gh CLI authenticated, and a commit-signing key (SSH or GPG): the pre-push gate requires every commit signed, and it is a hard gate: no key, no push |
| Time | ~30-45 minutes from empty machine to first green just go (mostly downloads/compiles); afterwards 2-15 s per commit, 20-60 s per push (warm) |
| Platform | macOS and Linux are first-class; Windows works with Git-Bash for the hooks |
Numbers from a real PR through this repo itself: the hello-world floor
(acmex-core + the acmex binary), so this is the minimum; your code
grows it:
| Path | Jobs | Wall clock | Compute minutes |
|---|---|---|---|
| Docs-only PR (classifier skips Rust jobs) | 7 | ~1-2 min | ~3 |
| Code-touching PR (full battery: clippy ×3 incl. Windows, tests, docs, security, drift) | 15 | ~3 min | ~14 |
| Merge-queue pass (the full battery again, on the queued state) | 15 | ~3.5 min | ~14 |
So a code change pays roughly ~6-7 minutes wall clock and ~28 compute minutes from "PR opened" to "merged through the queue": industrial-strength processing, and that is its time price. On top: the weekly tier-2 deep suite (miri, mutation testing, coverage; tens of compute minutes) and the nightly canary.
The money: on a public repo, GitHub-hosted runners are free - the whole machine costs $0. On a private repo at GitHub's list rates (Linux $0.008/min, Windows $0.016/min), the full battery is ~$0.13 per run, ~$0.26 per queued code change: a few dollars a month for an active project, before the free-tier minutes that most plans include.
Once you are in, the machine does not allow shortcuts, for you or for
your AI assistant. Hooks reject bad commits, the push gate rejects
unsigned or failing work, CI re-checks everything, and the bypass
(--no-verify) is mechanically blocked for AI sessions and treated as an
incident for humans. That is the deal: you give up the ability to cut
corners, and in return every green build actually means something: the
discipline you would need to impose on yourself (and on generated code) is
enforced by the repo instead.
The price, stated plainly: a pinned nightly toolchain (10-minute stable
downgrade documented), ~10 dev tools installed by just setup, a few seconds
per commit and under a minute per push for the gates, and lints that WILL
reject code that would compile fine. That price is the product.
Rule of thumb: if the project deserves a README, tests, and a version
number, it deserves this template. If it is a sketch, cargo new is the
right tool. Come back when the sketch becomes a plan.
| Layer | Contents |
|---|---|
| Lint posture | ~200-lint deny-everything [workspace.lints] (no unwrap/panic/todo, everything documented, #[expect] with reason instead of allow), nightly rustfmt, clippy.toml test relaxations |
| Local gates | gates.toml manifest → generated pre-commit / pre-push hooks (fmt, typos, REUSE, taplo, file-size, commit conventions, signatures, clippy tiers, tests, vet, deny, machete) with drift detection |
| Pipeline | just go (validation lane) and just ship (resumable bump → changelog → signed release PR → auto-merge) driven by the acmex-ci-pipeline crate |
| CI | pr-fast.yml tier-1 required gate (validated against gates.toml by acmex-gen-workflow), weekly tier-2 (miri, careful, mutants, udeps, hack, coverage), CodeQL, commitlint, nightly canary, dependabot triage + auto-merge, CI-failure notify + auto-rerun |
| Supply chain | cargo-vet (5 community audit-set imports, zero exemption debt), cargo-deny, SHA-pinned actions, committed Cargo.lock |
| Licensing | REUSE/SPDX compliance (checked at commit time), per-file headers, LICENSES/ store |
| Release lanes (dormant) | Multi-target release build, crates.io publish (release-plz), winget, SLSA attestation: all present, all inert until you flip a repo variable (see docs/forge/COMPONENTS.md) |
| Skeleton | acmex-core (lib), acmex-cli (bin acmex), acmex-version (shared --version machinery): hello-world code that exercises every gate honestly |
New to Rust,
just, or any of this? GETTING-STARTED.md is the zero-knowledge runbook: from empty machine to green pipeline, including the daily loop and a fix-it table for every gate.🤖 AI agents: read AGENTS.md before touching anything - state detection, hard prohibitions, and the exact fix for every gate. (Claude Code is routed there automatically via CLAUDE.md.)
Day zero, no project yet? Paste this into your AI and let it drive:
Read https://raw.githubusercontent.com/skyllc-ai/rust-forge-template/main/AGENTS.md and guide me from nothing to a green pipeline: help me create my own project from this template.Already inside a project built from this template? Paste this instead:
Read and follow: https://raw.githubusercontent.com/acmex-org/acmex/main/AGENTS.md(That second URL is this repository's own copy;
just initrewrites it to your project's address.)
Guided (recommended): one script drives the whole journey with a consent prompt at every step: docs gate → tools → GitHub auth → create/clone the repo → init ceremony → gate tools + hooks → commit signing → first green validation run:
curl -fsSL https://raw.githubusercontent.com/skyllc-ai/rust-forge-template/main/bootstrap.sh | bashFor unattended machines (fleet/CI) there is a separate --yes lane that
never generates signing keys; see GETTING-STARTED's
"Unattended / fleet provisioning" section.
Manual: the same journey as individual commands, for people who want to see every move (this is also exactly what the script runs):
# 1. Create your repo from this template (fresh history, no coupling)
gh repo create my-org/myproj --template skyllc-ai/rust-forge-template --private --clone
cd myproj
# 2. Init ceremony (renames acmex → your identity, resets earned state)
just init myproj my-org "My Org LLC" "Me <me@example.com>"
# 3. Gate tools + hooks, commit signing, then prove the machine
just setup
just setup-signing
just go
# 4. GitHub-side state a template cannot carry
# (rulesets + merge queue, required checks, labels, lane variables)
bash scripts/ci/bootstrap-github.shAlready have a project? The scaffolding can be brought to existing
code too, fully automated and fully reversible: adopt.sh wires
everything on a dedicated branch (every edit git-guarded and validated,
nothing of yours overwritten, lints installed inert), commits the trial,
and just adopt-undo restores your repo bit-for-bit if you change your
mind. Repo-global pieces (hooks config, signing, rulesets) stay deferred
to an explicitly sequenced cutover step: see
ADOPTING.md.
After init, rg -i acmex returns nothing; that emptiness is the proof the
rename ceremony completed.
The machinery ships at 100% and idles; the product grows through recipes.
docs/forge/COMPONENTS.md is the master catalog for both:
- Lanes (machinery you switch ON): crates.io publishing, winget, codecov,
SLSA, the release pipeline. Dormant behind repo variables (
LANE_*) andrelease-plz.tomlflags: activation is a data change, never a new file. - Components (structure you ADD): new crates, fuzz targets, benches.
Each entry documents prerequisites, tooling, files touched, and a verify
command that always ends in
just go.
just go # full validation lane (no version bump, no push)
just check # quick compile + lint sweep
just fmt # rustfmt
just test # nextest with coverage instrumentation
just lint-prod # strict production clippy
just ship # validate → bump → changelog → release PR (resumable)The workspace pins a nightly toolchain (rust-toolchain.toml) because the
rustfmt configuration uses unstable options. just toolchain-ensure installs
the pin; just toolchain-sync walks the pin forward safely; the nightly-canary
workflow builds against the floating nightly weekly as an early-warning system.
Projects that prefer stable:
rust-toolchain.toml: setchannel = "stable", dropmirifrom components.rustfmt.toml: deleteunstable_featuresand every option marked nightly-only (imports_granularity,group_imports,wrap_comments,format_code_in_doc_comments,normalize_*,format_macro_*,overflow_delimited_expr,hex_literal_case).- Root
Cargo.toml: addrust-version = "<current stable>"to[workspace.package]; addmsrv = "<same>"toclippy.toml. tier-2.yml: remove the miri job.just goto confirm.
Derived projects can pull scaffolding improvements without merging histories:
git remote add template https://github.com/skyllc-ai/rust-forge-template
git fetch template
git diff template/main -- justfile just/ scripts/ .github/ Cargo.tomlCherry-pick what you want; docs/forge/TEMPLATE_VERSION records the baseline you started
from. Improvements you make to the machinery inside a product repo should land
in the template first (its own CI proves them), then flow down.
Dual-licensed MIT OR Apache-2.0 (the Rust-ecosystem default), so projects
of any license can adopt the scaffolding. Keep the dual license or pass
license=<SPDX-id> to just init: the ceremony rewrites every SPDX header,
Cargo.toml, REUSE.toml, and the LICENSE pointer, then the reuse gate
holds the build red until you drop the matching text into LICENSES/ -
the machine itself enforces a complete relicense.