Skip to content

Commit 7a800c1

Browse files
KSXGitHubclaude
andauthored
docs: contributing guidelines and AI assistant instructions (#354)
Establishes comprehensive contributing guidelines and development standards for the project, along with quick-reference instructions for AI assistants. https://claude.ai/code/session_0118JGKVwhgbK8NwHfrorHfx --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7f4da0e commit 7a800c1

5 files changed

Lines changed: 279 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# AI Instructions
2+
3+
Read and follow the CONTRIBUTING.md file in this repository for all code style conventions, commit message format, and development guidelines.
4+
5+
## Quick Reference
6+
7+
- Commit format: Conventional Commits — `type(scope): lowercase description`
8+
- Version releases are the only exception: just the version number (e.g. `0.21.1`)
9+
- Import order: internal (`crate::`/`super::`) → external crates → `std::`, prefer merged imports
10+
- Use descriptive generic names (`Size`, `Report`), not single letters
11+
- Prefer `where` clauses for multiple trait bounds
12+
- Derive order: std traits → comparison traits → `Hash` → derive_more → feature-gated
13+
- Custom errors: `#[derive(Debug, Display, Error)]` + `#[non_exhaustive]`
14+
- Minimize `unwrap()` in non-test code — use proper error handling
15+
- `#![deny(warnings)]` is active — code must be warning-free
16+
- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
17+
- If the AI agent is Claude Code, `gh` (GitHub CLI) is not installed — do not attempt to use it
18+
- Run `FMT=true LINT=true BUILD=true TEST=true DOC=true ./test.sh` to validate changes

AGENTS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# AI Instructions
2+
3+
Read and follow the CONTRIBUTING.md file in this repository for all code style conventions, commit message format, and development guidelines.
4+
5+
## Quick Reference
6+
7+
- Commit format: Conventional Commits — `type(scope): lowercase description`
8+
- Version releases are the only exception: just the version number (e.g. `0.21.1`)
9+
- Import order: internal (`crate::`/`super::`) → external crates → `std::`, prefer merged imports
10+
- Use descriptive generic names (`Size`, `Report`), not single letters
11+
- Prefer `where` clauses for multiple trait bounds
12+
- Derive order: std traits → comparison traits → `Hash` → derive_more → feature-gated
13+
- Custom errors: `#[derive(Debug, Display, Error)]` + `#[non_exhaustive]`
14+
- Minimize `unwrap()` in non-test code — use proper error handling
15+
- `#![deny(warnings)]` is active — code must be warning-free
16+
- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
17+
- If the AI agent is Claude Code, `gh` (GitHub CLI) is not installed — do not attempt to use it
18+
- Run `FMT=true LINT=true BUILD=true TEST=true DOC=true ./test.sh` to validate changes

CLAUDE.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# AI Instructions
2+
3+
Read and follow the CONTRIBUTING.md file in this repository for all code style conventions, commit message format, and development guidelines.
4+
5+
## Quick Reference
6+
7+
- Commit format: Conventional Commits — `type(scope): lowercase description`
8+
- Version releases are the only exception: just the version number (e.g. `0.21.1`)
9+
- Import order: internal (`crate::`/`super::`) → external crates → `std::`, prefer merged imports
10+
- Use descriptive generic names (`Size`, `Report`), not single letters
11+
- Prefer `where` clauses for multiple trait bounds
12+
- Derive order: std traits → comparison traits → `Hash` → derive_more → feature-gated
13+
- Custom errors: `#[derive(Debug, Display, Error)]` + `#[non_exhaustive]`
14+
- Minimize `unwrap()` in non-test code — use proper error handling
15+
- `#![deny(warnings)]` is active — code must be warning-free
16+
- Install toolchain before running tests: `rustup toolchain install "$(< rust-toolchain)" && rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy`
17+
- If the AI agent is Claude Code, `gh` (GitHub CLI) is not installed — do not attempt to use it
18+
- Run `FMT=true LINT=true BUILD=true TEST=true DOC=true ./test.sh` to validate changes

CONTRIBUTING.md

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# Contributing to parallel-disk-usage
2+
3+
## Commit Message Convention
4+
5+
This project uses [Conventional Commits](https://www.conventionalcommits.org/).
6+
7+
### Format
8+
9+
```
10+
type(scope): lowercase description
11+
```
12+
13+
### Rules
14+
15+
- **Types:** `feat`, `fix`, `refactor`, `perf`, `docs`, `style`, `chore`, `ci`, `test`, `lint`
16+
- **Scopes** (optional): `cli`, `api`, `deps`, `readme`, `benchmark`, `toolchain`, `test`, or other relevant area
17+
- **Description:** always lowercase after the colon, no trailing period, brief (3-7 words preferred)
18+
- **Breaking changes:** append `!` before the colon (e.g. `feat(cli)!: remove deprecated flag`)
19+
- **Code identifiers** in descriptions should be wrapped in backticks (e.g. `` chore(deps): update `rand` ``)
20+
21+
### Exception: Version Releases
22+
23+
Version release commits use **only** the version number as the message — no type prefix:
24+
25+
```
26+
0.21.1
27+
```
28+
29+
## Code Style
30+
31+
Automated tools enforce formatting (`cargo fmt`) and linting (`cargo clippy`). The following conventions are **not** enforced by those tools and must be followed manually.
32+
33+
### Import Organization
34+
35+
Prefer **merged imports** — combine multiple items from the same crate or module into a single `use` statement with braces rather than separate `use` lines.
36+
37+
Imports are grouped in this order, separated by blank lines:
38+
39+
1. `use super::...` or `use crate::...` (internal)
40+
2. External crate imports (alphabetical)
41+
3. `use std::...` (standard library)
42+
43+
Within each group, items are ordered alphabetically. Platform-specific imports (`#[cfg(unix)]`) go in a separate block after the main imports.
44+
45+
```rust
46+
use crate::{
47+
args::{Args, Quantity, Threads},
48+
bytes_format::BytesFormat,
49+
size,
50+
};
51+
use clap::Parser;
52+
use pipe_trait::Pipe;
53+
use std::{io::stdin, time::Duration};
54+
55+
#[cfg(unix)]
56+
use crate::get_size::{GetBlockCount, GetBlockSize};
57+
```
58+
59+
### Module Organization
60+
61+
- Use the flat file pattern (`module.rs`) rather than `module/mod.rs` for submodules.
62+
- List `pub mod` declarations first, then `pub use` re-exports, then private imports and items.
63+
- Use `pub use` to re-export key types at the module level for convenience.
64+
65+
```rust
66+
pub mod error_only_reporter;
67+
pub mod error_report;
68+
pub mod event;
69+
70+
pub use error_only_reporter::ErrorOnlyReporter;
71+
pub use error_report::ErrorReport;
72+
pub use event::Event;
73+
```
74+
75+
- Type aliases using `pub use ... as ...` are used to provide semantic alternative names:
76+
77+
```rust
78+
pub use Reflection as DataTreeReflection;
79+
```
80+
81+
### Derive Macro Ordering
82+
83+
When deriving multiple traits, use this order and split across multiple `#[derive(...)]` lines for readability:
84+
85+
1. **Standard traits:** `Debug`, `Default`, `Clone`, `Copy`
86+
2. **Comparison traits:** `PartialEq`, `Eq`, `PartialOrd`, `Ord`
87+
3. **Hash**
88+
4. **`derive_more` traits:** `Display`, `From`, `Into`, `Add`, `AddAssign`, etc.
89+
5. **Feature-gated derives** on a separate `#[cfg_attr(...)]` line
90+
91+
```rust
92+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
93+
#[derive(From, Into, Add, AddAssign, Sub, SubAssign, Sum)]
94+
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
95+
pub struct Bytes(u64);
96+
```
97+
98+
### Generic Parameter Naming
99+
100+
Use **descriptive names** for type parameters, not single letters:
101+
102+
- `Size`, `Name`, `SizeGetter`, `HardlinksRecorder`, `Report`
103+
104+
Single-letter generics are acceptable only in very short, self-contained trait impls.
105+
106+
### Trait Bounds
107+
108+
Prefer `where` clauses over inline bounds when there are multiple constraints:
109+
110+
```rust
111+
impl<Size, SizeGetter, HardlinksRecorder, Report>
112+
From<FsTreeBuilder<'a, Size, SizeGetter, HardlinksRecorder, Report>>
113+
for DataTree<OsStringDisplay, Size>
114+
where
115+
Report: Reporter<Size> + Sync + ?Sized,
116+
Size: size::Size + Send + Sync,
117+
SizeGetter: GetSize<Size = Size> + Sync,
118+
HardlinksRecorder: RecordHardlinks<Size, Report> + Sync + ?Sized,
119+
```
120+
121+
### Visibility
122+
123+
- Use `pub` for the public API surface.
124+
- Use `pub(crate)` for items shared within the crate but not exposed externally.
125+
- Default to private for everything else.
126+
127+
### Error Handling
128+
129+
- Define custom error enums with `#[derive(Debug, Display, Error)]` from `derive_more`.
130+
- Mark error enums as `#[non_exhaustive]`.
131+
- 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.
132+
133+
```rust
134+
#[derive(Debug, Display, Error)]
135+
#[non_exhaustive]
136+
pub enum RuntimeError {
137+
#[display("SerializationFailure: {_0}")]
138+
SerializationFailure(serde_json::Error),
139+
}
140+
```
141+
142+
### Documentation Comments
143+
144+
- Use `///` doc comments for all public types, traits, functions, and fields.
145+
- Use `//!` module-level doc comments at the top of `lib.rs` and significant modules.
146+
- Include usage examples with `/// ```no_run` blocks for key public APIs.
147+
- Reference related types with `[`backtick links`](crate::path)` syntax.
148+
149+
### Feature Gating
150+
151+
- Use `#[cfg(feature = "...")]` for optional functionality (e.g., `json`, `cli`).
152+
- Use `#[cfg(unix)]` for POSIX-specific code.
153+
- Use `#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]` for conditional derives.
154+
155+
### Pattern Matching
156+
157+
Use exhaustive matching. When mapping enum variants to values, prefer the concise wrapping style:
158+
159+
```rust
160+
ExitCode::from(match self {
161+
RuntimeError::SerializationFailure(_) => 2,
162+
RuntimeError::DeserializationFailure(_) => 3,
163+
})
164+
```
165+
166+
### Struct Field Ordering
167+
168+
Order fields logically by purpose, not alphabetically. Group related fields together. Document every public field with `///` comments.
169+
170+
### Macros
171+
172+
Use macros to reduce boilerplate for repetitive patterns (e.g. newtype wrappers, trait impls for multiple numeric types). Keep macros well-scoped and documented.
173+
174+
### Warnings Policy
175+
176+
The crate uses `#![deny(warnings)]` — all warnings are treated as errors. Code must compile warning-free.
177+
178+
## Setup
179+
180+
Install the required Rust toolchain and components before running any checks:
181+
182+
```sh
183+
rustup toolchain install "$(< rust-toolchain)"
184+
rustup component add --toolchain "$(< rust-toolchain)" rustfmt clippy
185+
```
186+
187+
## Automated Checks
188+
189+
Before submitting, ensure:
190+
191+
- `cargo fmt -- --check` passes
192+
- `cargo clippy` passes (on all feature combinations)
193+
- `cargo test` passes
194+
- The project builds with no default features, default features, and all features
195+
196+
The CI script `test.sh` runs all of these across 5 feature combinations. You can run it locally with:
197+
198+
```sh
199+
FMT=true LINT=true BUILD=true TEST=true DOC=true ./test.sh
200+
```

tests/sync_ai_instructions.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! The following tests check whether the AI instruction files are in sync.
2+
//!
3+
//! All three files (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md) should be identical.
4+
5+
macro_rules! check {
6+
($name:ident: $a_path:literal == $b_path:literal) => {
7+
#[test]
8+
fn $name() {
9+
let a = include_str!($a_path);
10+
let b = include_str!($b_path);
11+
assert!(
12+
a == b,
13+
concat!(
14+
"AI instruction files are out of sync: ",
15+
$a_path,
16+
" != ",
17+
$b_path,
18+
),
19+
);
20+
}
21+
};
22+
}
23+
24+
check!(claude_md_vs_agents_md: "../CLAUDE.md" == "../AGENTS.md");
25+
check!(claude_md_vs_copilot_instructions: "../CLAUDE.md" == "../.github/copilot-instructions.md");

0 commit comments

Comments
 (0)