From 7f206ebafd2f8bb7421276955a179bfa3fc76ce3 Mon Sep 17 00:00:00 2001 From: Joseph O'Brien <98370624+89jobrien@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:39:36 -0400 Subject: [PATCH] docs: update CLAUDE.md for workspace layout, add HANDOFF.md --- CLAUDE.md | 64 +++++++++++++++++++++++++++++++++++++----------------- HANDOFF.md | 37 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 HANDOFF.md diff --git a/CLAUDE.md b/CLAUDE.md index 8d7e017..9203f83 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,36 +9,60 @@ A modern dotfiles manager written in Rust — a pure Rust alternative to GNU Sto ## Build & Test Commands ```bash -cargo build # build -cargo test # run all tests (unit + integration) -cargo test --lib # unit tests only -cargo test --test integration # integration tests only -cargo test # run a single test by name -cargo clippy # lint -cargo fmt --check # check formatting +cargo build # build all workspace crates +cargo build -p notfiles # build just the notfiles binary +cargo test # run all tests across workspace +cargo test -p notcore # test notcore only +cargo test -p notfiles # test notfiles only +cargo test -p notsecrets # test notsecrets only +cargo test -p nothooks # test nothooks only +cargo clippy --workspace # lint all crates +cargo fmt --check # check formatting ``` +## Workspace Structure + +This is a Cargo workspace with 5 crates under `crates/`: + +| Crate | Purpose | +|-------|---------| +| `notcore` | Shared types: `Config`, `NotfilesError`, `expand_tilde`, `HookPhase`, `HookSpec`, `Report`, `StepStatus` | +| `notfiles` | Dotfiles linker — lib + `notfiles` binary (symlink/copy, init, status) | +| `notsecrets` | Age key retrieval via Bitwarden, file, or prompt; SOPS decryption | +| `nothooks` | Nushell hook runner with dot/setup phases and state persistence | +| `notstrap` | New-machine bootstrap orchestrator — ties all crates together | + ## Architecture -The binary has four subcommands: `init`, `link`, `unlink`, `status`. CLI parsing uses clap derive in `src/cli.rs`; command dispatch happens in `src/main.rs`. +### notfiles (primary user-facing tool) -**Core flow for `link`:** `main` → `resolve_packages` (discover subdirs or validate requested names) → `collect_files` (recursive walk with ignore filtering) → `linker::link_package` (create symlinks or copies, record in state). +Four subcommands: `init`, `link`, `unlink`, `status`. CLI parsing in `crates/notfiles/src/cli.rs`; dispatch in `src/main.rs`. -Key modules: -- **linker** — Creates/removes symlinks or copies. Manages `State` (serialized to `.notfiles-state.toml` in the dotfiles dir) which tracks every linked file with source, target, method, and timestamp. Handles conflict detection, `--force` backups, and empty-parent cleanup on unlink. -- **config** — Parses `notfiles.toml`. Provides per-package overrides for method (symlink/copy), target directory, and ignore patterns. Falls back to `[defaults]` section values. -- **package** — Discovers packages (non-hidden subdirectories of the dotfiles dir) and recursively collects files, filtering through `IgnoreMatcher`. -- **ignore** — Glob-based ignore matching using `globset`. Matches both full relative paths and individual path components. -- **paths** — `expand_tilde` utility. -- **status** — Compares expected state (files on disk + config) against actual state (symlinks/copies + state file) to report linked/copied/missing/conflict/orphan. -- **error** — `NotfilesError` enum via `thiserror`. +**Core flow for `link`:** `main` → `resolve_packages` → `collect_files` (recursive walk with ignore filtering) → `linker::link_package` (create symlinks or copies, record in state). -Integration tests (`tests/integration.rs`) run the compiled binary against temp directories using `tempfile`. +Key modules in `crates/notfiles/src/`: +- **linker** — Creates/removes symlinks or copies. Manages `State` (`.notfiles-state.toml`) tracking every linked file. Handles conflict detection, `--force` backups, empty-parent cleanup on unlink. +- **config** — Parses `notfiles.toml`. Per-package overrides for method, target, ignore. Falls back to `[defaults]`. +- **package** — Discovers packages (non-hidden subdirs) and recursively collects files via `IgnoreMatcher`. +- **ignore** — Glob-based ignore matching using `globset`. +- **status** — Compares expected vs actual state: linked/copied/missing/conflict/orphan. + +### notsecrets + +`AgeKeySource` trait with three implementations: `BitwardenSource` (bw CLI), `FileSource`, `PromptSource`. `resolve_age_key()` tries each in order. `install_age_key()` writes to `~/.config/sops/age/keys.txt` (mode 0600). `decrypt_sops()` shells out to `sops --decrypt`. + +### nothooks + +`HookRunner` executes `.nu` scripts via `nu