Diff
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index f04b72b..c514dc4 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -4,17 +4,18 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
## Quick Reference
-- Commit format: Conventional Commits — `type(scope): lowercase description`
-- Use descriptive variable and closure parameter names by default — single letters are only allowed in: conventional names (`n` for count, `f` for formatter), comparison closures (`|a, b|`), trivial single-expression closures, fold accumulators, index variables (`i`/`j`/`k` in short closures or index-based loops only), and test fixtures (identical roles only). Never use single letters in multi-line functions or closures
-- Use `pipe-trait` for chaining through unary functions (constructors, `Some`, `Ok`, free functions, etc.), avoiding nested calls, and continuing method chains — but not for simple standalone calls (prefer `foo(value)` over `value.pipe(foo)`)
-- Use `command-extra` (`CommandExtra` trait) when building `std::process::Command` — use `.with_arg(...)`, `.with_env(...)`, etc. instead of `.arg(...)`, `.env(...)` to keep construction as a single owned expression chain
-- Prefer `where` clauses for multiple trait bounds
-- Minimize `unwrap()` in non-test code — use proper error handling
-- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` to skip tests — use `#[cfg]` on tests only when the code cannot compile under the condition (e.g., references types/functions that don't exist on other platforms)
-- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
-- Run `cargo fmt -- --check && cargo clippy --all-targets && cargo test` to validate changes
-- **ALWAYS run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before committing, regardless of how trivial the change seems — this includes documentation-only changes, comment edits, and config changes
-- If a sync test fails, read its error message carefully and run the exact command it tells you to run
-- Run CSpell check if necessary (with `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`).
-- When the user provides a diff and you need to update the files, don't manually interpret each hunk (that'd be slow); apply it with `git apply` instead. If the user provides a diff for context or discussion rather than as a change to apply, respond accordingly instead.
-- `gh` (GitHub CLI) is not installed — do not attempt to use it
+- Commit format: Conventional Commits. Pattern: `type(scope): lowercase description`. The scope is optional.
+- Write documentation, comments, and other prose for ease of understanding first. Prefer a formal tone when it does not hurt clarity, and use complete sentences. Avoid mid-sentence breaks introduced by em dashes or long parenthetical clauses. Em dashes are a reliable symptom of loose phrasing; when one appears, restructure the surrounding sentence so each clause stands on its own rather than swapping the em dash for another punctuation mark.
+- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
+- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
+- Use the `command-extra` crate (the `CommandExtra` trait) when building `std::process::Command`. Call `.with_arg(...)`, `.with_env(...)`, and similar methods rather than `.arg(...)` or `.env(...)`, so construction remains a single owned expression chain.
+- Prefer `where` clauses when a type has multiple trait bounds.
+- Minimize `unwrap()` in non-test code. Use proper error handling instead.
+- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
+- Install the toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`.
+- Validate changes with `cargo fmt -- --check && cargo clippy --all-targets && cargo test`.
+- **Always run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before every commit. This rule applies to all changes, including documentation changes, comment edits, and config updates.
+- When a sync test fails, read its error message and run the exact command it reports.
+- Run the CSpell spell check when a change may introduce new words: `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`.
+- When the user provides a diff to apply, run `git apply` rather than interpreting each hunk manually. When a diff is provided for context or discussion, respond accordingly.
+- The `gh` (GitHub CLI) is not installed. Do not attempt to use it.
diff --git a/AGENTS.md b/AGENTS.md
index bba0b1e..c7aaf3c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,16 +4,17 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
## Quick Reference
-- Commit format: Conventional Commits — `type(scope): lowercase description`
-- Use descriptive variable and closure parameter names by default — single letters are only allowed in: conventional names (`n` for count, `f` for formatter), comparison closures (`|a, b|`), trivial single-expression closures, fold accumulators, index variables (`i`/`j`/`k` in short closures or index-based loops only), and test fixtures (identical roles only). Never use single letters in multi-line functions or closures
-- Use `pipe-trait` for chaining through unary functions (constructors, `Some`, `Ok`, free functions, etc.), avoiding nested calls, and continuing method chains — but not for simple standalone calls (prefer `foo(value)` over `value.pipe(foo)`)
-- Use `command-extra` (`CommandExtra` trait) when building `std::process::Command` — use `.with_arg(...)`, `.with_env(...)`, etc. instead of `.arg(...)`, `.env(...)` to keep construction as a single owned expression chain
-- Prefer `where` clauses for multiple trait bounds
-- Minimize `unwrap()` in non-test code — use proper error handling
-- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` to skip tests — use `#[cfg]` on tests only when the code cannot compile under the condition (e.g., references types/functions that don't exist on other platforms)
-- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
-- Run `cargo fmt -- --check && cargo clippy --all-targets && cargo test` to validate changes
-- **ALWAYS run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before committing, regardless of how trivial the change seems — this includes documentation-only changes, comment edits, and config changes
-- If a sync test fails, read its error message carefully and run the exact command it tells you to run
-- Run CSpell check if necessary (with `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`).
-- When the user provides a diff and you need to update the files, don't manually interpret each hunk (that'd be slow); apply it with `git apply` instead. If the user provides a diff for context or discussion rather than as a change to apply, respond accordingly instead.
+- Commit format: Conventional Commits. Pattern: `type(scope): lowercase description`. The scope is optional.
+- Write documentation, comments, and other prose for ease of understanding first. Prefer a formal tone when it does not hurt clarity, and use complete sentences. Avoid mid-sentence breaks introduced by em dashes or long parenthetical clauses. Em dashes are a reliable symptom of loose phrasing; when one appears, restructure the surrounding sentence so each clause stands on its own rather than swapping the em dash for another punctuation mark.
+- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
+- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
+- Use the `command-extra` crate (the `CommandExtra` trait) when building `std::process::Command`. Call `.with_arg(...)`, `.with_env(...)`, and similar methods rather than `.arg(...)` or `.env(...)`, so construction remains a single owned expression chain.
+- Prefer `where` clauses when a type has multiple trait bounds.
+- Minimize `unwrap()` in non-test code. Use proper error handling instead.
+- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
+- Install the toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`.
+- Validate changes with `cargo fmt -- --check && cargo clippy --all-targets && cargo test`.
+- **Always run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before every commit. This rule applies to all changes, including documentation changes, comment edits, and config updates.
+- When a sync test fails, read its error message and run the exact command it reports.
+- Run the CSpell spell check when a change may introduce new words: `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`.
+- When the user provides a diff to apply, run `git apply` rather than interpreting each hunk manually. When a diff is provided for context or discussion, respond accordingly.
diff --git a/CLAUDE.md b/CLAUDE.md
index bba0b1e..c7aaf3c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -4,16 +4,17 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
## Quick Reference
-- Commit format: Conventional Commits — `type(scope): lowercase description`
-- Use descriptive variable and closure parameter names by default — single letters are only allowed in: conventional names (`n` for count, `f` for formatter), comparison closures (`|a, b|`), trivial single-expression closures, fold accumulators, index variables (`i`/`j`/`k` in short closures or index-based loops only), and test fixtures (identical roles only). Never use single letters in multi-line functions or closures
-- Use `pipe-trait` for chaining through unary functions (constructors, `Some`, `Ok`, free functions, etc.), avoiding nested calls, and continuing method chains — but not for simple standalone calls (prefer `foo(value)` over `value.pipe(foo)`)
-- Use `command-extra` (`CommandExtra` trait) when building `std::process::Command` — use `.with_arg(...)`, `.with_env(...)`, etc. instead of `.arg(...)`, `.env(...)` to keep construction as a single owned expression chain
-- Prefer `where` clauses for multiple trait bounds
-- Minimize `unwrap()` in non-test code — use proper error handling
-- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` to skip tests — use `#[cfg]` on tests only when the code cannot compile under the condition (e.g., references types/functions that don't exist on other platforms)
-- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
-- Run `cargo fmt -- --check && cargo clippy --all-targets && cargo test` to validate changes
-- **ALWAYS run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before committing, regardless of how trivial the change seems — this includes documentation-only changes, comment edits, and config changes
-- If a sync test fails, read its error message carefully and run the exact command it tells you to run
-- Run CSpell check if necessary (with `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`).
-- When the user provides a diff and you need to update the files, don't manually interpret each hunk (that'd be slow); apply it with `git apply` instead. If the user provides a diff for context or discussion rather than as a change to apply, respond accordingly instead.
+- Commit format: Conventional Commits. Pattern: `type(scope): lowercase description`. The scope is optional.
+- Write documentation, comments, and other prose for ease of understanding first. Prefer a formal tone when it does not hurt clarity, and use complete sentences. Avoid mid-sentence breaks introduced by em dashes or long parenthetical clauses. Em dashes are a reliable symptom of loose phrasing; when one appears, restructure the surrounding sentence so each clause stands on its own rather than swapping the em dash for another punctuation mark.
+- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
+- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
+- Use the `command-extra` crate (the `CommandExtra` trait) when building `std::process::Command`. Call `.with_arg(...)`, `.with_env(...)`, and similar methods rather than `.arg(...)` or `.env(...)`, so construction remains a single owned expression chain.
+- Prefer `where` clauses when a type has multiple trait bounds.
+- Minimize `unwrap()` in non-test code. Use proper error handling instead.
+- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
+- Install the toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`.
+- Validate changes with `cargo fmt -- --check && cargo clippy --all-targets && cargo test`.
+- **Always run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before every commit. This rule applies to all changes, including documentation changes, comment edits, and config updates.
+- When a sync test fails, read its error message and run the exact command it reports.
+- Run the CSpell spell check when a change may introduce new words: `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`.
+- When the user provides a diff to apply, run `git apply` rather than interpreting each hunk manually. When a diff is provided for context or discussion, respond accordingly.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f9f9218..848e274 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,20 +28,20 @@ Use **descriptive names** for variables and closure parameters by default. Singl
#### When single-letter names are allowed
-- **Comparison closures:** `|a, b|` in `sort_by`, `cmp`, or similar two-argument comparison callbacks — this is idiomatic Rust.
+- **Comparison closures:** `|a, b|` in `sort_by`, `cmp`, or similar two-argument comparison callbacks. This is idiomatic Rust.
```rust
items.sort_by(|a, b| a.name.cmp(&b.name));
-- Conventional single-letter names: n for a natural number (unsigned integer / count), f for a fmt::Formatter, and similar well-established conventions from math or the Rust standard library. Note: for indices, use index, idx, or *_index — not n. (For i/j/k, see the dedicated rule below.)
+- Conventional single-letter names: n for a natural number (unsigned integer / count); f for a fmt::Formatter; and similar well-established conventions from math or the Rust standard library. Note: for indices, use index, idx, or *_index, not n. (For i/j/k, see the dedicated rule below.)
fn with_capacity(n: usize) -> Self { todo!() }
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!() }
-- Index variables (i, j, k): These may only be used in two contexts: (1) short closures, and (2) index-based loops/iterations (rare in Rust). In all other cases, use index, idx, or *_index.
+- Index variables (i, j, k): These may only be used in two contexts: short closures and index-based loops. In all other cases, use index, idx, or *_index.
- Trivial single-expression closures: A closure whose body is a single field access, method call, or wrapper may use a single letter when the type and purpose are obvious from context.
@@ -55,7 +55,7 @@ Use descriptive names for variables and closure parameters by default. Singl
.fold(PathBuf::new(), |acc, x| acc.join(x))
-- **Test fixtures:** `let a`, `let b`, `let c` for interchangeable specimens with identical roles in equality or comparison tests. Do not use single letters when the variables have distinct roles — use `actual`/`expected` or similar descriptive names instead.
+- **Test fixtures:** `let a`, `let b`, `let c` for interchangeable specimens with identical roles in equality or comparison tests. Do not use single letters when the variables have distinct roles; use `actual`/`expected` or similar descriptive names instead.
#### When single-letter names are NOT allowed
@@ -99,23 +99,23 @@ where
### Error Handling
-- Minimize `unwrap()` in non-test code — use proper error propagation. `unwrap()` is acceptable in tests and for provably infallible operations (with a comment explaining why). When deliberately ignoring an error, use `.ok()` with a comment explaining why.
+- Minimize `unwrap()` in non-test code; use proper error propagation. `unwrap()` is acceptable in tests and for provably infallible operations (with a comment explaining why). When deliberately ignoring an error, use `.ok()` with a comment explaining why.
### Conditional Test Skipping: `#[cfg]` vs `#[cfg_attr(..., ignore)]`
-When a test cannot run under certain conditions (e.g., wrong platform), prefer `#[cfg_attr(..., ignore)]` over `#[cfg(...)]` to skip it. This way the test is still compiled on all configurations — catching type errors and regressions early — but simply skipped at runtime.
+When a test cannot run under certain conditions, such as on the wrong platform, prefer `#[cfg_attr(..., ignore)]` over `#[cfg(...)]` to skip it. The test still compiles on every configuration and is only skipped at runtime. This approach catches type errors and regressions that a `#[cfg]` skip would hide.
-Use `#[cfg]` on tests **only** when the code cannot compile under the condition — for example, when the test references types, functions, or trait methods that are gated behind `#[cfg]` and do not exist on other platforms.
+Use `#[cfg]` on tests **only** when the code cannot compile under the condition. An example is a test that uses platform-specific types or functions gated behind `#[cfg]`.
Prefer including a reason string in the `ignore` attribute to explain why the test is skipped.
```rust
-// Good — test compiles everywhere, skipped at runtime on non-unix
+// Good: test compiles everywhere, skipped at runtime on non-unix
#[test]
#[cfg_attr(not(unix), ignore = "only unix path separators are tested")]
fn unix_path_logic() { /* uses hardcoded unix paths but no unix-only types */ }
-// Good — test CANNOT compile on non-unix (uses unix-only types)
+// Good: test CANNOT compile on non-unix (uses unix-only types)
#[cfg(unix)]
#[test]
fn unix_only_types() { /* uses OsStrExt which only exists on unix */ }
@@ -125,14 +125,14 @@ fn unix_only_types() { /* uses OsStrExt which only exists on unix */ }
This codebase uses the [`pipe-trait`](https://docs.rs/pipe-trait) crate for method-chaining through unary functions, keeping code in a natural left-to-right reading order. Import it as `use pipe_trait::Pipe;`.
-Any callable that takes a single argument works with `.pipe()` — free functions, closures, newtype constructors, enum variant constructors, `Some`, `Ok`, `Err`, trait methods like `From::from`, etc.
+Any callable that takes a single argument works with `.pipe()`. This includes free functions, closures, newtype constructors, enum variant constructors, `Some`, `Ok`, `Err`, and trait methods such as `From::from`.
#### When to use pipe
**Chaining through a unary function at the end of an expression chain:**
```rust
-// Good — pipe keeps the chain flowing left-to-right
+// Good: pipe keeps the chain flowing left-to-right
entry.file_name().pipe(OsStringDisplay::from).pipe(Some)
@@ -149,7 +149,7 @@ let data = stdin().pipe(serde_json::from_reader::<_, JsonData>);
Continuing a method chain through a free function and back to methods:
-// Good — pipe bridges from methods to a free function and back
+// Good: pipe bridges from methods to a free function and back
path_buf
.pipe_as_ref(fs::read_to_string)
.map(|content| content.trim().to_owned())
@@ -157,13 +157,13 @@ path_buf
#### When NOT to use pipe
-**Simple standalone function calls** — pipe adds noise with no readability benefit:
+**Simple standalone function calls.** Pipe adds noise with no readability benefit:
```rust
-// Bad — unnecessary pipe
+// Bad: unnecessary pipe
let result = value.pipe(foo);
-// Good — just call the function directly
+// Good: just call the function directly
let result = foo(value);
@@ -171,17 +171,17 @@ let result = foo(value);
This codebase uses the command-extra crate to build std::process::Command values in a chainable, owned style. Import it as use command_extra::CommandExtra;.
-The standard Command builder methods (arg, env, current_dir, etc.) take &mut self and return &mut Command, making them unsuitable for method chains that end in an owned value. The CommandExtra extension trait provides .with_* counterparts that take ownership and return an owned Command, enabling fluent one-expression construction:
+The standard Command builder methods, such as arg, env, and current_dir, take &mut self and return &mut Command. This makes them unsuitable for method chains that end in an owned value. The CommandExtra extension trait provides .with_* counterparts that take ownership and return an owned Command, enabling fluent one-expression construction:
-// Good — fully chainable, owned style
+// Good: fully chainable, owned style
let output = Command::new("my-tool")
.with_arg("--flag")
.with_arg(value)
.output()
.expect("spawn my-tool");
-// Avoid — mutable-reference style, cannot chain with owned methods
+// Avoid: mutable-reference style, cannot chain with owned methods
let mut cmd = Command::new("my-tool");
cmd.arg("--flag");
cmd.arg(value);
@@ -199,7 +199,7 @@ rustup toolchain install "$(< rust-toolchain)"
rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy
-If you need to run the spell check locally, install the Node.js dependencies via pnpm:
+To run the spell check locally, install the Node.js dependencies with pnpm:
pnpm install --frozen-lockfile
@@ -227,7 +227,7 @@ cargo fmt -- --check && cargo clippy --all-targets && cargo test
### Spell Check
-Run the [CSpell](https://cspell.org) spell check if necessary:
+Run the [CSpell](https://cspell.org) spell check when a change may introduce new words:
```sh
pnpm exec cspell lint --no-progress --gitignore '**'
diff --git a/template/ai-instructions/copilot.md b/template/ai-instructions/copilot.md
index b458326..a887ba3 100644
--- a/template/ai-instructions/copilot.md
+++ b/template/ai-instructions/copilot.md
@@ -1 +1 @@
-- `gh` (GitHub CLI) is not installed — do not attempt to use it
+- The `gh` (GitHub CLI) is not installed. Do not attempt to use it.
diff --git a/template/ai-instructions/shared.md b/template/ai-instructions/shared.md
index bba0b1e..c7aaf3c 100644
--- a/template/ai-instructions/shared.md
+++ b/template/ai-instructions/shared.md
@@ -4,16 +4,17 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
## Quick Reference
-- Commit format: Conventional Commits — `type(scope): lowercase description`
-- Use descriptive variable and closure parameter names by default — single letters are only allowed in: conventional names (`n` for count, `f` for formatter), comparison closures (`|a, b|`), trivial single-expression closures, fold accumulators, index variables (`i`/`j`/`k` in short closures or index-based loops only), and test fixtures (identical roles only). Never use single letters in multi-line functions or closures
-- Use `pipe-trait` for chaining through unary functions (constructors, `Some`, `Ok`, free functions, etc.), avoiding nested calls, and continuing method chains — but not for simple standalone calls (prefer `foo(value)` over `value.pipe(foo)`)
-- Use `command-extra` (`CommandExtra` trait) when building `std::process::Command` — use `.with_arg(...)`, `.with_env(...)`, etc. instead of `.arg(...)`, `.env(...)` to keep construction as a single owned expression chain
-- Prefer `where` clauses for multiple trait bounds
-- Minimize `unwrap()` in non-test code — use proper error handling
-- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` to skip tests — use `#[cfg]` on tests only when the code cannot compile under the condition (e.g., references types/functions that don't exist on other platforms)
-- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
-- Run `cargo fmt -- --check && cargo clippy --all-targets && cargo test` to validate changes
-- **ALWAYS run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before committing, regardless of how trivial the change seems — this includes documentation-only changes, comment edits, and config changes
-- If a sync test fails, read its error message carefully and run the exact command it tells you to run
-- Run CSpell check if necessary (with `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`).
-- When the user provides a diff and you need to update the files, don't manually interpret each hunk (that'd be slow); apply it with `git apply` instead. If the user provides a diff for context or discussion rather than as a change to apply, respond accordingly instead.
+- Commit format: Conventional Commits. Pattern: `type(scope): lowercase description`. The scope is optional.
+- Write documentation, comments, and other prose for ease of understanding first. Prefer a formal tone when it does not hurt clarity, and use complete sentences. Avoid mid-sentence breaks introduced by em dashes or long parenthetical clauses. Em dashes are a reliable symptom of loose phrasing; when one appears, restructure the surrounding sentence so each clause stands on its own rather than swapping the em dash for another punctuation mark.
+- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
+- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
+- Use the `command-extra` crate (the `CommandExtra` trait) when building `std::process::Command`. Call `.with_arg(...)`, `.with_env(...)`, and similar methods rather than `.arg(...)` or `.env(...)`, so construction remains a single owned expression chain.
+- Prefer `where` clauses when a type has multiple trait bounds.
+- Minimize `unwrap()` in non-test code. Use proper error handling instead.
+- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
+- Install the toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`.
+- Validate changes with `cargo fmt -- --check && cargo clippy --all-targets && cargo test`.
+- **Always run the full Rust test suite** (`cargo fmt -- --check && cargo clippy --all-targets && cargo test`) before every commit. This rule applies to all changes, including documentation changes, comment edits, and config updates.
+- When a sync test fails, read its error message and run the exact command it reports.
+- Run the CSpell spell check when a change may introduce new words: `pnpm install --frozen-lockfile && pnpm exec cspell lint --gitignore '**'`.
+- When the user provides a diff to apply, run `git apply` rather than interpreting each hunk manually. When a diff is provided for context or discussion, respond accordingly.
This is from a PR on an unrelated codebase:
Diff
-- Conventional single-letter names:
nfor a natural number (unsigned integer / count),ffor afmt::Formatter, and similar well-established conventions from math or the Rust standard library. Note: for indices, useindex,idx, or*_index— notn. (Fori/j/k, see the dedicated rule below.)+- Conventional single-letter names:
nfor a natural number (unsigned integer / count);ffor afmt::Formatter; and similar well-established conventions from math or the Rust standard library. Note: for indices, useindex,idx, or*_index, notn. (Fori/j/k, see the dedicated rule below.)-- Index variables (
i,j,k): These may only be used in two contexts: (1) short closures, and (2) index-based loops/iterations (rare in Rust). In all other cases, useindex,idx, or*_index.+- Index variables (
i,j,k): These may only be used in two contexts: short closures and index-based loops. In all other cases, useindex,idx, or*_index.@@ -55,7 +55,7 @@ Use descriptive names for variables and closure parameters by default. Singl
.fold(PathBuf::new(), |acc, x| acc.join(x))
@@ -149,7 +149,7 @@ let data = stdin().pipe(serde_json::from_reader::<_, JsonData>);
Continuing a method chain through a free function and back to methods:
@@ -171,17 +171,17 @@ let result = foo(value);
This codebase uses the
command-extracrate to buildstd::process::Commandvalues in a chainable, owned style. Import it asuse command_extra::CommandExtra;.-The standard
Commandbuilder methods (arg,env,current_dir, etc.) take&mut selfand return&mut Command, making them unsuitable for method chains that end in an owned value. TheCommandExtraextension trait provides.with_*counterparts that take ownership and return an ownedCommand, enabling fluent one-expression construction:+The standard
Commandbuilder methods, such asarg,env, andcurrent_dir, take&mut selfand return&mut Command. This makes them unsuitable for method chains that end in an owned value. TheCommandExtraextension trait provides.with_*counterparts that take ownership and return an ownedCommand, enabling fluent one-expression construction:-If you need to run the spell check locally, install the Node.js dependencies via pnpm:
+To run the spell check locally, install the Node.js dependencies with pnpm:
TASKS:
Analyze the diff.
Adapt whatever is applicable to this codebase.