1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
---
name: rust
description: Use when writing, reviewing, scaffolding, releasing, or measuring coverage on Rust code — routes to references for style, project layout, testing, Dockerfile, and release
---

# Rust

Preferences for writing and shipping Rust. The actual guidance lives
in references — this file routes by task and lists the cross-cutting
principles that apply everywhere.

*This is a self-improving skill. If you used it and it came up short — a missing command, flag, gotcha, or workflow — invoke the `self-improving-skills` skill and follow it before you finish.*

## When to read which reference

| Task | Read |
|------|------|
| Writing or reviewing Rust code | `style.md` |
| Scaffolding a new project | `scaffolding.md` + `binary.md` (CLI) or `server.md` (server) |
| Setting up a Dockerfile for a server | `dockerfile.md` |
| Debugging coverage gaps | `coverage.md` |
| Adding property tests | `property-testing.md` |
| Adding mutation testing | `mutation-testing.md` |
| Wiring `<NAME>_VERSION` into a binary | `versioning.md` |
| Releasing a CLI binary | `binary.md` (release section) |
| Deploying a server | `server.md` (deploy section) + `dockerfile.md` |

## Cross-cutting principles

These apply to every Rust project regardless of shape.

### Edition

`edition = "2024"` for new projects. Bump existing projects when
upstream dependencies require it, not preemptively.

### Project structure

Single crate with both library and binary targets. All domain logic
lives in the library; the binary is a thin shell that parses input,
calls the library, and renders output. `scaffolding.md` covers the
layout in detail.

### Errors

Library errors derive `thiserror::Error` *and* `miette::Diagnostic`.
The diagnostic codes and help text live on the variant itself, so
errors carry their own labels and source spans through tests, other
binaries, and HTTP handlers. Binaries return `miette::Result<()>` from
`main` and call `miette::set_panic_hook()` early.

### Logging

Use `tracing` and `tracing-subscriber` with `EnvFilter`. Never
`println!` for diagnostic output — `println!` belongs to user-facing
program output only.

### Filesystem

Use `fs-err` instead of `std::fs`. Bare `std::fs` errors omit the
path that failed. The Clippy configuration in `style.md` enforces
this.

### Cargo.lock

Commit `Cargo.lock` for binaries (CLIs and servers both). Builds
stay reproducible even though dependency versions in `Cargo.toml`
are unpinned (`"*"`). `cargo update` upgrades to the latest
compatible release without editing `Cargo.toml`.

### Task runner

Use `just`. The `justfile` template is in `scaffolding.md`.

### CI

GitHub Actions, with every `uses:` pinned to a commit SHA and a
version comment (`@<sha> # v4`). Never pin to a moving tag.

### Async runtime

`tokio` with `features = ["full"]` for both CLIs and servers.
Single-threaded runtimes are an opt-in micro-optimization, not a
default.