red64-cli 0.5.0 → 0.6.0

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 (62) hide show
  1. package/README.md +64 -58
  2. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  3. package/dist/components/screens/StartScreen.js +2 -2
  4. package/dist/components/screens/StartScreen.js.map +1 -1
  5. package/dist/services/AgentInvoker.js +4 -4
  6. package/dist/services/AgentInvoker.js.map +1 -1
  7. package/dist/services/ClaudeHealthCheck.d.ts +5 -0
  8. package/dist/services/ClaudeHealthCheck.d.ts.map +1 -1
  9. package/dist/services/ClaudeHealthCheck.js +43 -5
  10. package/dist/services/ClaudeHealthCheck.js.map +1 -1
  11. package/dist/services/index.d.ts +1 -1
  12. package/dist/services/index.d.ts.map +1 -1
  13. package/dist/services/index.js +1 -1
  14. package/dist/services/index.js.map +1 -1
  15. package/framework/stacks/c/code-quality.md +326 -0
  16. package/framework/stacks/c/coding-style.md +347 -0
  17. package/framework/stacks/c/conventions.md +513 -0
  18. package/framework/stacks/c/error-handling.md +350 -0
  19. package/framework/stacks/c/feedback.md +158 -0
  20. package/framework/stacks/c/memory-safety.md +408 -0
  21. package/framework/stacks/c/tech.md +122 -0
  22. package/framework/stacks/c/testing.md +472 -0
  23. package/framework/stacks/cpp/code-quality.md +282 -0
  24. package/framework/stacks/cpp/coding-style.md +363 -0
  25. package/framework/stacks/cpp/conventions.md +420 -0
  26. package/framework/stacks/cpp/error-handling.md +264 -0
  27. package/framework/stacks/cpp/feedback.md +104 -0
  28. package/framework/stacks/cpp/memory-safety.md +351 -0
  29. package/framework/stacks/cpp/tech.md +160 -0
  30. package/framework/stacks/cpp/testing.md +323 -0
  31. package/framework/stacks/java/code-quality.md +357 -0
  32. package/framework/stacks/java/coding-style.md +400 -0
  33. package/framework/stacks/java/conventions.md +437 -0
  34. package/framework/stacks/java/error-handling.md +408 -0
  35. package/framework/stacks/java/feedback.md +180 -0
  36. package/framework/stacks/java/tech.md +126 -0
  37. package/framework/stacks/java/testing.md +485 -0
  38. package/framework/stacks/javascript/async-patterns.md +216 -0
  39. package/framework/stacks/javascript/code-quality.md +182 -0
  40. package/framework/stacks/javascript/coding-style.md +293 -0
  41. package/framework/stacks/javascript/conventions.md +268 -0
  42. package/framework/stacks/javascript/error-handling.md +216 -0
  43. package/framework/stacks/javascript/feedback.md +80 -0
  44. package/framework/stacks/javascript/tech.md +114 -0
  45. package/framework/stacks/javascript/testing.md +209 -0
  46. package/framework/stacks/loco/code-quality.md +156 -0
  47. package/framework/stacks/loco/coding-style.md +247 -0
  48. package/framework/stacks/loco/error-handling.md +225 -0
  49. package/framework/stacks/loco/feedback.md +35 -0
  50. package/framework/stacks/loco/loco.md +342 -0
  51. package/framework/stacks/loco/structure.md +193 -0
  52. package/framework/stacks/loco/tech.md +129 -0
  53. package/framework/stacks/loco/testing.md +211 -0
  54. package/framework/stacks/rust/code-quality.md +370 -0
  55. package/framework/stacks/rust/coding-style.md +475 -0
  56. package/framework/stacks/rust/conventions.md +430 -0
  57. package/framework/stacks/rust/error-handling.md +399 -0
  58. package/framework/stacks/rust/feedback.md +152 -0
  59. package/framework/stacks/rust/memory-safety.md +398 -0
  60. package/framework/stacks/rust/tech.md +121 -0
  61. package/framework/stacks/rust/testing.md +528 -0
  62. package/package.json +14 -2
