|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Build, Test, and Development Commands |
| 6 | + |
| 7 | +### Building |
| 8 | +```bash |
| 9 | +# Build in debug mode |
| 10 | +cargo build |
| 11 | + |
| 12 | +# Build optimized release binary |
| 13 | +cargo build --release |
| 14 | + |
| 15 | +# Check code without building (faster feedback) |
| 16 | +cargo check |
| 17 | +``` |
| 18 | + |
| 19 | +### Testing |
| 20 | +```bash |
| 21 | +# Run all tests |
| 22 | +cargo test --all |
| 23 | + |
| 24 | +# Run tests with output displayed |
| 25 | +cargo test --all -- --nocapture |
| 26 | + |
| 27 | +# Run a specific test |
| 28 | +cargo test test_prompt -- --nocapture |
| 29 | + |
| 30 | +# Run tests across all Rust versions (stable, beta, nightly) |
| 31 | +cargo test --locked |
| 32 | +``` |
| 33 | + |
| 34 | +### Code Quality |
| 35 | +```bash |
| 36 | +# Format code (required before commit) |
| 37 | +cargo fmt --all |
| 38 | + |
| 39 | +# Check formatting without making changes |
| 40 | +cargo fmt --all -- --check |
| 41 | + |
| 42 | +# Run clippy linter |
| 43 | +cargo clippy --all-targets --all-features -- -D warnings |
| 44 | + |
| 45 | +# Security audit dependencies |
| 46 | +cargo audit |
| 47 | +``` |
| 48 | + |
| 49 | +### Local Development |
| 50 | +```bash |
| 51 | +# Run the binary locally against current repo |
| 52 | +./target/debug/aigitcommit |
| 53 | + |
| 54 | +# Run with verbose output for debugging |
| 55 | +./target/debug/aigitcommit -v |
| 56 | + |
| 57 | +# Check environment configuration |
| 58 | +cargo run -- --check-env |
| 59 | + |
| 60 | +# Test API connectivity |
| 61 | +cargo run -- --check-model |
| 62 | +``` |
| 63 | + |
| 64 | +### Installation for Development |
| 65 | +```bash |
| 66 | +# Install locally for testing in other repos |
| 67 | +cargo install --path . |
| 68 | +``` |
| 69 | + |
| 70 | +## Code Architecture |
| 71 | + |
| 72 | +### High-Level Overview |
| 73 | + |
| 74 | +AIGitCommit is a CLI tool that generates semantic commit messages from staged Git changes using AI. The architecture follows a clear separation of concerns: |
| 75 | + |
| 76 | +1. **CLI Layer** (`cli.rs`): Parses command-line arguments and options using clap |
| 77 | +2. **Git Layer** (`git/`): Provides Git operations via git2 (diff, logs, commit) |
| 78 | +3. **AI Layer** (`openai.rs`): Interfaces with OpenAI-compatible APIs |
| 79 | +<<<<<<< HEAD |
| 80 | +4. **Cache Layer** (`cache.rs`): Provides lightweight, stable FNV-1a-hashed on-disk caching of responses |
| 81 | +5. **Utilities** (`utils.rs`): Shared utilities for output formatting, environment config, file operations |
| 82 | + |
| 83 | +### Module Responsibilities |
| 84 | + |
| 85 | +#### `main.rs` - Application Entry Point |
| 86 | +- Orchestrates the workflow: parse args → get git info → call AI → format output → optionally commit |
| 87 | +- Handles three main flows: |
| 88 | + - Hook installation (`install-hook` subcommand) |
| 89 | + - Environment/model checking (`--check-env`, `--check-model`) |
| 90 | + - Main workflow: analyze staged changes → generate message → display/commit |
| 91 | +- Initializes tracing/logging based on verbosity flag (`-v`/`--verbose`) |
| 92 | + |
| 93 | +#### `cli.rs` - Command-Line Interface |
| 94 | +- Defines `Cli` struct with all command-line flags and options |
| 95 | +- Supports subcommands: `install-hook` for git hook setup |
| 96 | +- Options include: `--commit`, `--json`, `--copy-to-clipboard`, `--signoff`, `--yes`, `--no-cache`, `--clear-cache`, `--no-table`, `--save`, etc. |
| 97 | +- Uses clap's derive macros for parsing and help text generation |
| 98 | + |
| 99 | +#### `git/repository.rs` - Git Operations |
| 100 | +- `Repository` struct wraps git2::Repository for high-level operations |
| 101 | +- `get_diff()`: Gets staged changes as lines (`git diff --cached`) |
| 102 | +- `get_logs(count)`: Gets recent commit messages for context on style/conventions |
| 103 | +- `commit(&message)`: Creates a commit with the generated message |
| 104 | +- `get_author()`: Retrieves author info from git config |
| 105 | +- Filters out common noise (lock files, generated code) from diffs |
| 106 | + |
| 107 | +#### `git/message.rs` - Commit Message Representation |
| 108 | +- `GitMessage` struct represents a formatted commit message |
| 109 | +- Follows Conventional Commits specification (type: scope: title + body) |
| 110 | +- Supports Signed-off-by appending |
| 111 | +- Handles serialization to different formats (JSON, plain text, table) |
| 112 | + |
| 113 | +#### `openai.rs` - AI Integration |
| 114 | +- `OpenAI` struct wraps async-openai's Client |
| 115 | +- Configures API endpoint, authentication, proxy, and timeouts from environment |
| 116 | +- `chat()`: Sends messages to OpenAI API and returns response |
| 117 | +- `check_model()`: Verifies model availability before generating messages |
| 118 | +- `prompt()`: Uses Askama templates to format user prompt with logs and diffs |
| 119 | +- Template path: `templates/user.txt` |
| 120 | + |
| 121 | +#### `cache.rs` - Response Cache Layer |
| 122 | +- `Cache` struct manages file-based caching under `<repo>/.git/aigitcommit-cache/` |
| 123 | +- Keys are derived from stable 64-bit FNV-1a hashing of variables that alter prompt inputs (model name, system prompt, staged diff lines, and recent git commit log messages). |
| 124 | +- When staged diffs and surrounding context are unchanged, cached responses are reused immediately, avoiding redundant API calls |
| 125 | +- Exposes options to bypass (`--no-cache`) or clear (`--clear-cache`) |
| 126 | + |
| 127 | +#### `utils.rs` - Shared Utilities |
| 128 | +- Environment variable reading with fallbacks |
| 129 | +- Output formatting: `OutputFormat` enum supporting Table, JSON, and plain text |
| 130 | +- Hook installation logic |
| 131 | +- File I/O operations (save to file) |
| 132 | +- Signoff configuration handling (env vars vs git config) |
| 133 | + |
| 134 | +### Build System |
| 135 | + |
| 136 | +- Uses Rust edition 2024 |
| 137 | +- `build.rs`: Generates `built.rs` (via `built` crate) containing build metadata (version, authors, etc.) |
| 138 | +- Optimized release profile: LTO enabled, single codegen unit, stripped binary |
| 139 | +- Key dependencies: |
| 140 | + - `git2`: Git operations |
| 141 | + - `async-openai`: OpenAI API client |
| 142 | + - `tokio`: Async runtime |
| 143 | + - `askama`: Template rendering for prompts |
| 144 | + - `clap`: CLI parsing |
| 145 | + - `tabled`: Table formatting |
| 146 | + - `cliclack`: Interactive prompts |
| 147 | + |
| 148 | +### Environment Variables |
| 149 | + |
| 150 | +The application can be configured using the following environment variables: |
| 151 | + |
| 152 | +| Variable | Description | Default | |
| 153 | +| --------------------- | ----------------------------------------------------------------------------------------------- | --------------------------------- | |
| 154 | +| `OPENAI_API_TOKEN` | API token / key for authenticating with the AI service | `""` | |
| 155 | +| `OPENAI_API_BASE` | Base URL for the OpenAI-compatible API endpoint | standard OpenAI endpoint | |
| 156 | +| `OPENAI_MODEL_NAME` | The model identifier used for generating commit messages | model configured on OpenAI client | |
| 157 | +| `OPENAI_API_PROXY` | Optional proxy server address | None | |
| 158 | +| `OPENAI_API_TIMEOUT` | Optional HTTP client request timeout in seconds | default no timeout | |
| 159 | +| `AIGITCOMMIT_SIGNOFF` | Opt-in truthy value (`1`, `true`, `yes`, `on`) to enforce repository-wide Signed-off-by trailer | None | |
| 160 | +| `TEST_REPO_PATH` | Path pointing to a test repository for integration testing | `.` | |
| 161 | + |
| 162 | +### Key Design Decisions |
| 163 | + |
| 164 | +1. **libgit2 over git CLI**: Uses git2 crate instead of spawning `git` command for security and performance |
| 165 | +2. **Async Runtime**: Uses tokio for async API calls; main.rs runs with `#[tokio::main]` |
| 166 | +3. **Template System**: Uses Askama templates (`templates/user.txt`, `templates/system.txt`) for prompts |
| 167 | +4. **Error Handling**: Returns `Result<T, Box<dyn Error>>` for flexible error propagation |
| 168 | +5. **Conventional Commits**: Expects AI response in format `title\n\nbody` (split on double newline) |
| 169 | + |
| 170 | +### Testing |
| 171 | + |
| 172 | +- Unit tests are placed alongside code with `#[cfg(test)]` modules |
| 173 | +- `openai.rs` contains integration test for prompt generation (requires `TEST_REPO_PATH` env var) |
| 174 | +- CI runs tests on stable, beta, and nightly Rust toolchains |
| 175 | +- Use `cargo test --all --locked` to match CI behavior |
| 176 | + |
| 177 | +### Style and Development Guidelines |
| 178 | + |
| 179 | +- **Code Formatting**: Ensure all code is cleanly formatted before committing. Check via `cargo fmt --all -- --check` and fix with `cargo fmt --all`. |
| 180 | +- **Linting**: Keep code clean and warning-free. Always run `cargo clippy --all-targets --all-features -- -D warnings` to verify. |
| 181 | +- **Imports**: Prefer grouping standard library imports first, then internal crates, then third-party dependency modules. |
| 182 | +- **Tracing / Logging**: Make clean use of `tracing::debug`, `tracing::trace`, `tracing::warn`, etc. For details regarding CLI tracing levels, refer to logger configuration in [src/main.rs](src/main.rs). |
| 183 | + |
| 184 | +||||||| ab6a6cc |
| 185 | +======= |
| 186 | +4. **Utilities** (`utils.rs`): Shared utilities for output formatting, environment config, file operations |
| 187 | + |
| 188 | +### Module Responsibilities |
| 189 | + |
| 190 | +#### `main.rs` - Application Entry Point |
| 191 | +- Orchestrates the workflow: parse args → get git info → call AI → format output → optionally commit |
| 192 | +- Handles three main flows: |
| 193 | + - Hook installation (`install-hook` subcommand) |
| 194 | + - Environment/model checking (`--check-env`, `--check-model`) |
| 195 | + - Main workflow: analyze staged changes → generate message → display/commit |
| 196 | +- Initializes tracing/logging based on verbosity flag |
| 197 | + |
| 198 | +#### `cli.rs` - Command-Line Interface |
| 199 | +- Defines `Cli` struct with all command-line flags and options |
| 200 | +- Supports subcommands: `install-hook` for git hook setup |
| 201 | +- Options include: `--commit`, `--json`, `--copy-to-clipboard`, `--signoff`, `--yes`, etc. |
| 202 | +- Uses clap's derive macros for parsing and help text generation |
| 203 | + |
| 204 | +#### `git/repository.rs` - Git Operations |
| 205 | +- `Repository` struct wraps git2::Repository for high-level operations |
| 206 | +- `get_diff()`: Gets staged changes as lines (`git diff --cached`) |
| 207 | +- `get_logs(count)`: Gets recent commit messages for context on style/conventions |
| 208 | +- `commit(&message)`: Creates a commit with the generated message |
| 209 | +- `get_author()`: Retrieves author info from git config |
| 210 | +- Filters out common noise (lock files, generated code) from diffs |
| 211 | + |
| 212 | +#### `git/message.rs` - Commit Message Representation |
| 213 | +- `GitMessage` struct represents a formatted commit message |
| 214 | +- Follows Conventional Commits specification (type: scope: title + body) |
| 215 | +- Supports Signed-off-by appending |
| 216 | +- Handles serialization to different formats (JSON, plain text, table) |
| 217 | + |
| 218 | +#### `openai.rs` - AI Integration |
| 219 | +- `OpenAI` struct wraps async-openai's Client |
| 220 | +- Configures API endpoint, authentication, proxy, and timeouts from environment |
| 221 | +- `chat()`: Sends messages to OpenAI API and returns response |
| 222 | +- `check_model()`: Verifies model availability before generating messages |
| 223 | +- `prompt()`: Uses Askama templates to format user prompt with logs and diffs |
| 224 | +- Template path: `templates/user.txt` |
| 225 | + |
| 226 | +#### `utils.rs` - Shared Utilities |
| 227 | +- Environment variable reading with fallbacks |
| 228 | +- Output formatting: `OutputFormat` enum supporting Table, JSON, and plain text |
| 229 | +- Hook installation logic |
| 230 | +- File I/O operations (save to file) |
| 231 | +- Signoff configuration handling (env vars vs git config) |
| 232 | + |
| 233 | +### Build System |
| 234 | + |
| 235 | +- Uses Rust edition 2024 |
| 236 | +- `build.rs`: Generates `built.rs` (via `built` crate) containing build metadata (version, authors, etc.) |
| 237 | +- Optimized release profile: LTO enabled, single codegen unit, stripped binary |
| 238 | +- Key dependencies: |
| 239 | + - `git2`: Git operations |
| 240 | + - `async-openai`: OpenAI API client |
| 241 | + - `tokio`: Async runtime |
| 242 | + - `askama`: Template rendering for prompts |
| 243 | + - `clap`: CLI parsing |
| 244 | + - `tabled`: Table formatting |
| 245 | + - `cliclack`: Interactive prompts |
| 246 | + |
| 247 | +### Key Design Decisions |
| 248 | + |
| 249 | +1. **libgit2 over git CLI**: Uses git2 crate instead of spawning `git` command for security and performance |
| 250 | +2. **Async Runtime**: Uses tokio for async API calls; main.rs runs with `#[tokio::main]` |
| 251 | +3. **Template System**: Uses Askama templates (`templates/user.txt`, `templates/system.txt`) for prompts |
| 252 | +4. **Error Handling**: Returns `Result<T, Box<dyn Error>>` for flexible error propagation |
| 253 | +5. **Conventional Commits**: Expects AI response in format `title\n\nbody` (split on double newline) |
| 254 | + |
| 255 | +### Testing |
| 256 | + |
| 257 | +- Unit tests are placed alongside code with `#[cfg(test)]` modules |
| 258 | +- `openai.rs` contains integration test for prompt generation (requires `TEST_REPO_PATH` env var) |
| 259 | +- CI runs tests on stable, beta, and nightly Rust toolchains |
| 260 | +- Use `cargo test --all --locked` to match CI behavior |
| 261 | +>>>>>>> develop |
0 commit comments