Skip to content

Commit f429f63

Browse files
max-sixtyclaude
andauthored
docs(CLAUDE.md): streamline and add Quick Start section (#886)
- Add Quick Start section at top for immediate discoverability - Consolidate verbose multi-line code blocks into inline comments - Remove outdated "just getting started" note - Streamline Coverage and Repository Caching sections - Add Error Handling and Adding CLI Commands sections - Add Releases section pointing to skill Co-authored-by: Claude <noreply@anthropic.com>
1 parent 59886fc commit f429f63

File tree

1 file changed

+71
-119
lines changed

1 file changed

+71
-119
lines changed

CLAUDE.md

Lines changed: 71 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Worktrunk Development Guidelines
22

3-
> **Note**: This CLAUDE.md is just getting started. More guidelines will be added as patterns emerge.
3+
## Quick Start
4+
5+
```bash
6+
cargo run -- hook pre-merge --yes # run all tests + lints (do this before committing)
7+
```
8+
9+
For Claude Code web environments, run `task setup-web` first. See [Testing](#testing) for more commands.
410

511
## Project Status
612

@@ -50,40 +56,33 @@ Key skills:
5056
### Running Tests
5157

5258
```bash
53-
# Run all tests + lints (recommended before committing)
59+
# All tests + lints (recommended before committing)
5460
cargo run -- hook pre-merge --yes
61+
62+
# Tests with coverage report → target/llvm-cov/html/index.html
63+
task coverage
5564
```
5665

5766
**For faster iteration:**
5867

5968
```bash
60-
# Lints only
61-
pre-commit run --all-files
62-
63-
# Unit tests only
64-
cargo test --lib --bins
65-
66-
# Integration tests (no shell tests)
67-
cargo test --test integration
68-
69-
# Integration tests with shell tests (requires bash/zsh/fish)
70-
cargo test --test integration --features shell-integration-tests
69+
pre-commit run --all-files # lints only
70+
cargo test --lib --bins # unit tests only
71+
cargo test --test integration # integration tests (no shell tests)
72+
cargo test --test integration --features shell-integration-tests # with shell tests
7173
```
7274

7375
### Claude Code Web Environment
7476

75-
When working in Claude Code web, install the task runner and run setup:
77+
Run `task setup-web` to install required shells (zsh, fish), `gh`, and other dev tools. Install `task` first if needed:
7678

7779
```bash
78-
# Install task (go-task) - https://taskfile.dev
7980
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/bin
8081
export PATH="$HOME/bin:$PATH"
81-
82-
# Run setup
8382
task setup-web
8483
```
8584

86-
This installs required shells (zsh, fish) for shell integration tests and builds the project. Also installs `gh` and other dev tools—run this if any command is not found. The permission tests (`test_permission_error_prevents_save`, `test_approval_prompt_permission_error`) automatically skip when running as root, which is common in containerized environments.
85+
The permission tests (`test_permission_error_prevents_save`, `test_approval_prompt_permission_error`) skip automatically when running as root.
8786

8887
### Shell/PTY Integration Tests
8988

@@ -254,59 +253,27 @@ Examples: `feature-user-post-start-npm.log`, `feature-project-post-start-build.l
254253

255254
The `codecov/patch` CI check enforces coverage on changed lines — respond to failures by writing tests, not by ignoring them. If code is unused, remove it. This includes specialized error handlers for rare cases when falling through to a more general handler is sufficient.
256255

257-
### Running Coverage Locally
258-
259-
```bash
260-
task coverage # includes --features shell-integration-tests
261-
# Report: target/llvm-cov/html/index.html
262-
```
263-
264-
Install once: `cargo install cargo-llvm-cov`
265-
266256
### Investigating codecov/patch Failures
267257

268-
When CI shows a codecov/patch failure, investigate before declaring "ready to merge" — even if the check is marked "not required":
258+
When CI shows a codecov/patch failure, investigate before declaring "ready to merge":
269259

270-
1. Identify uncovered lines in your changes:
271-
```bash
272-
task coverage # run tests, generate coverage
273-
cargo llvm-cov report --show-missing-lines | grep <file> # query the report
274-
git diff main...HEAD -- path/to/file.rs
275-
```
276-
277-
2. For each uncovered function/method you added, either:
278-
- Write a test that exercises it, or
279-
- Document why it's intentionally untested (e.g., error paths requiring external system mocks)
280-
281-
### How Coverage Works with Integration Tests
282-
283-
Coverage is collected via `cargo llvm-cov` which instruments the binary. **Subprocess execution IS captured** — when tests spawn `wt` via `assert_cmd_snapshot!`, the instrumented binary writes coverage data to profile files that get merged into the report.
284-
285-
When investigating uncovered lines:
286-
287-
1. Run `task coverage` first to see actual coverage % (~92% is normal)
288-
2. Use `cargo llvm-cov report --show-missing-lines | grep <file>` to find specific uncovered lines
289-
3. **Check if tests already exist** for that functionality before writing new ones
290-
4. Remaining uncovered lines are typically:
291-
- Error handling paths requiring mocked git failures
292-
- Edge cases in shell integration states (e.g., running as `git wt`)
293-
- Test assertion code (only executes when tests fail)
260+
```bash
261+
task coverage # run tests, generate coverage
262+
cargo llvm-cov report --show-missing-lines | grep <file> # find uncovered lines
263+
```
294264

295-
Code that only runs on test failure (assertion messages, custom panic handlers) shows as uncovered since tests pass. Keep this code minimal — useful for debugging but a rarely-traveled path.
265+
For each uncovered function/method, either write a test or document why it's intentionally untested. Integration tests (via `assert_cmd_snapshot!`) do capture subprocess coverage.
296266

297267
## Benchmarks
298268

299-
See `benches/CLAUDE.md` for details.
269+
Benchmarks measure `wt list` performance across worktree counts and repository sizes.
300270

301271
```bash
302-
# Fast synthetic benchmarks (skip slow ones)
303-
cargo bench --bench list -- --skip cold --skip real
304-
305-
# Specific benchmark
306-
cargo bench --bench list bench_list_by_worktree_count
272+
cargo bench --bench list -- --skip cold --skip real # fast synthetic benchmarks
273+
cargo bench --bench list bench_list_by_worktree_count # specific benchmark
307274
```
308275

309-
Real repo benchmarks clone rust-lang/rust (~2-5 min first run, cached thereafter). Skip with `--skip real`.
276+
Real repo benchmarks clone rust-lang/rust (~2-5 min first run, cached thereafter). Skip with `--skip real`. See `benches/CLAUDE.md` for methodology and adding new benchmarks.
310277

311278
## JSON Output Format
312279

@@ -343,6 +310,44 @@ fn validate_config() { ... }
343310

344311
Never use `#[cfg(test)]` to add test-only convenience methods to library code. Tests should call the real API directly. If tests need helpers, define them in the test module.
345312

313+
## Error Handling
314+
315+
Use `anyhow` for error propagation with context:
316+
317+
```rust
318+
use anyhow::{bail, Context, Result};
319+
320+
// Prefer .context() for adding helpful error messages
321+
let data = std::fs::read_to_string(path)
322+
.context("Failed to read config file")?;
323+
324+
// Use bail! for early returns with formatted errors
325+
if worktree.is_dirty() {
326+
bail!("worktree has uncommitted changes");
327+
}
328+
```
329+
330+
**Patterns:**
331+
332+
- **Use `bail!`** for business logic errors (dirty worktree, missing branch, invalid state)
333+
- **Use `.context()`** for wrapping I/O and external command failures
334+
- **Don't `logger.error` before raising** — include context in the error message itself
335+
- **Let errors propagate** — don't catch and re-raise without adding information
336+
337+
## Adding CLI Commands
338+
339+
CLI commands live in `src/cli/` with implementations in `src/commands/`.
340+
341+
1. **Add subcommand** to `Cli` enum in `src/cli/mod.rs`
342+
2. **Create command module** in `src/commands/` (e.g., `src/commands/mycommand.rs`)
343+
3. **Add `after_long_help`** attribute for extended help that syncs to docs
344+
4. **Run doc sync** after adding help text:
345+
```bash
346+
cargo test --test integration test_command_pages_and_skill_files_are_in_sync
347+
```
348+
349+
Help text in `after_long_help` is the source of truth for `docs/content/{command}.md`.
350+
346351
## Accessor Function Naming Conventions
347352

348353
Function prefixes signal return behavior and side effects.
@@ -370,69 +375,16 @@ Function prefixes signal return behavior and side effects.
370375
- Don't use `load_*` for computed values (use bare nouns)
371376
- Don't use `get_*` prefix — use bare nouns instead (Rust convention)
372377

373-
## Repository Caching Strategy
374-
375-
Most data is stable for the duration of a command. The only things worktrunk modifies are:
378+
## Repository Caching
376379

377-
- **Worktree list**`wt switch --create`, `wt remove` create/remove worktrees
378-
- **Working tree state**`wt merge` commits, stages files
379-
- **Git config**`wt config` modifies settings
380-
381-
Everything else (remote URLs, project config, branch metadata) is read-only.
382-
383-
### Caching Implementation
384-
385-
`Repository` holds its cache directly via `Arc<RepoCache>`. Cloning a Repository shares the cache — all clones see the same cached values.
386-
387-
**Key patterns:**
388-
389-
- **Command entry points** create Repository via `Repository::current()` or `Repository::at(path)`
390-
- **Parallel tasks** (e.g., `wt list`) clone the Repository, sharing the cache
391-
- **Tests** naturally get isolation since each test creates its own Repository
392-
393-
**Currently cached:**
394-
395-
- `git_common_dir` — computed at construction, stored on struct
396-
- `worktree_root()` — per-worktree, keyed by path
397-
- `repo_path()` — derived from git_common_dir and is_bare
398-
- `is_bare()` — git config, doesn't change
399-
- `current_branch()` — per-worktree, keyed by path
400-
- `project_identifier()` — derived from remote URL
401-
- `primary_remote()` — git config, doesn't change
402-
- `primary_remote_url()` — derived from primary_remote, doesn't change
403-
- `default_branch()` — from git config or detection, doesn't change
404-
- `integration_target()` — effective target for integration checks (local default or upstream if ahead)
405-
- `merge_base()` — keyed by (commit1, commit2) pair
406-
- `ahead_behind` — keyed by (base_ref, branch_name), populated by `batch_ahead_behind()`
407-
- `project_config` — loaded from .config/wt.toml
408-
409-
**Not cached (intentionally):**
380+
Most data is stable for the duration of a command. `Repository` caches read-only values (remote URLs, config, branch metadata) via `Arc<RepoCache>` — cloning a Repository shares the cache.
410381

382+
**Not cached (changes during command execution):**
411383
- `is_dirty()` — changes as we stage/commit
412384
- `list_worktrees()` — changes as we create/remove worktrees
413385

414-
### Adding New Cached Methods
415-
416-
1. Add field to `RepoCache` struct: `field_name: OnceCell<T>`
417-
2. Access via `self.cache.field_name`
418-
3. Return owned values (String, PathBuf, bool)
386+
When adding new cached methods, see `RepoCache` in `src/git/repository/mod.rs` for patterns (repo-wide via `OnceCell`, per-worktree via `DashMap`).
419387

420-
```rust
421-
// For repo-wide values (same for all clones)
422-
pub fn cached_value(&self) -> anyhow::Result<String> {
423-
self.cache
424-
.field_name
425-
.get_or_init(|| { /* compute value */ })
426-
.clone()
427-
}
388+
## Releases
428389

429-
// For per-worktree values (different per worktree path)
430-
// Use DashMap for concurrent access
431-
pub fn cached_per_worktree(&self, path: &Path) -> String {
432-
self.cache
433-
.field_name
434-
.entry(path.to_path_buf())
435-
.or_insert_with(|| { /* compute value */ })
436-
.clone()
437-
}
438-
```
390+
Use the `release` skill for cutting releases. It handles version bumping, changelog generation, crates.io publishing, and GitHub releases.

0 commit comments

Comments
 (0)