# CLAUDE.md — git-paw
## Project Overview
**git-paw** (Parallel AI Worktrees) is a Rust CLI tool that orchestrates multiple AI coding CLI sessions across git worktrees from a single terminal using tmux.
Repository: `bearicorn/git-paw`
Crate: `git-paw`
Binary: `git-paw` (invokable as `git paw` via git subcommand convention)
## Command Set
```
git paw # Smart start (default)
git paw start # Same — reattach / recover / launch new
git paw start --cli claude # Skip CLI picker
git paw start --cli claude --branches feat/a,feat/b # Fully non-interactive
git paw start --dry-run # Preview without executing
git paw start --preset backend # Use config preset
git paw stop # Kill tmux, keep worktrees + state for later
git paw purge # Nuclear: kill tmux, remove worktrees, delete state
git paw purge --force # Skip confirmation
git paw status # Show session state for current repo
git paw list-clis # Show detected + custom CLIs
git paw add-cli <name> <cmd> # Register a custom CLI globally
git paw remove-cli <name> # Unregister a custom CLI
```
One session per repo. `start` is smart — it reattaches if active, recovers if stopped/crashed, or launches new if nothing exists.
## Architecture
```
src/
├── main.rs # Entry point, wires modules together
├── cli.rs # Clap derive structs and subcommands
├── detect.rs # AI CLI detection (scans PATH + custom CLIs)
├── git.rs # Git operations (branches, worktrees)
├── tmux.rs # Tmux session/pane orchestration
├── session.rs # Session state persistence (~/.local/share/git-paw/)
├── config.rs # .git-paw/config.toml and global config parsing
├── interactive.rs # Dialoguer prompts (branch picker, CLI picker)
└── error.rs # PawError enum (thiserror)
```
## Development Commands
Prefer using `just` recipes — they mirror what CI runs:
```bash
just check # fmt + clippy + test (run this before pushing)
just test # Run all tests
just test-all # Include tmux-dependent ignored tests
just coverage # Generate HTML coverage report
just lint # cargo fmt --check + cargo clippy
just deny # cargo deny check (licenses, advisories, duplicates)
just audit # cargo audit (vulnerability scan)
just docs # Build mdBook and open
just api-docs # Build and open Rustdoc
just changelog # Regenerate CHANGELOG.md with git-cliff
just build # cargo build --release
just install # cargo install from local source
just clean # cargo clean
```
Raw cargo commands:
```bash
cargo build # Build
cargo test # Run all tests
cargo test -- --ignored # Run tmux-dependent tests
cargo clippy -- -D warnings # Lint (must pass with zero warnings)
cargo fmt --check # Format check (must pass)
cargo run -- --help # Run locally
cargo llvm-cov --html # Generate coverage report
cargo doc --no-deps --open # Build and open API docs
git cliff -o CHANGELOG.md # Regenerate changelog
```
## Conventions
### Code Style
- Use `cargo fmt` formatting (configured in `rustfmt.toml`)
- Clippy pedantic lints enabled (configured in `Cargo.toml` under `[lints.clippy]`)
- All public functions and types must have doc comments (`///`)
- All modules must have module-level doc comments (`//!`)
- No `unwrap()` or `expect()` in non-test code — propagate errors with `?`
- Use `PawError` variants from `error.rs` for all error cases
- Use `anyhow::Result` at the application boundary (`main.rs`, `cli.rs`)
- Use `thiserror` for library-level error types (`error.rs`)
- Prefer `std::process::Command` for calling external tools (git, tmux)
### Linting & Supply Chain
- **rustfmt** — code formatting, configured in `rustfmt.toml`. Run: `cargo fmt`
- **clippy** — linting with pedantic mode. Run: `cargo clippy -- -D warnings`
- **cargo deny** — license compliance, duplicate deps, advisory checks. Config: `deny.toml`. Run: `cargo deny check`
- **cargo audit** — vulnerability scanning. Run: `cargo audit`
- All four run in CI and must pass for PRs to merge
### Commit Conventions
This project follows **Conventional Commits** (Commitizen compatible).
Format: `<type>(<scope>): <description>`
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `ci`, `chore`, `perf`
Scopes: `detect`, `git`, `tmux`, `session`, `config`, `interactive`, `error`, `cli`, `docs`, `ci`
Examples:
```
feat(detect): add CLI detection for aider and amp
fix(git): handle branch names with multiple slashes
test(session): add round-trip serialization test
docs(readme): add quick start section
ci: add coverage threshold check to CI pipeline
```
Breaking changes: add `!` after type/scope and `BREAKING CHANGE:` footer.
All commit messages must be lowercase descriptions (no period at end).
### CLI Help Text
Every subcommand needs `about` + `long_about` with examples.
Every flag/option needs a `help` string.
The root command has `after_help` with a quick-start guide.
### Testing
- Unit tests in `#[cfg(test)] mod tests {}` at bottom of each module
- Integration tests in `tests/` directory
- `tempfile` for filesystem-touching tests
- `assert_cmd` for CLI binary tests
- Tests requiring `tmux` marked `#[ignore]`
- All tests independent — no shared mutable state
- All tests should test behavior and not implementation
### Dependencies
Only add dependencies listed in the approved set:
| `clap` v4 | CLI parsing with derive |
| `dialoguer` | Interactive terminal prompts |
| `console` | Terminal colors/styling |
| `which` | PATH binary detection |
| `thiserror` | Error derive macros |
| `anyhow` | Application error handling |
| `serde` + `serde_json` | Session state serialization |
| `toml` + `serde` | Config file parsing |
| `dirs` | Platform XDG directories |
Dev: `assert_cmd`, `predicates`, `tempfile`, `serial_test`
Do not add other dependencies without explicit approval.
## Spec-Driven Development
This project uses OpenSpec-style specifications. Each module has a spec in its GitHub issue.
Specs use RFC 2119 keywords: **SHALL/MUST** (mandatory), **SHOULD** (recommended), **MAY** (optional).
Requirements include GIVEN/WHEN/THEN scenarios. Each scenario maps to at least one test.
## Parallel Development Rules
**CRITICAL: Only modify files listed in your issue's "Files Owned" section.**
Do not modify files owned by another branch. If you need a type from another module, use the stub on `main` and add `// TODO: wire up after merge`.
### Branch → File Ownership
**Wave 1: Core Implementation**
| `feat/detect` | `src/detect.rs` |
| `feat/git-ops` | `src/git.rs` |
| `feat/tmux` | `src/tmux.rs` |
| `feat/session-state` | `src/session.rs` |
| `feat/config` | `src/config.rs` |
| `feat/interactive` | `src/interactive.rs` |
| `feat/errors` | `src/error.rs` |
**Wave 2: Testing, CI, Docs, Polish**
| `feat/wire-up` | `src/main.rs`, `src/cli.rs` |
| `feat/unit-tests` | `#[cfg(test)]` blocks in `src/*.rs`, `tests/helpers/` |
| `feat/integration-tests` | `tests/*.rs` |
| `feat/ci` | `.github/workflows/`, `.github/dependabot.yml`, `deny.toml` |
| `feat/openspec` | `openspec/` |
| `feat/docs-site` | `docs/` |
| `feat/readme` | `README.md`, `CONTRIBUTING.md`, `CHANGELOG.md`, etc. |
### Merge Order
**Wave 1:** `feat/errors` first → all others in any order
**Wave 2:** `feat/wire-up` first → tests → openspec/docs/readme → CI last
## External Tool Interaction
### Git
- Call via `std::process::Command::new("git")`
- Always capture stderr for error messages
- Parse stdout for branch lists, worktree info
### Tmux
- Call via `std::process::Command::new("tmux")`
- Builder pattern: accumulate ops, execute or return as strings (for testing/dry-run)
- Session names: `paw-<project-name>`
- **Critical: apply `tiled` layout before each new split**, not just at the end. Without this, tmux runs out of space after ~5 panes even on large terminals.
- Apply final `tiled` layout after all panes for clean alignment.
- Enable `mouse on` per-session (not globally) so users can click panes and drag borders.
- Set pane titles to `<branch> → <cli>` via `select-pane -T` so users can identify panes at a glance.
- Enable `pane-border-status top` and `pane-border-format " #{pane_title} "` per-session to display titles.
## Testing Conventions
### Unit Tests
- In `#[cfg(test)] mod tests {}` at bottom of each module
- Every OpenSpec scenario maps to at least one test
- `tempfile` for filesystem tests
- No system side effects
### Integration Tests
- In `tests/` directory
- `assert_cmd` for CLI binary tests
- `predicates` for output assertions
- Tmux-dependent tests marked `#[ignore]`
- Shared helpers in `tests/helpers/mod.rs`
### Coverage
- Tool: `cargo-llvm-cov`
- Local: `cargo llvm-cov --html` → `target/llvm-cov/html/`
- CI uploads LCOV to Codecov
- Target: >= 80% line coverage
## Documentation
### Four Layers
1. `--help` text — comprehensive with examples
2. README.md — landing page with badges, quick starts, CLI table
3. mdBook site — full user guide at `https://bearicorn.github.io/git-paw/`
4. `cargo doc` / Rustdoc — API docs for contributors
All layers must be consistent.
### mdBook
- Source: `docs/src/`, Config: `docs/book.toml`
- OpenSpec specs embedded via `{{#include}}` — single source of truth
- Two quick start tutorials: same-CLI mode and per-branch CLI mode
### OpenSpec
- Specs in `openspec/specs/<capability>/spec.md`
- RFC 2119 keywords, GIVEN/WHEN/THEN scenarios with `Test:` annotations
- Included in mdBook docs site
### Changelog
- [Keep a Changelog](https://keepachangelog.com/) format
- Generated from Conventional Commits using `git-cliff`
- Config: `cliff.toml`
- Generate: `git cliff -o CHANGELOG.md`
- CI auto-generates on tag push
## Platform Support
- **macOS** (ARM + x86) — fully supported
- **Linux** (x86_64 + ARM64) — fully supported
- **Windows** — WSL only. Native Windows is not supported (tmux is Unix-only).
## Release & Distribution
Handled by `cargo-dist`. Config: `[workspace.metadata.dist]` in Cargo.toml.
- **Trigger:** push tag `v*`
- **Automatic:** cross-platform binaries, checksums, shell installer, Homebrew formula
- **Workflow:** `.github/workflows/release.yml` (generated by cargo-dist)
- **Homebrew tap:** `bearicorn/homebrew-tap`
Install methods:
```bash
cargo install git-paw
brew install bearicorn/tap/git-paw
curl --proto '=https' --tlsv1.2 -LsSf \
## Project Metadata
- License: MIT
- MSRV: current stable
- Targets: macOS (ARM + x86), Linux (x86_64 + ARM64), Windows (WSL)
## Commits
Commits should not include any reference to claude. It should also be one clean linear commit. The commit should also resolve the issue that you are working on.