scaffold-rust · git:20260530.d3be4dd · 2026-05-30 · sha256 5560aa9cec84d640
scaffold-rust git:20260530.d3be4ddA
Immutable. This exact content never changes and is served at /api/v1/blob/5560aa9cec84d640.
---
name: scaffold-rust
description: >
Scaffold a complete Rust project with CI/CD, release pipeline, and sr.yaml.
Uses cargo as the native build system. Loads on top of scaffold-project (run
that first for cross-language standard files). Use when creating a new
Rust CLI, library, or workspace, or when the user mentions "new Rust project",
"cargo init", or "Rust scaffold". Do NOT use for Go, Python, Node, or Terraform
projects; use the matching scaffold-<lang> skill.
allowed-tools: Read, Grep, Glob, Edit, Write, Bash(cargo *), Bash(cross *), Bash(git *)
user-invocable: true
metadata:
title: Scaffold Rust Project
category: development
order: 10
---
# Scaffold Rust Project
Generate a production-ready Rust project following established CI/CD patterns. Read the `scaffold-project` skill first for standard files (README, AGENTS.md, LICENSE, CONTRIBUTING.md, llms.txt).
## When to Use
- Creating a new Rust CLI tool, library, or workspace
- Adding CI/CD to an existing Rust project missing workflows
- Standardizing a Rust project to match org conventions
## Generated Files
### `.github/workflows/ci.yml`
```yaml
name: CI
on:
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo check --workspace
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --workspace -- -D warnings
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --workspace
```
### `.github/workflows/release.yml`
```yaml
name: Release
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: release
cancel-in-progress: false
jobs:
ci:
if: github.actor != 'sr[bot]'
uses: ./.github/workflows/ci.yml
release:
needs: ci
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.SR_RELEASER_APP_ID }}
private-key: ${{ secrets.SR_RELEASER_PRIVATE_KEY }}
repositories: ${{ github.event.repository.name }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- uses: urmzd/sr@v8
id: sr
with:
github-token: ${{ steps.app-token.outputs.token }}
outputs:
released: ${{ steps.sr.outputs.released }}
tag: ${{ steps.sr.outputs.tag }}
version: ${{ steps.sr.outputs.version }}
build:
needs: release
if: needs.release.outputs.released == 'true'
name: Build (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
permissions:
contents: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
cross: false
- target: aarch64-unknown-linux-gnu
runner: ubuntu-latest
cross: true
- target: x86_64-unknown-linux-musl
runner: ubuntu-latest
cross: false
- target: aarch64-unknown-linux-musl
runner: ubuntu-latest
cross: true
- target: x86_64-apple-darwin
runner: macos-15-intel
cross: false
- target: aarch64-apple-darwin
runner: macos-15
cross: false
- target: x86_64-pc-windows-msvc
runner: windows-latest
cross: false
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.release.outputs.tag }}
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install musl-tools
if: matrix.target == 'x86_64-unknown-linux-musl'
run: sudo apt-get update && sudo apt-get install -y musl-tools
- name: Install cross
if: matrix.cross
run: cargo install cross --locked
- name: Build
shell: bash
run: |
BIN_NAME="${{ github.event.repository.name }}"
if [ "${{ matrix.cross }}" = "true" ]; then
cross build --release --target ${{ matrix.target }}
else
cargo build --release --target ${{ matrix.target }}
fi
- name: Upload to release
shell: bash
run: |
BIN_NAME="${{ github.event.repository.name }}"
TAG="${{ needs.release.outputs.tag }}"
if [ -f "target/${{ matrix.target }}/release/${BIN_NAME}.exe" ]; then
cp "target/${{ matrix.target }}/release/${BIN_NAME}.exe" "${BIN_NAME}-${{ matrix.target }}.exe"
gh release upload "$TAG" "${BIN_NAME}-${{ matrix.target }}.exe" --clobber
else
cp "target/${{ matrix.target }}/release/${BIN_NAME}" "${BIN_NAME}-${{ matrix.target }}"
chmod +x "${BIN_NAME}-${{ matrix.target }}"
gh release upload "$TAG" "${BIN_NAME}-${{ matrix.target }}" --clobber
fi
# Uncomment for crates.io publishing:
# publish:
# needs: release
# if: needs.release.outputs.released == 'true'
# runs-on: ubuntu-latest
# permissions:
# id-token: write
# contents: read
# steps:
# - uses: actions/checkout@v4
# with:
# ref: ${{ needs.release.outputs.tag }}
# - uses: dtolnay/rust-toolchain@stable
# - uses: Swatinem/rust-cache@v2
# - id: auth
# uses: rust-lang/crates-io-auth-action@v1
# - name: Publish
# env:
# CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
# run: cargo publish --allow-dirty
```
### `sr.yaml`
See `sync-release` skill for full sr.yaml reference.
```yaml
git:
tag_prefix: "v"
floating_tag: true
commit:
types:
minor: [feat]
patch: [fix, perf, refactor]
none: [docs, revert, chore, ci, test, build, style]
changelog:
file: CHANGELOG.md
packages:
- path: .
version_files:
- Cargo.toml
stage_files:
- Cargo.lock
publish:
type: cargo
workspace: true # iterate [workspace].members in declaration order
```
For workspaces, sr auto-discovers member `Cargo.toml` files from the root. List `[workspace].members` in dependency order (leaf crates first) so `cargo publish` reaches crates.io in the right order.
### Common Commands
Cargo is the native build system:
```sh
cargo fmt --all # format
cargo clippy --workspace -- -D warnings # lint
cargo test --workspace # test
cargo build --release # build
cargo run -- <args> # run
```
Set up git hooks during init: `git config core.hooksPath .githooks && cargo fetch`
## Gotchas
- Always use `--workspace` for clippy/test/check in multi-crate repos
- `cross` is only needed for ARM targets (`aarch64-*`); x86 musl just needs `musl-tools`
- `macos-15-intel` for x86_64 Darwin, `macos-15` for aarch64 Darwin
- List `[workspace].members` in dependency order (leaf crates first) -- the cargo publisher iterates in that order, and crates.io index propagation (~30-60s) is handled via retry inside sr
- Use `-p <crate-name>` for `cargo build` when the workspace has multiple binaries (publish is handled by the typed publisher)
- `cancel-in-progress: false` on release workflow to prevent partial releases
## Workspace Member Files
Each publishable workspace member (`crates/<name>/`) must have:
| File | Content |
|------|---------|
| `LICENSE` | Copy of root `LICENSE` |
| `README.md` | Crate name heading, description from `Cargo.toml`, link to workspace repo |
When scaffolding a new workspace member, generate both files. See `scaffold-project` for the README template.
Skip `examples/` members -- they are not published to crates.io.