litclaude-ai 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +369 -0
  4. package/README_ko-KR.md +374 -0
  5. package/RELEASE_CHECKLIST.md +165 -0
  6. package/bin/litclaude-ai.js +643 -0
  7. package/cover.png +0 -0
  8. package/docs/agents.md +67 -0
  9. package/docs/hooks.md +134 -0
  10. package/docs/lsp.md +40 -0
  11. package/docs/migration.md +209 -0
  12. package/docs/workflow-compatibility-audit.md +119 -0
  13. package/generate_cover.py +123 -0
  14. package/package.json +48 -0
  15. package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
  16. package/plugins/litclaude/.lsp.json +13 -0
  17. package/plugins/litclaude/.mcp.json +9 -0
  18. package/plugins/litclaude/agents/boulder-executor.md +12 -0
  19. package/plugins/litclaude/agents/librarian-researcher.md +15 -0
  20. package/plugins/litclaude/agents/oracle-verifier.md +16 -0
  21. package/plugins/litclaude/agents/prometheus-planner.md +13 -0
  22. package/plugins/litclaude/agents/qa-runner.md +16 -0
  23. package/plugins/litclaude/agents/quality-reviewer.md +17 -0
  24. package/plugins/litclaude/bin/litclaude-hook.js +110 -0
  25. package/plugins/litclaude/bin/litclaude-hud.js +271 -0
  26. package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
  27. package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
  28. package/plugins/litclaude/commands/deep-interview.md +21 -0
  29. package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
  30. package/plugins/litclaude/commands/lit-loop.md +40 -0
  31. package/plugins/litclaude/commands/lit-plan.md +35 -0
  32. package/plugins/litclaude/commands/litgoal.md +30 -0
  33. package/plugins/litclaude/commands/review-work.md +35 -0
  34. package/plugins/litclaude/commands/start-work.md +36 -0
  35. package/plugins/litclaude/hooks/hooks.json +54 -0
  36. package/plugins/litclaude/lib/context-pressure.mjs +25 -0
  37. package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
  38. package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
  39. package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
  40. package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
  41. package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
  42. package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
  43. package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
  44. package/plugins/litclaude/lib/workflow-check.mjs +83 -0
  45. package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
  46. package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
  47. package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
  48. package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
  49. package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
  50. package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
  51. package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
  52. package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
  53. package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
  54. package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
  55. package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
  56. package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  57. package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
  58. package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
  59. package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
  60. package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
  61. package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
  62. package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
  63. package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
  64. package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
  65. package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
  66. package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
  67. package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
  68. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
  69. package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
  70. package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
  71. package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
  72. package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
  73. package/plugins/litclaude/skills/programming/SKILL.md +106 -0
  74. package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
  75. package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
  76. package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
  77. package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
  78. package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
  79. package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
  80. package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
  81. package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
  82. package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
  83. package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
  84. package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
  85. package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
  86. package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
  87. package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
  88. package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
  89. package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
  90. package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
  91. package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
  92. package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
  93. package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
  94. package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
  95. package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
  96. package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
  97. package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
  98. package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
  99. package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
  100. package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
  101. package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
  102. package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
  103. package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
  104. package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
  105. package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
  106. package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
  107. package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
  108. package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
  109. package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
  110. package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
  111. package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
  112. package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
  113. package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
  114. package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
  115. package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
  116. package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  117. package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  118. package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
  119. package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
  120. package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
  121. package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
  122. package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
  123. package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  124. package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
  125. package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  126. package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
  127. package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
  128. package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  129. package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  130. package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  131. package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  132. package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
  133. package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
  134. package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
  135. package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  136. package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
  137. package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  138. package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
  139. package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
  140. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  141. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  142. package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
  143. package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  144. package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
  145. package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
  146. package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
  147. package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
  148. package/plugins/litclaude/skills/rules/SKILL.md +66 -0
  149. package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
  150. package/scripts/audit-plan-checkboxes.mjs +37 -0
  151. package/scripts/doctor.mjs +41 -0
  152. package/scripts/inspect-agent-tools.mjs +27 -0
  153. package/scripts/postinstall.mjs +50 -0
  154. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  155. package/scripts/qa-portable-install.sh +136 -0
  156. package/scripts/validate-plugin.mjs +72 -0