@@ -0,0 +1,398 @@
1
+ # Memory Safety Patterns
2
+
3
+ Ownership, borrowing, lifetimes, and safe concurrency patterns for Rust applications. Guidelines for when and how to use `unsafe`.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Ownership is the foundation**: Understand move semantics before reaching for `Clone`
10
+ - **Borrow, do not copy**: Pass references by default; clone only when necessary
11
+ - **Minimize unsafe**: Every `unsafe` block is a contract you must uphold manually
12
+ - **Concurrency through types**: `Arc`, `Mutex`, and channels prevent data races at compile time
13
+
14
+ ---
15
+
16
+ ## Ownership and Borrowing
17
+
18
+ ### The Three Rules
19
+
20
+ 1. Each value has exactly one owner
21
+ 2. When the owner goes out of scope, the value is dropped
22
+ 3. You can have either one mutable reference OR any number of immutable references
23
+
24
+ ```rust
25
+ // GOOD: Borrowing -- no allocation, no move
26
+ fn process_name(name: &str) -> String {
27
+ name.trim().to_uppercase()
28
+ }
29
+
30
+ let name = String::from(" Alice ");
31
+ let processed = process_name(&name); // Borrows name
32
+ println!("{name}"); // name is still valid
33
+
34
+ // GOOD: Moving when ownership transfer is intentional
35
+ fn consume_request(req: Request) -> Response {
36
+ // req is owned here, dropped at end of function
37
+ Response::from(req)
38
+ }
39
+
40
+ // BAD: Unnecessary clone to satisfy borrow checker
41
+ fn process_name_bad(name: String) -> String {
42
+ name.trim().to_uppercase()
43
+ }
44
+
45
+ let name = String::from(" Alice ");
46
+ let processed = process_name_bad(name.clone()); // Wasteful clone
47
+ ```
48
+
49
+ ### Clone vs Borrow Decision
50
+
51
+ | Situation | Use | Reason |
52
+ |---|---|---|
53
+ | Reading data | `&T` | Zero cost, no allocation |
54
+ | Modifying data | `&mut T` | Exclusive access, no allocation |
55
+ | Transferring ownership | `T` (move) | Clear ownership transfer |
56
+ | Shared ownership needed | `Arc<T>` | Multiple owners, reference counted |
57
+ | Small Copy types (`i32`, `bool`) | Copy | Trivially cheap |
58
+ | Data needed beyond borrow scope | `Clone` | Only when lifetime cannot work |
59
+
60
+ ```rust
61
+ // GOOD: Borrow for read access
62
+ fn total_price(items: &[OrderItem]) -> Decimal {
63
+ items.iter().map(|i| i.price).sum()
64
+ }
65
+
66
+ // GOOD: Clone when data must outlive the borrow
67
+ fn spawn_background_task(config: &Config) {
68
+ let config = config.clone(); // Clone needed: task outlives the borrow
69
+ tokio::spawn(async move {
70
+ process_with_config(&config).await;
71
+ });
72
+ }
73
+
74
+ // BAD: Clone when a reference would work
75
+ fn total_price_bad(items: Vec<OrderItem>) -> Decimal {
76
+ items.iter().map(|i| i.price).sum()
77
+ // items is moved in and dropped -- caller loses access
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Lifetime Annotations
84
+
85
+ ### When You Need Them
86
+
87
+ Lifetimes are needed when the compiler cannot infer the relationship between input and output references:
88
+
89
+ ```rust
90
+ // GOOD: Lifetime ties output reference to input
91
+ fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
92
+ if a.len() >= b.len() { a } else { b }
93
+ }
94
+
95
+ // GOOD: Struct with borrowed data
96
+ struct Request<'a> {
97
+ path: &'a str,
98
+ headers: &'a [(String, String)],
99
+ }
100
+
101
+ // GOOD: Lifetime elision -- compiler infers this
102
+ fn first_word(s: &str) -> &str {
103
+ s.split_whitespace().next().unwrap_or("")
104
+ }
105
+ // Equivalent to: fn first_word<'a>(s: &'a str) -> &'a str
106
+
107
+ // BAD: Storing references when you should own
108
+ struct UserCache {
109
+ users: Vec<&str>, // Dangling reference risk
110
+ }
111
+
112
+ // GOOD: Own the data in long-lived structs
113
+ struct UserCache {
114
+ users: Vec<String>,
115
+ }
116
+ ```
117
+
118
+ ### Lifetime Elision Rules
119
+
120
+ The compiler automatically infers lifetimes when:
121
+
122
+ 1. Each reference parameter gets its own lifetime
123
+ 2. If there is exactly one input lifetime, it is assigned to all output lifetimes
124
+ 3. If there is a `&self` or `&mut self`, its lifetime is assigned to all output lifetimes
125
+
126
+ ```rust
127
+ // All of these are equivalent (elision applies):
128
+ fn trim(s: &str) -> &str { ... }
129
+ fn trim<'a>(s: &'a str) -> &'a str { ... }
130
+
131
+ // Elision does NOT apply here (multiple inputs, no self):
132
+ // Must annotate explicitly
133
+ fn pick<'a>(a: &'a str, b: &str) -> &'a str { ... }
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Shared Ownership: `Arc<Mutex<T>>`
139
+
140
+ ### Sharing State Across Async Tasks
141
+
142
+ ```rust
143
+ use std::sync::Arc;
144
+ use tokio::sync::Mutex;
145
+
146
+ // GOOD: Arc<Mutex<T>> for shared mutable state
147
+ #[derive(Clone)]
148
+ struct AppState {
149
+ db: PgPool,
150
+ cache: Arc<Mutex<HashMap<String, CachedValue>>>,
151
+ }
152
+
153
+ async fn get_cached_or_fetch(state: &AppState, key: &str) -> Result<String> {
154
+ // Check cache first
155
+ {
156
+ let cache = state.cache.lock().await;
157
+ if let Some(value) = cache.get(key) {
158
+ return Ok(value.data.clone());
159
+ }
160
+ } // Lock is dropped here
161
+
162
+ // Fetch and cache
163
+ let value = fetch_from_db(&state.db, key).await?;
164
+ {
165
+ let mut cache = state.cache.lock().await;
166
+ cache.insert(key.to_string(), CachedValue { data: value.clone() });
167
+ }
168
+ Ok(value)
169
+ }
170
+ ```
171
+
172
+ ### Choosing the Right Synchronization Primitive
173
+
174
+ | Primitive | Use Case |
175
+ |---|---|
176
+ | `Arc<T>` | Shared immutable data across threads |
177
+ | `Arc<Mutex<T>>` | Shared mutable data, low contention |
178
+ | `Arc<RwLock<T>>` | Shared data, many readers, few writers |
179
+ | `tokio::sync::Mutex` | Holding lock across `.await` points |
180
+ | `std::sync::Mutex` | Short critical sections, no `.await` inside |
181
+ | `tokio::sync::mpsc` | Message passing between tasks |
182
+ | `tokio::sync::watch` | Single-producer, multi-consumer broadcast |
183
+ | `dashmap::DashMap` | Concurrent hashmap, high contention |
184
+
185
+ ```rust
186
+ // GOOD: Use tokio::sync::Mutex when holding across .await
187
+ let data = state.cache.lock().await; // tokio Mutex
188
+ let result = fetch_something(&data).await; // .await while holding lock is OK
189
+
190
+ // BAD: std::sync::Mutex across .await points
191
+ let data = state.cache.lock().unwrap(); // std Mutex
192
+ let result = fetch_something(&data).await; // BLOCKS the runtime thread!
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Interior Mutability
198
+
199
+ ### `Cell` and `RefCell`
200
+
201
+ ```rust
202
+ use std::cell::{Cell, RefCell};
203
+
204
+ // Cell: for Copy types, zero overhead
205
+ struct Counter {
206
+ count: Cell<u32>,
207
+ }
208
+
209
+ impl Counter {
210
+ fn increment(&self) { // Note: &self, not &mut self
211
+ self.count.set(self.count.get() + 1);
212
+ }
213
+ }
214
+
215
+ // RefCell: for non-Copy types, runtime borrow checking
216
+ struct Logger {
217
+ messages: RefCell<Vec<String>>,
218
+ }
219
+
220
+ impl Logger {
221
+ fn log(&self, msg: String) {
222
+ self.messages.borrow_mut().push(msg);
223
+ }
224
+
225
+ fn dump(&self) -> Vec<String> {
226
+ self.messages.borrow().clone()
227
+ }
228
+ }
229
+
230
+ // WARNING: RefCell panics on double mutable borrow at runtime
231
+ // BAD: This will panic
232
+ fn bad_refcell() {
233
+ let data = RefCell::new(vec![1, 2, 3]);
234
+ let mut a = data.borrow_mut();
235
+ let mut b = data.borrow_mut(); // PANIC: already borrowed mutably
236
+ }
237
+ ```
238
+
239
+ ### When to Use Which
240
+
241
+ | Type | Thread-safe? | Overhead | Use Case |
242
+ |---|---|---|---|
243
+ | `Cell<T>` | No | Zero | Single-thread, Copy types |
244
+ | `RefCell<T>` | No | Runtime check | Single-thread, non-Copy |
245
+ | `Mutex<T>` | Yes | Lock | Multi-thread |
246
+ | `RwLock<T>` | Yes | Lock | Multi-thread, read-heavy |
247
+ | `AtomicU64` etc. | Yes | Atomic op | Counters, flags |
248
+
249
+ ---
250
+
251
+ ## Pin and Self-Referential Types
252
+
253
+ ### When Pin Is Needed
254
+
255
+ Pin is required for self-referential types (most commonly, async futures):
256
+
257
+ ```rust
258
+ use std::pin::Pin;
259
+ use std::future::Future;
260
+
261
+ // GOOD: Returning pinned futures (common in trait methods)
262
+ trait Service {
263
+ fn call(&self, req: Request) -> Pin<Box<dyn Future<Output = Response> + Send + '_>>;
264
+ }
265
+
266
+ impl Service for MyService {
267
+ fn call(&self, req: Request) -> Pin<Box<dyn Future<Output = Response> + Send + '_>> {
268
+ Box::pin(async move {
269
+ // async body
270
+ Response::ok()
271
+ })
272
+ }
273
+ }
274
+
275
+ // In most application code, you do NOT need Pin directly.
276
+ // async/await handles it automatically.
277
+ async fn handle_request(req: Request) -> Response {
278
+ // The compiler pins the future for you
279
+ Response::ok()
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Unsafe Guidelines
286
+
287
+ ### Rules for `unsafe` Code
288
+
289
+ 1. **Minimize scope**: Keep `unsafe` blocks as small as possible
290
+ 2. **Document invariants**: Explain why the unsafe operation is sound
291
+ 3. **Test with Miri**: Run `cargo +nightly miri test` on all unsafe code
292
+ 4. **Encapsulate**: Wrap unsafe code in a safe API
293
+
294
+ ```rust
295
+ // GOOD: Minimal unsafe scope with documented invariants
296
+ /// Returns a reference to the element at `index` without bounds checking.
297
+ ///
298
+ /// # Safety
299
+ ///
300
+ /// The caller must ensure that `index < self.len()`.
301
+ pub unsafe fn get_unchecked(&self, index: usize) -> &T {
302
+ // SAFETY: Caller guarantees index is in bounds.
303
+ unsafe { self.data.get_unchecked(index) }
304
+ }
305
+
306
+ // GOOD: Safe wrapper around unsafe
307
+ pub fn get(&self, index: usize) -> Option<&T> {
308
+ if index < self.len() {
309
+ // SAFETY: We just checked that index < len.
310
+ Some(unsafe { self.get_unchecked(index) })
311
+ } else {
312
+ None
313
+ }
314
+ }
315
+
316
+ // BAD: Large unsafe block with no documentation
317
+ unsafe {
318
+ let ptr = data.as_ptr();
319
+ let len = data.len();
320
+ let slice = std::slice::from_raw_parts(ptr, len);
321
+ let result = process(slice);
322
+ std::ptr::copy_nonoverlapping(result.as_ptr(), output.as_mut_ptr(), result.len());
323
+ output.set_len(result.len());
324
+ }
325
+ ```
326
+
327
+ ### When Unsafe Is Justified
328
+
329
+ | Use Case | Justification |
330
+ |---|---|
331
+ | FFI (calling C code) | No safe alternative |
332
+ | Performance-critical inner loops | Measured, benchmarked, significant gain |
333
+ | Implementing data structures | Self-referential or intrusive structures |
334
+ | Hardware/OS interaction | Low-level system programming |
335
+
336
+ ### When Unsafe Is NOT Justified
337
+
338
+ | Use Case | Safe Alternative |
339
+ |---|---|
340
+ | "The borrow checker is annoying" | Refactor ownership, use `Arc`/`Rc` |
341
+ | Skip bounds checking "for speed" | Profile first; usually negligible |
342
+ | Transmute between types | Use `From`/`Into` or `bytemuck` |
343
+ | Global mutable state | Use `once_cell::sync::Lazy` or `std::sync::OnceLock` |
344
+
345
+ ---
346
+
347
+ ## Common Ownership Patterns
348
+
349
+ ### Axum State Sharing
350
+
351
+ ```rust
352
+ // GOOD: Shared application state with Axum
353
+ #[derive(Clone)]
354
+ struct AppState {
355
+ db: PgPool, // PgPool is already Arc internally
356
+ config: Arc<Config>, // Immutable shared config
357
+ rate_limiter: Arc<Mutex<RateLimiter>>, // Mutable shared state
358
+ }
359
+
360
+ async fn create_app() -> Router {
361
+ let state = AppState {
362
+ db: PgPool::connect(&db_url).await.unwrap(),
363
+ config: Arc::new(Config::from_env()),
364
+ rate_limiter: Arc::new(Mutex::new(RateLimiter::new())),
365
+ };
366
+
367
+ Router::new()
368
+ .route("/users", post(create_user))
369
+ .with_state(state)
370
+ }
371
+
372
+ async fn create_user(
373
+ State(state): State<AppState>,
374
+ Json(data): Json<CreateUserRequest>,
375
+ ) -> Result<Json<UserResponse>, AppError> {
376
+ // state.db is cheaply cloned (Arc internally)
377
+ let user = insert_user(&state.db, &data).await?;
378
+ Ok(Json(UserResponse::from(user)))
379
+ }
380
+ ```
381
+
382
+ ---
383
+
384
+ ## Anti-Patterns
385
+
386
+ | Anti-Pattern | Problem | Correct Approach |
387
+ |---|---|---|
388
+ | `clone()` to silence borrow checker | Hidden allocations, hides design issues | Refactor to proper ownership or use `Arc` |
389
+ | `Rc` in async code | Not `Send`, cannot cross `.await` | Use `Arc` in async contexts |
390
+ | `std::sync::Mutex` across `.await` | Blocks runtime thread | Use `tokio::sync::Mutex` |
391
+ | Large `unsafe` blocks | Hard to audit, likely unsound | Minimize scope, document each operation |
392
+ | `'static` lifetime everywhere | Prevents borrowing, forces allocation | Use proper lifetime parameters |
393
+ | `RefCell` in multi-threaded code | Not thread-safe, compiles but panics | Use `Mutex` or `RwLock` |
394
+ | Leaking memory with `Box::leak` | Never reclaimed | Use `Arc` or `OnceLock` for global state |
395
+
396
+ ---
397
+
398
+ _Rust's ownership model is not a constraint to work around -- it is a design tool. Lean into it, and your programs will be correct by construction._
@@ -0,0 +1,121 @@
1
+ # Technology Stack
2
+
3
+ ## Architecture
4
+
5
+ Modern Rust application with async-first design. Axum or Actix-web as web framework, PostgreSQL for persistence, Redis for caching, Tokio as async runtime, Docker for deployment.
6
+
7
+ ---
8
+
9
+ ## Core Technologies
10
+
11
+ - **Language**: Rust stable (Edition 2024, 1.85+)
12
+ - **Build System**: Cargo (with cargo-nextest for testing)
13
+ - **Web Framework**: Axum (default) or Actix-web (high-throughput)
14
+ - **Async Runtime**: Tokio (multi-threaded)
15
+ - **Database**: PostgreSQL with SQLx (async, compile-time checked)
16
+ - **Serialization**: serde + serde_json
17
+
18
+ ---
19
+
20
+ ## Key Libraries
21
+
22
+ ### Web & API
23
+ - **Axum**: Tower-based web framework, excellent DX, Tokio ecosystem native
24
+ - **Actix-web**: Actor-based, highest raw throughput for extreme concurrency
25
+ - **Tower**: Middleware and service abstractions (used by Axum)
26
+ - **tower-http**: HTTP-specific middleware (CORS, compression, tracing)
27
+
28
+ ### Database & Storage
29
+ - **SQLx**: Async, compile-time verified SQL queries (PostgreSQL, MySQL, SQLite)
30
+ - **Diesel**: Sync ORM with strong type safety and migration system
31
+ - **SeaORM**: Async ORM built on SQLx, ActiveRecord-style
32
+ - **deadpool**: Connection pooling for async database drivers
33
+
34
+ ### Serialization & Validation
35
+ - **serde**: Derive-based serialization/deserialization framework
36
+ - **serde_json**: JSON support
37
+ - **validator**: Struct validation with derive macros
38
+ - **utoipa**: OpenAPI documentation generation from code
39
+
40
+ ### Error Handling
41
+ - **thiserror**: Derive macro for custom error types (libraries)
42
+ - **anyhow**: Ergonomic error handling for applications
43
+ - **miette**: Diagnostic error reporting with source spans
44
+
45
+ ### CLI
46
+ - **clap**: Command-line argument parser with derive macros
47
+ - **dialoguer**: Interactive prompts
48
+ - **indicatif**: Progress bars and spinners
49
+
50
+ ### Observability
51
+ - **tracing**: Structured, async-aware logging and diagnostics
52
+ - **tracing-subscriber**: Log formatting and filtering
53
+ - **opentelemetry**: Distributed tracing integration
54
+
55
+ ### Testing
56
+ - **cargo test / cargo-nextest**: Test execution
57
+ - **mockall**: Trait-based mocking framework
58
+ - **proptest**: Property-based testing
59
+ - **wiremock**: HTTP mock server for integration tests
60
+ - **rstest**: Fixture and parametrize support
61
+
62
+ ---
63
+
64
+ ## Development Environment
65
+
66
+ ### Required Tools
67
+ - Rust stable 1.85+ (Edition 2024)
68
+ - Cargo (bundled with rustup)
69
+ - PostgreSQL 16+
70
+ - Redis 7+
71
+ - Docker & Docker Compose
72
+
73
+ ### Common Commands
74
+ ```bash
75
+ # Environment setup
76
+ rustup update stable # Update toolchain
77
+ cargo build # Build project
78
+ cargo build --release # Release build
79
+
80
+ # Dev server (Axum example)
81
+ cargo run # Run application
82
+ cargo watch -x run # Auto-reload on changes
83
+
84
+ # Tests
85
+ cargo test # All tests
86
+ cargo nextest run # Faster parallel test runner
87
+ cargo test --doc # Doctests only
88
+
89
+ # Code quality
90
+ cargo clippy -- -D warnings # Lint (deny warnings)
91
+ cargo fmt # Format
92
+ cargo fmt -- --check # Verify formatting
93
+
94
+ # Database (SQLx)
95
+ sqlx migrate run # Apply migrations
96
+ sqlx migrate add <name> # Create new migration
97
+ sqlx prepare # Generate offline query data
98
+
99
+ # Docker
100
+ docker compose up -d # Start services
101
+ docker compose logs -f app # Follow app logs
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Key Technical Decisions
107
+
108
+ | Decision | Rationale |
109
+ |----------|-----------|
110
+ | **Axum over Actix-web** | Better DX, Tokio-native, Tower middleware ecosystem, most adopted since 2023 |
111
+ | **SQLx over Diesel** | Async-native, compile-time SQL verification, no DSL learning curve |
112
+ | **Tokio runtime** | Industry standard, largest async ecosystem, multi-threaded by default |
113
+ | **thiserror + anyhow** | thiserror for library error types, anyhow for application-level propagation |
114
+ | **tracing over log** | Structured, span-based, async-aware, OpenTelemetry compatible |
115
+ | **serde for serialization** | Universal Rust standard, zero-cost abstractions, derive macros |
116
+ | **cargo-nextest** | Faster parallel execution, better output, retries support |
117
+ | **Edition 2024** | Latest stable edition with improved ergonomics and safety defaults |
118
+
119
+ ---
120
+
121
+ _Document standards and patterns, not every dependency. See individual steering docs for detailed conventions._