/ CLAUDE.md
CLAUDE.md
  1  # CLAUDE.md
  2  
  3  This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
  4  
  5  ## Project Overview
  6  
  7  Auths is a decentralized identity system for developers. It enables cryptographic commit signing with Git-native storage using KERI-inspired identity principles. No central server or blockchain—just Git and cryptography.
  8  
  9  ## Build & Test Commands
 10  
 11  ```bash
 12  # Build
 13  cargo build                              # Debug build
 14  cargo build --release                    # Release build
 15  cargo build --package auths_cli         # Build specific crate
 16  
 17  # Test
 18  cargo nextest run --workspace            # Run all tests (except doc tests)
 19  cargo test --all --doc                   # Run doc tests (nextest doesn't support these)
 20  cargo nextest run -p auths_verifier     # Test specific crate
 21  cargo nextest run -E 'test(verify_chain)' # Run single test by name
 22  
 23  # Lint & Format
 24  cargo fmt --all                          # Format code
 25  cargo fmt --check --all                  # Check formatting (CI uses this)
 26  cargo clippy --all-targets --all-features -- -D warnings
 27  
 28  # Security audit
 29  cargo audit
 30  
 31  # WASM verification (auths-verifier only)
 32  # Must cd into the crate — resolver = "3" rejects --features from workspace root
 33  cd crates/auths-verifier && cargo check --target wasm32-unknown-unknown --no-default-features --features wasm
 34  ```
 35  
 36  ## Code Comments
 37  
 38  You SHOULD NOT add code comments that explain processes - the code should be self-evident
 39  
 40  Only leave comments where a particular decision was made - i.e. opinionated code
 41  Or in places where
 42  
 43  If you are leaving comments to explain processes, it is a sign to break the function into modular components and name them clearly.
 44  
 45  ## Docstrings
 46  
 47  Doc strings should look like this, including description, Args, and Usage code block
 48  ```
 49  /// Verifies a GitHub Actions OIDC token and extracts its claims.
 50  ///
 51  /// Args:
 52  /// * `token`: The raw JWT string provided by the GitHub Actions environment.
 53  /// * `jwks_client`: The client used to fetch GitHub's public keys.
 54  ///
 55  /// Usage:
 56  /// ```ignore (add ignore where necessary like doc tests)
 57  /// let claims = verify_github_token(&raw_token, &jwks_client).await?;
 58  /// ```
 59  ```
 60  All public functions, and public API functions should be documented
 61  Private functions don't need to be documented - but you can if it seems like an important function
 62  
 63  ## Crate Architecture
 64  
 65  ```
 66  Layer 0: auths-crypto     (cryptographic primitives, DID:key encoding)
 67  Layer 1: auths-verifier   (standalone verification, FFI/WASM)
 68  Layer 2: auths-core       (keychains, signing, policy, ports)
 69  Layer 3: auths-id         (identity, attestation, KERI, traits)
 70           auths-policy     (policy expression engine)
 71  Layer 4: auths-storage    (Git/SQL storage adapters)
 72           auths-sdk        (application services)
 73  Layer 5: auths-infra-git  (Git client adapter)
 74           auths-infra-http (HTTP client adapter)
 75  Layer 6: auths-cli        (user commands)
 76  ```
 77  
 78  **auths-crypto**: Layer 0 cryptographic primitives — Ed25519, KERI key parsing, DID:key encoding.
 79  
 80  **auths-verifier**: Minimal-dependency verification library for FFI/WASM embedding. Depends only on auths-crypto.
 81  
 82  **auths-core**: Foundation layer with platform keychains (macOS Security Framework, Linux Secret Service, Windows Credential Manager), signing, policy, and port abstractions.
 83  
 84  **auths-id**: Identity and attestation domain logic. Defines key traits: `IdentityStorage`, `AttestationSource`, `AttestationSink`. KERI identity management. Refs stored under `refs/auths/` and `refs/keri/`.
 85  
 86  **auths-storage**: Storage backend implementations — `GitAttestationStorage`, `GitIdentityStorage`, `GitRefSink`, `GitRegistryBackend`.
 87  
 88  **auths-cli**: Command-line interface with three binaries: `auths`, `auths-sign`, `auths-verify`. Uses clap for argument parsing.
 89  
 90  **auths-verifier**: Minimal-dependency verification library designed for embedding. Supports FFI (feature: `ffi`), WASM (feature: `wasm`). Does NOT depend on git2 or heavy deps. Core functions: `verify_chain()`, `verify_with_keys()`, `did_key_to_ed25519()`.
 91  
 92  ## Key Patterns
 93  
 94  **Git as Storage**: All identity data and attestations are stored as Git refs. The `~/.auths` directory is a Git repository.
 95  
 96  **DID Types**:
 97  - `did:keri:...` - Primary identity (derived from Ed25519 key)
 98  - `did:key:z...` - Device identifiers (Ed25519 multicodec format)
 99  
100  **Attestation Structure**: JSON-serialized, canonicalized with `json-canon`, dual-signed (issuer + device). Fields include: version, rid, issuer, subject, device_public_key, identity_signature, device_signature, capabilities, expires_at.
101  
102  **Trait Abstractions**: Platform-specific code uses traits (`Storage`, `DidResolver`) with conditional compilation for cross-platform support.
103  
104  **Clock Injection**: `Utc::now()` is banned in `auths-core/src/` and `auths-id/src/` outside `#[cfg(test)]`. All time-sensitive functions accept `now: DateTime<Utc>` as their first parameter. The `auths-sdk` layer calls `clock.now()` and passes the value down. The CLI calls `Utc::now()` at the presentation boundary. Never add `Utc::now()` to domain or core logic — inject it instead.
105  
106  ## Feature Flags
107  
108  - `auths-core`: `keychain-file-fallback`, `keychain-windows`, `crypto-secp256k1`, `test-utils`
109  - `auths-id`: `auths-radicle`, `indexed-storage`
110  - `auths-verifier`: `ffi` (enables libc, FFI module), `wasm` (enables wasm-bindgen)
111  
112  ## Writing Tests
113  
114  Each crate uses a single integration-test binary: `tests/integration.rs` (entry point) with submodules under `tests/cases/`. Add new test cases as `tests/cases/<topic>.rs` and re-export from `tests/cases/mod.rs`.
115  
116  Use `crates/auths-test-utils` for shared helpers — add `auths-test-utils.workspace = true` under `[dev-dependencies]`:
117  - `auths_test_utils::crypto::get_shared_keypair()` — shared Ed25519 key via `OnceLock` (fast, use by default)
118  - `auths_test_utils::crypto::create_test_keypair()` — fresh key per call (use only when uniqueness matters)
119  - `auths_test_utils::git::init_test_repo()` — new `TempDir` + initialised git repo
120  - `auths_test_utils::git::get_cloned_test_repo()` — cloned copy of a shared template repo (faster for read-only setup)
121  
122  See `TESTING_STRATEGY.md` for full details.
123  
124  ## CI Requirements
125  
126  Tests require Git configuration, ask the user for this and help them find it:
127  ```bash
128  git config --global user.name "{user_current_name}"
129  git config --global user.email "{user_current_email}"
130  ```
131  
132  CI runs on: Ubuntu (x86_64), macOS (aarch64), Windows (x86_64). Rust 1.93 with clippy and rustfmt.
133  
134  When the user is getting errors locally, don't forget to remind them to reinstall any local changes (e.g. `cargo install --path crates/auths-cli`)
135  
136  1. **DRY & Separated**: Business workflows entirely separated from I/O. No monolithic functions.
137  2. **Documentation**: Rustdoc mandatory for all exported SDK/Core items. `/// Description`, `/// Args:`, `/// Usage:` blocks per CLAUDE.md conventions.
138  3. **Minimalism**: No inline comments explaining process. Use structural decomposition. Per CLAUDE.md: only comment opinionated decisions.
139  4. **Domain-Specific Errors**: `thiserror` enums only. No `anyhow::Error` or `Box<dyn Error>` in Core/SDK. Example: `DomainError::InvalidSignature`, `StorageError::ConcurrentModification`.
140  5. **`thiserror`/`anyhow` Translation Boundary**: The ban on `anyhow` in Core/SDK is strict, but the CLI and API servers (`auths-auth-server`, `auths-registry-server`) **must** define a clear translation boundary where domain errors are wrapped with operational context. The CLI and server crates continue using `anyhow::Context` to collect system-level information (paths, environment, subprocess output), but always wrap the domain `thiserror` errors cleanly — never discard the typed error:
141      ```rust
142      // auths-cli/src/commands/sign.rs (Presentation Layer)
143      // Converts the strict thiserror SigningError into a contextualized anyhow::Error
144      let signature = sign_artifact(&config, data)
145          .with_context(|| format!("Failed to sign artifact for namespace: {}", config.namespace))?;
146      ```
147      The existing SDK error types (`SetupError`, `DeviceError`, `RegistrationError` in `crates/auths-sdk/src/error.rs`) currently wrap `anyhow::Error` in their `StorageError` and `NetworkError` variants (e.g., `StorageError(#[source] anyhow::Error)`). These must be migrated to domain-specific `thiserror` variants during Epic 1/2 execution — the `anyhow` wrapping is a transitional pattern, not a permanent design. The `map_storage_err()` and `map_device_storage_err()` helper functions should be replaced with direct `From` impls on the domain storage errors.
148  6. **No reverse dependencies**: Core and SDK must never reference presentation layer crates.