@@ -0,0 +1,439 @@
1
+ # Library Defaults — Full Decision Tree
2
+
3
+ The opinionated, audited-in-prod stack for 2026 Rust. Every entry has a one-line rationale and a canonical code snippet so the agent does not have to relearn each library's idioms.
4
+
5
+ ## Async runtime — `tokio`
6
+
7
+ The default. Use `tokio` for new work. Multi-thread runtime unless you have a measured reason to go single-thread.
8
+
9
+ ```rust
10
+ #[tokio::main(flavor = "multi_thread", worker_threads = 8)]
11
+ async fn main() -> anyhow::Result<()> {
12
+ tracing_subscriber::fmt::init();
13
+ run().await
14
+ }
15
+ ```
16
+
17
+ Avoid:
18
+ - `async-std` — unmaintained, last release ages ago. crates.io download counts are misleading because of historical inertia.
19
+ - `smol` — fine for embedded-ish niches; outside that, the ecosystem is on tokio.
20
+ - Mixing runtimes in one binary. Pick one and stay.
21
+
22
+ ## Errors — `anyhow` (apps) + `thiserror` (libs)
23
+
24
+ Application boundaries get `anyhow::Error` with `.context("...")` at every layer that adds meaning. Libraries expose `#[derive(thiserror::Error)]` enums with `#[non_exhaustive]`.
25
+
26
+ ```rust
27
+ // Application code
28
+ use anyhow::Context as _;
29
+
30
+ pub async fn load_config(path: &Path) -> anyhow::Result<Config> {
31
+ let text = tokio::fs::read_to_string(path)
32
+ .await
33
+ .with_context(|| format!("reading config from {}", path.display()))?;
34
+ let cfg: Config = toml::from_str(&text)
35
+ .with_context(|| format!("parsing config at {}", path.display()))?;
36
+ Ok(cfg)
37
+ }
38
+
39
+ // Library code
40
+ #[derive(Debug, thiserror::Error)]
41
+ #[non_exhaustive]
42
+ pub enum ParseError {
43
+ #[error("expected {expected}, found {found} at position {position}")]
44
+ Mismatch { expected: &'static str, found: String, position: usize },
45
+ #[error("unexpected end of input after {context}")]
46
+ UnexpectedEof { context: &'static str },
47
+ #[error(transparent)]
48
+ Io(#[from] std::io::Error),
49
+ }
50
+ ```
51
+
52
+ `#[non_exhaustive]` on enums prevents downstream `match` from breaking when you add variants. `#[error(transparent)]` on a wrapper variant forwards Display + cause to the inner error.
53
+
54
+ ## CLI — `clap` with derive
55
+
56
+ ```rust
57
+ use clap::{Parser, Subcommand};
58
+
59
+ #[derive(Parser, Debug)]
60
+ #[command(author, version, about, long_about = None)]
61
+ struct Cli {
62
+ /// Path to the config file
63
+ #[arg(short, long, env = "MYAPP_CONFIG", default_value = "config.toml")]
64
+ config: PathBuf,
65
+
66
+ /// Enable verbose output (-v, -vv, -vvv)
67
+ #[arg(short, long, action = clap::ArgAction::Count)]
68
+ verbose: u8,
69
+
70
+ #[command(subcommand)]
71
+ command: Command,
72
+ }
73
+
74
+ #[derive(Subcommand, Debug)]
75
+ enum Command {
76
+ /// Run the server
77
+ Serve {
78
+ #[arg(short, long, default_value_t = 8080)]
79
+ port: u16,
80
+ },
81
+ /// Migrate the database
82
+ Migrate {
83
+ #[arg(long)]
84
+ dry_run: bool,
85
+ },
86
+ }
87
+ ```
88
+
89
+ Avoid `structopt` (deprecated, merged into clap), `argh` (less ergonomic), `pico-args` (only when binary size matters more than DX).
90
+
91
+ ## Logging — `tracing` + `tracing-subscriber`
92
+
93
+ Not `log` + `env_logger`. `tracing` supports spans (structured context that follows async tasks) and structured fields - `log` cannot.
94
+
95
+ ```rust
96
+ use tracing::{info, instrument, warn, Level};
97
+ use tracing_subscriber::{fmt, EnvFilter};
98
+
99
+ fn init_tracing() {
100
+ let filter = EnvFilter::try_from_default_env()
101
+ .unwrap_or_else(|_| EnvFilter::new("info,sqlx=warn,hyper=warn"));
102
+ fmt()
103
+ .with_env_filter(filter)
104
+ .with_target(false)
105
+ .with_thread_ids(true)
106
+ .with_line_number(true)
107
+ .compact()
108
+ .init();
109
+ }
110
+
111
+ #[instrument(skip(db), fields(user_id = %user.id))]
112
+ async fn process_user(db: &Pool, user: &User) -> anyhow::Result<()> {
113
+ info!("processing user");
114
+ if user.is_banned() {
115
+ warn!(reason = "banned", "skipping");
116
+ return Ok(());
117
+ }
118
+ // ... body ...
119
+ Ok(())
120
+ }
121
+ ```
122
+
123
+ Replace `println!` with `info!`/`warn!`/`error!`. Replace `eprintln!` with `tracing::error!`.
124
+
125
+ ## Error reporting (binaries) — `color-eyre`
126
+
127
+ For binary `main()`, hook `color-eyre` to give pretty panics + nice `Result` printing:
128
+
129
+ ```rust
130
+ fn main() -> color_eyre::Result<()> {
131
+ color_eyre::install()?;
132
+ tracing_subscriber::fmt::init();
133
+ real_main()
134
+ }
135
+ ```
136
+
137
+ Library code stays on `anyhow`/`thiserror`. `color-eyre` is purely a display layer for the binary.
138
+
139
+ ## Serialization — `serde` + `serde_json`
140
+
141
+ The default for any data crossing a process boundary (file, network, IPC, database column).
142
+
143
+ ```rust
144
+ #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
145
+ #[serde(deny_unknown_fields, rename_all = "snake_case")]
146
+ pub struct ApiResponse {
147
+ pub user_id: UserId,
148
+ pub created_at: jiff::Timestamp,
149
+ #[serde(default, skip_serializing_if = "Option::is_none")]
150
+ pub display_name: Option<String>,
151
+ #[serde(flatten)]
152
+ pub extra: HashMap<String, serde_json::Value>,
153
+ }
154
+ ```
155
+
156
+ `deny_unknown_fields` catches typos in inputs. `rename_all = "snake_case"` aligns with REST/JSON conventions while keeping idiomatic Rust field names. `#[serde(flatten)]` for forward-compatible extra fields.
157
+
158
+ Alternatives:
159
+ - `serde_yaml` (YAML — note: YAML's "deserialize anything" surface is a security trap; prefer JSON/TOML where possible)
160
+ - `toml` (config files)
161
+ - `rmp-serde` (MessagePack — binary, fast)
162
+ - `ciborium` (CBOR)
163
+ - `bincode 2` (binary, smaller; no serde required in v2 but interop fine)
164
+
165
+ ## HTTP client — `reqwest`
166
+
167
+ ```rust
168
+ let client = reqwest::Client::builder()
169
+ .timeout(std::time::Duration::from_secs(30))
170
+ .user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")))
171
+ .https_only(true)
172
+ .pool_max_idle_per_host(8)
173
+ .build()?;
174
+
175
+ #[derive(serde::Deserialize)]
176
+ struct Repo { full_name: String, stargazers_count: u64 }
177
+
178
+ let repo: Repo = client
179
+ .get("https://api.github.com/repos/rust-lang/rust")
180
+ .send().await?
181
+ .error_for_status()?
182
+ .json().await?;
183
+ ```
184
+
185
+ `error_for_status()?` turns 4xx/5xx into `Err`. Always include a User-Agent. `https_only(true)` is a soundness toggle - prevents accidental http:// downgrade.
186
+
187
+ ## Web framework — `axum`
188
+
189
+ ```rust
190
+ use axum::{Router, routing::get, extract::State, response::Json};
191
+ use std::sync::Arc;
192
+
193
+ #[derive(Clone)]
194
+ struct AppState { db: sqlx::PgPool }
195
+
196
+ async fn health(State(state): State<Arc<AppState>>) -> Json<serde_json::Value> {
197
+ let ok = sqlx::query_scalar!("SELECT 1::int4").fetch_one(&state.db).await.is_ok();
198
+ Json(serde_json::json!({ "ok": ok }))
199
+ }
200
+
201
+ #[tokio::main]
202
+ async fn main() -> anyhow::Result<()> {
203
+ tracing_subscriber::fmt::init();
204
+ let state = Arc::new(AppState { db: sqlx::PgPool::connect(&env_db()).await? });
205
+ let app = Router::new()
206
+ .route("/health", get(health))
207
+ .with_state(state)
208
+ .layer(tower_http::trace::TraceLayer::new_for_http())
209
+ .layer(tower_http::compression::CompressionLayer::new());
210
+ let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
211
+ axum::serve(listener, app).await?;
212
+ Ok(())
213
+ }
214
+ ```
215
+
216
+ Avoid `actix-web` (legacy patterns, separate runtime model), `warp` (filter explosion in non-trivial apps), `rocket` (slow release cadence). Pair `axum` with `tower-http` for middleware (trace, compression, CORS, timeout, request-id).
217
+
218
+ ## Database — `sqlx` (compile-time checked SQL)
219
+
220
+ ```rust
221
+ use sqlx::PgPool;
222
+
223
+ #[derive(Debug, sqlx::FromRow)]
224
+ pub struct User { pub id: uuid::Uuid, pub email: String, pub created_at: jiff::Timestamp }
225
+
226
+ pub async fn find_user(pool: &PgPool, email: &str) -> Result<Option<User>, sqlx::Error> {
227
+ sqlx::query_as!(
228
+ User,
229
+ r#"SELECT id, email, created_at as "created_at: jiff::Timestamp"
230
+ FROM users WHERE email = $1"#,
231
+ email
232
+ )
233
+ .fetch_optional(pool)
234
+ .await
235
+ }
236
+ ```
237
+
238
+ `query_as!` checks the SQL against the live database at compile time. To work without a live DB during builds, generate offline metadata: `cargo sqlx prepare`. Commit the resulting `.sqlx/` directory.
239
+
240
+ Avoid `diesel` (sync-first, heavy DSL), raw `tokio-postgres` (loses type checks), `sea-orm` (more magic, less control).
241
+
242
+ For migrations: `sqlx migrate add <name>` + `sqlx::migrate!("./migrations").run(&pool).await?`.
243
+
244
+ ## Time — `jiff`
245
+
246
+ The 2025+ choice. Single crate, sane defaults, civil time / instant / span distinction.
247
+
248
+ ```rust
249
+ use jiff::{Timestamp, Span, ToSpan, Zoned};
250
+
251
+ let now: Timestamp = Timestamp::now();
252
+ let in_one_hour = now.checked_add(1.hour())?;
253
+ let local: Zoned = now.in_tz("Asia/Seoul")?;
254
+ let span: Span = local - some_earlier.in_tz("Asia/Seoul")?;
255
+ ```
256
+
257
+ Avoid `chrono` (old API, generic-heavy, time zone story still painful), `time` crate (split ecosystem, weaker docs). `jiff` is the post-`chrono` consolidation.
258
+
259
+ ## UUID — `uuid` with v7
260
+
261
+ ```rust
262
+ use uuid::Uuid;
263
+
264
+ // v7 for IDs (sortable, time-ordered, monotonic-ish, RFC 9562)
265
+ let id = Uuid::now_v7();
266
+ ```
267
+
268
+ v4 is fine for nonces, v7 for primary keys (better index locality). Never v1 (leaks MAC). Cargo features: `uuid = { version = "1", features = ["v4", "v7", "serde"] }`.
269
+
270
+ ## DataFrames / analytics — `polars`
271
+
272
+ For columnar data, joins, group-by, lazy plans:
273
+
274
+ ```rust
275
+ use polars::prelude::*;
276
+
277
+ let df = LazyCsvReader::new("events.csv")
278
+ .finish()?
279
+ .group_by([col("user_id")])
280
+ .agg([col("amount").sum().alias("total")])
281
+ .sort(["total"], Default::default())
282
+ .collect()?;
283
+ ```
284
+
285
+ The Rust API mirrors the Python one. Use the lazy API by default; materialize with `.collect()` at the end.
286
+
287
+ ## Channels
288
+
289
+ - Single-producer single-consumer or bounded MPSC → `tokio::sync::mpsc` (async) or `flume` (sync + async).
290
+ - Broadcast → `tokio::sync::broadcast`.
291
+ - Watch (latest-value pubsub) → `tokio::sync::watch`.
292
+ - Oneshot → `tokio::sync::oneshot`.
293
+
294
+ Avoid raw `std::sync::mpsc` (sync only, fewer features), `crossbeam-channel` (good but heavier; use only if you need rendezvous semantics).
295
+
296
+ ## Coordinate spaces / 2D math — `euclid`
297
+
298
+ ```rust
299
+ use euclid::{Point2D, Size2D, default::Box2D};
300
+ struct ScreenSpace;
301
+ struct WorldSpace;
302
+
303
+ type ScreenPoint = Point2D<f32, ScreenSpace>;
304
+ type WorldPoint = Point2D<f32, WorldSpace>;
305
+
306
+ let cursor: ScreenPoint = Point2D::new(120.0, 240.0);
307
+ let player: WorldPoint = Point2D::new(3.5, 1.2);
308
+
309
+ // let mistake = cursor + player; // ❌ type error
310
+ ```
311
+
312
+ Generalize the pattern to your own domains (see `references/type-state.md`).
313
+
314
+ ## Property tests — `proptest`
315
+
316
+ ```rust
317
+ use proptest::prelude::*;
318
+
319
+ proptest! {
320
+ #[test]
321
+ fn parse_roundtrips(s in r"[a-zA-Z0-9_-]{1,50}") {
322
+ let parsed = parse(&s).unwrap();
323
+ let back = parsed.to_string();
324
+ prop_assert_eq!(back, s);
325
+ }
326
+ }
327
+ ```
328
+
329
+ Avoid `quickcheck` (older, less ergonomic). proptest gives shrinking + regression corpus + integration with `criterion`.
330
+
331
+ ## Snapshot tests — `insta`
332
+
333
+ ```rust
334
+ #[test]
335
+ fn renders_help() {
336
+ let output = render(&example_input());
337
+ insta::assert_snapshot!(output);
338
+ }
339
+
340
+ #[test]
341
+ fn serializes_well() {
342
+ insta::assert_json_snapshot!(serializable_value());
343
+ }
344
+ ```
345
+
346
+ `cargo insta review` (after `cargo install cargo-insta`) — interactive review of changed snapshots.
347
+
348
+ ## Benchmarks — `criterion`
349
+
350
+ Stable Rust friendly (no nightly `#[bench]`).
351
+
352
+ ```rust
353
+ use criterion::{black_box, criterion_group, criterion_main, Criterion};
354
+
355
+ fn bench_parse(c: &mut Criterion) {
356
+ let input = std::fs::read_to_string("samples/large.txt").unwrap();
357
+ c.bench_function("parse_large", |b| b.iter(|| parse(black_box(&input))));
358
+ }
359
+
360
+ criterion_group!(benches, bench_parse);
361
+ criterion_main!(benches);
362
+ ```
363
+
364
+ Run with `cargo bench`. HTML reports under `target/criterion/`. Pair with `cargo bench -- --save-baseline main` then `--baseline main` for comparison.
365
+
366
+ ## Concurrency model — `loom`
367
+
368
+ For lock-free or atomic-heavy code (channels, refcounts, hazard pointers). See `references/concurrency.md` for the full pattern.
369
+
370
+ ## Arena allocator — `bumpalo`
371
+
372
+ ```rust
373
+ use bumpalo::Bump;
374
+
375
+ let bump = Bump::new();
376
+ let node = bump.alloc(Node { value: 42, next: None });
377
+ let s: &str = bump.alloc_str("hello");
378
+ // All allocations freed at once when `bump` drops.
379
+ ```
380
+
381
+ For parser nodes, AST construction, per-request scratch. Outperforms heap allocation for short-lived owned data by an order of magnitude.
382
+
383
+ ## Web client (browser, WASM-bound) — `gloo` ecosystem
384
+
385
+ If targeting WASM browser, use `gloo-net` for fetch and `gloo-storage` for localStorage; not `web-sys` directly unless you need DOM-level APIs.
386
+
387
+ ## Lazy statics — `std::sync::LazyLock` (since 1.80)
388
+
389
+ ```rust
390
+ use std::sync::LazyLock;
391
+ static CONFIG: LazyLock<Config> = LazyLock::new(|| Config::load_from_env().unwrap());
392
+ ```
393
+
394
+ Avoid `lazy_static!` (macro-heavy, predates std), `once_cell` (now in std as `LazyLock`/`OnceLock`).
395
+
396
+ ## Hash maps — `std::collections::HashMap` + `ahash` for hot paths
397
+
398
+ ```rust
399
+ use std::collections::HashMap;
400
+ use ahash::RandomState;
401
+
402
+ type FastMap<K, V> = HashMap<K, V, RandomState>;
403
+ let mut counters: FastMap<String, u64> = FastMap::default();
404
+ ```
405
+
406
+ `HashMap` defaults to SipHash (DoS-resistant). For internal hot loops where you trust the keys, `ahash` is 2-5x faster.
407
+
408
+ For sorted iteration, use `BTreeMap`. For small keys with known small N, `Vec<(K, V)>` may beat both.
409
+
410
+ ## File I/O — `tokio::fs` (async) or `std::fs` (sync utility)
411
+
412
+ ```rust
413
+ let contents = tokio::fs::read_to_string("data.json").await?;
414
+ ```
415
+
416
+ For large files: `tokio::fs::File` + `tokio::io::BufReader`. For random access, `memmap2` (with the unsafe-discipline wrappers).
417
+
418
+ ## Decision tree
419
+
420
+ ```
421
+ Need to ship the thing?
422
+ ├── HTTP server → axum + sqlx + tracing + jiff + tokio
423
+ ├── HTTP client → reqwest (+ tokio)
424
+ ├── CLI → clap + color-eyre + tracing + indicatif (progress) + dialoguer (prompts)
425
+ ├── TUI → ratatui + crossterm
426
+ ├── Background worker → tokio + ETL → polars + duckdb
427
+ ├── Game / graphics → wgpu + winit + euclid (or bevy if you want the engine)
428
+ ├── WASM front-end → leptos (or dioxus / yew) + wasm-bindgen + gloo
429
+ ├── Embedded → embassy (async on bare metal)
430
+ ├── FFI to C / Python → cxx (C++) / pyo3 (Python) / cbindgen (header gen)
431
+ └── Just a script → rust-script (see one-liners.md)
432
+ ```
433
+
434
+ When in doubt, search crates.io for the latest version, then check:
435
+ 1. Is it maintained? (`cargo deny check` will scream if it's yanked or unmaintained)
436
+ 2. Does it have `serde` feature? (boundary types should always serde)
437
+ 3. Does it have `tokio` integration? (avoid runtime mixing)
438
+ 4. Is it on `tokio::io::AsyncRead`/`AsyncWrite` (the std for async I/O)?
439
+ 5. Are there safety-critical `unsafe` regions? If yes, has the author shipped miri proofs?