# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

- Build: `cargo check`
- Run all tests (10 tests): `cargo test`
- Run a single test: `cargo test --test <name>` (e.g. `cargo test --test crypto_test`)
- Run binary in TUI mode: `cargo run`
- Run binary in CLI mode: `cargo run -- <subcommands>` (e.g. `cargo run -- cc p l`)
- Fix warnings: `cargo fix --lib -p closure-app && cargo fix --bin closure`

## Architecture

This is a Rust binary crate (`closure-app` on crates.io, binary name `closure`) — a TUI/CLI tool for managing coding agent configurations. Entry point dispatches: no args → TUI, args → CLI.

### Module layout

- `src/core/error.rs` — `ClosureError` enum (thiserror), `Result<T>` alias. All modules use this error type.
- `src/core/crypto.rs` — `encrypt()` / `decrypt()` using Argon2id (key derivation) + AES-256-GCM. Ciphertext format: `salt_len(u8) || salt || nonce(12B) || ciphertext+tag`.
- `src/core/provider.rs` — `Provider` enum (serde-tagged: `ClaudeCode` with env map + model, `Codex` with api_key/base_url/model/model_provider/review_model). `ProviderStore` is the root encrypted structure (`version` + `providers` vec).
- `src/core/store.rs` — `Store` handles file I/O under `~/.kozbox/closure/workdata/`: `providers.enc` (encrypted), `providers.json` (temp decrypted, 0600), `state.json` (active provider per agent). Methods: `load`, `save`, `authenticate`, `logout`, `load_state`, `save_state`.
- `src/core/agent.rs` — `Agent` trait with single method `apply(&self, provider)`. `ClaudeCodeAdapter` writes to `~/.claude/settings.json` (only touches `.env` and `.model`). `CodexAdapter` writes to `~/.codex/config.toml` and `~/.codex/auth.json` (touches model/model_provider/review_model/model_providers.*.base_url and OPENAI_API_KEY).
- `src/core/sync.rs` — `sync_dirs(src, dst)` bidirectional file sync via mtime comparison, pure Rust.
- `src/cli/args.rs` — clap derive structs. Agent aliases: `claude-code`→`cc`, `codex`→`cx`. Subcommand aliases: `provider`→`p`, `select`→`s`, `list`→`l`/`ls`, `add`→`a`, `remove`→`r`.
- `src/cli/commands.rs` — `run(cli)` dispatches to auth/sync/agent commands. Reads from decrypted `providers.json` (fails with `AuthRequired` if not authenticated).
- `src/tui/app.rs` — ratatui event loop, `Screen` enum routing (Auth/List), filter mode for provider search.
- `src/tui/screens/auth.rs` — password input screen, calls `Store::authenticate`.
- `src/tui/screens/list.rs` — provider list with vim-style navigation, filter, selection via Enter/s.

### Integration tests (under `tests/`)

Tests use `closure_app::core::...` as the crate prefix. Tests that run a subprocess use `assert_cmd::Command::cargo_bin("closure")` since the binary name is unchanged.

### Design constraints

- Agent configs are **selectively written**: only the provider-related fields are touched; all other settings (plugins, hooks, etc.) are preserved.
- The decrypted temp file (`providers.json`) is never synced and never committed.
- CJK text should not appear in ASCII art/diagrams in docs — pure ASCII in box-drawing code blocks.
