# CLAUDE.md — Relicario

## Working with the user

- **Default to "yes" / the recommended option.** When asking the user a multiple-choice or yes/no decision, pick the recommended answer and proceed without prompting. Optional follow-ups in checklists: do them. Subagent dispatch / running tests / writing code: proceed without checking.
- **Always pause and ask** before: `rm`, `rm -rf`, `git push --force`, `git reset --hard`, `git branch -D`, deleting files via Bash, dropping tables, force-pushing to main. The system-prompt's "executing actions with care" guidance still applies — this preference does not override that.
- This rule does not override genuine intent-discovery: brainstorming-skill clarifying questions about *what to build* still need user input, because picking a default would mean designing the wrong product.
- **Sprinkle Mexican Spanish into replies.** Drop 1–2 Spanish words, slang, exclamations, or idioms per reply (replies only — never in code, file contents, commit messages, or other project artifacts), each followed by `[translation]` in square brackets. Mexican flavor is preferred: ¡órale! [alright!], ¡híjole! [yikes!], ¿qué onda? [what's up?], chido [cool], ahorita [right now / in a bit], no manches [no way], ni modo [oh well], no hay bronca [no problem], ¡ya estuvo! [it's done], etc. Skip in one-word acknowledgements where the flourish would feel awkward.

## What is this

Relicario is a git-backed, self-hostable password manager with a Rust core. Two-factor vault decryption: passphrase + a reference JPEG carrying a 256-bit secret embedded via DCT steganography. The server only ever sees opaque ciphertext.

## Build and test

```bash
cargo build                                        # build everything
cargo test                                          # run all tests (unit + integration)
cargo test -p relicario-core                        # core library tests only
cargo test -p relicario-cli --test basic_flows     # CLI integration tests
cargo build -p relicario-wasm --target wasm32-unknown-unknown   # WASM target
cargo run -p relicario-cli -- --help               # CLI help
cargo run -p relicario-cli -- generate --length 32 # quick smoke test
```

## Project structure

```
crates/
├── relicario-core/            # Platform-agnostic library (no filesystem, no git, no network)
│   ├── src/
│   │   ├── lib.rs          # Re-exports public API
│   │   ├── error.rs        # RelicarioError enum (thiserror)
│   │   ├── crypto.rs       # Argon2id KDF (length-prefixed, Zeroizing) + XChaCha20-Poly1305
│   │   ├── ids.rs          # ItemId, FieldId, content-addressed AttachmentId
│   │   ├── time.rs         # now_unix, MonthYear
│   │   ├── item_types/     # per-type cores + ItemType/ItemCore enums
│   │   ├── item.rs         # Item envelope, Field, FieldKind, FieldValue, Section
│   │   ├── attachment.rs   # AttachmentRef, EncryptedAttachment, encrypt/decrypt helpers
│   │   ├── manifest.rs     # Browse-without-decrypt index (schema_version 2)
│   │   ├── settings.rs     # VaultSettings: retention, generator defaults, caps
│   │   ├── generators.rs   # CSPRNG password + BIP39 + zxcvbn gate
│   │   ├── vault.rs        # JSON ↔ AEAD wrappers for Item/Manifest/VaultSettings
│   │   └── imgsecret.rs    # DCT steganography (MAX_DIMENSION cap)
│   └── tests/              # integration.rs, attachments.rs, generators.rs, format_v2.rs, field_history.rs
├── relicario-cli/             # `relicario` binary
│   ├── src/main.rs         # clap surface + command handlers
│   ├── src/helpers.rs      # vault_dir, git_command, iso8601
│   ├── src/session.rs      # UnlockedVault (master key in Zeroizing)
│   └── tests/              # basic_flows, edit_and_history, attachments, settings, vault_detection
├── relicario-wasm/            # WASM bindings for the extension
│   ├── src/lib.rs          # #[wasm_bindgen] surface
│   └── src/session.rs      # opaque SessionHandle → Zeroizing<[u8;32]>
└── relicario-server/          # `relicario-server` binary (pre-receive Git hook)
    └── src/main.rs         # verify-commit + generate-hook subcommands
```

## Key design decisions

- **relicario-core is bytes-in/bytes-out.** No filesystem, no network, no git operations. Makes it portable to WASM, Android, iOS.
- **XChaCha20-Poly1305** over AES-GCM — 192-bit nonce eliminates collision risk, fast in WASM/ARM without AES-NI.
- **Single master_key** (no per-entry subkeys) — simpler, sufficient for family vault sizes.
- **imgsecret uses central-embed DCT** — embeds only in the middle 70% of the image (15% crumple zone for crop tolerance), with majority voting across 5-50 redundant copies.
- **QUANT_STEP = 50.0** — higher than typical (25) to survive JPEG recompression down to Q85.
- **Device ed25519 keys are separate from the KDF.** Revoking a device doesn't require rotating the passphrase or reference image.

## Crypto pipeline

```
passphrase (UTF-8 bytes) || image_secret (32 bytes from reference JPEG)
  → Argon2id(salt=vault_salt, m=64MiB, t=3, p=4)
  → master_key (32 bytes)
  → XChaCha20-Poly1305(nonce=random 24 bytes)
  → encrypted Item/Manifest/VaultSettings
```

## Conventions

- Tests use fast Argon2id params (m=256, t=1, p=1) so they don't take forever.
- Test JPEGs are generated synthetically via `make_test_jpeg()` — no binary test fixtures.
- Item IDs and Field IDs are random 16-char hex strings (64 bits of OsRng entropy). AttachmentIds are content-addressed: first 32 hex chars of SHA-256 over the plaintext (128 bits).
- Git history is preserved as an audit log — no squashing.
- The CLI shells out to `git` for sync — no libgit2/gitoxide dependency.

## Remote

Source code: `ssh://git@git.adlee.work:2222/alee/relicario.git`

## Planning & design specs

**Before starting any planning or implementation task**, search `docs/superpowers/specs/` for a spec covering the feature area, and `docs/superpowers/plans/` for any existing implementation plan. The specs are the authoritative design record; plans track per-milestone implementation details. Once a plan exists, execute it via the release workflow (see **Release lifecycle** below) — not directly via subagent-driven-development or executing-plans unless the workflow is unavailable.

Core references (read before touching crypto, data model, or architecture):
- `docs/superpowers/specs/2026-04-11-relicario-design.md` — threat model, entropy analysis, crypto pipeline, crate layout
- `docs/superpowers/specs/2026-04-18-relicario-typed-items-design.md` — typed-item data model and envelope
- `docs/superpowers/specs/2026-04-30-relicario-fullscreen-ux-redesign-design.md` — fullscreen UX phase plan

After completing any dev iteration, update `STATUS.md` to reflect what shipped and what's now in flight. Update the component doc for any area you changed (see table below).

## Release lifecycle

The `release` workflow (`.claude/workflows/release.js`) is the **default execution layer** for all dev work. Invoke it via the `Workflow` tool or the `/release` skill. Full reference: `docs/superpowers/RELEASE-WORKFLOW.md`.

### Standard actions

| Action | When | How |
|--------|------|-----|
| `develop` + `mode:"single"` | Implement a plan; phone/remote; fire-and-forget | `Workflow({name:"release", args:{action:"develop", mode:"single", release:"<label>"}})` |
| `develop` + `mode:"multi"` | Parallel streams; at PC; PM supervises devs | `Workflow({name:"release", args:{action:"develop", mode:"multi", release:"<label>"}})` |
| `debug` | Fix a failing test or broken feature after manual testing | `Workflow({name:"release", args:{action:"debug", context:"<paste failure>"}})` |
| `verify` | Confirm tests pass before releasing | `Workflow({name:"release", args:{action:"verify"}})` |
| `release` | Cut and tag a version | `Workflow({name:"release", args:{action:"release", release:"<label>"}})` |

### Execution defaults

- **Single-plan work** → `mode:"single"`. One agent works through tasks sequentially; updates `STATUS.md` automatically on completion.
- **Multi-plan or multi-phase work** → `mode:"multi"`. PM agent reads plans, assigns dev streams (up to 6), generates prompt files + a `<release>-launch.sh` in `docs/superpowers/coordination/`. Run the launch script — it starts the relay and opens a tmux session.
- **Debugging** → always `action:"debug"`. Never hand-fix without at least trying the debug loop first.
- **Releasing** → always `action:"release"`. It verifies first, writes CHANGELOG, tags, and stops before push.

### Multi-agent relay

The relay server (`tools/relay/`) supports roles `pm`, `dev-a` through `dev-f`. The launch script starts it automatically. If you need to start it manually: `cd tools/relay && ./start.sh`. Protocol reference: `docs/superpowers/coordination/RELAY.md`.

## Roadmap & status

Current in-flight work: `STATUS.md`. Full roadmap with release targets: `ROADMAP.md`. Wire format reference: `docs/FORMATS.md`.

## Living docs — update discipline

| File | What it documents | Update when... |
|---|---|---|
| `DESIGN.md` | Cross-codebase structure: four codebases, contracts, secrets map, build matrix, test strategy | Adding a codebase, changing inter-codebase contracts, new build targets |
| `docs/CRYPTO.md` | Crypto pipeline diagrams, vault creation/unlock flows, DCT embedding, encrypted file format | Changing crypto primitives, format version byte, or file format |
| `crates/relicario-core/ARCHITECTURE.md` | Module map, invariants, key flows, test architecture for `relicario-core` | Adding/changing modules, item types, or crypto invariants in core |
| `crates/relicario-cli/ARCHITECTURE.md` | Module map, invariants, key flows (init, unlock, all commands) for `relicario-cli` | Adding/changing CLI commands, helpers, or session behavior |
| `extension/ARCHITECTURE.md` | Bundle structure, SW↔popup contract, component architecture | Adding bundles, changing the SW message protocol, or major UI flows |
| `docs/SECURITY.md` | Threat model, device auth, env-var trust surface | Adding env vars, changing auth model, new security-relevant config |
| `docs/FORMATS.md` | Wire formats: `.enc` blobs, `params.json`, `devices.json`, manifest schema | Changing any serialized format, version number, or on-disk layout |
| `STATUS.md` | In-flight work, recent landings, what's next | End of every dev iteration |
| `ROADMAP.md` | Full roadmap with release targets | When milestones shift or new work is scoped |
| `CHANGELOG.md` | User-facing release history | When tagging a release |

### Discipline rules

Four rules to prevent the kind of drift the 2026-05-30 audits found:

1. **Scope-boundary check.** When editing a tour doc, verify the change fits the doc's scope header. If it doesn't, the change belongs in a different doc — move it instead of stretching the scope. Concretely: a sentence about crypto added to `DESIGN.md` belongs in `docs/CRYPTO.md`; a wire-format table added to `docs/CRYPTO.md` belongs in `docs/FORMATS.md`.

2. **Code-constant pinning.** When a tour doc cites a code constant (`VERSION_BYTE = 0x02`, `QUANT_STEP = 50.0`, `MIN_COPIES = 5`, `MANIFEST_SCHEMA_VERSION = 2`, etc.), the doc must cite the source file + line. When the underlying constant changes, grep for the citation pattern and update the docs together with the code change in the same commit. Most drift the audit found was code-constant drift — this rule attacks it at the source.

3. **New-doc rule.** When adding a tour doc, also update (a) `DESIGN.md`'s code-map, (b) the reading-order sequence (the "Next:" footer chain), and (c) the living-docs table above. A new doc that doesn't appear in all three is not done.

4. **Plan-state hygiene.** Plan checkboxes and `STATUS.md`/`ROADMAP.md` must reflect what's actually shipped. Two halves:
   - **Ship side:** when a commit lands work that maps to a plan task, tick that plan's checkboxes in the same commit (or the immediately-following docs commit). Same for `STATUS.md` — the "Up next" list does not get to lag the actual state of `main` by weeks.
   - **Execute side:** before starting execution of a plan whose checkboxes are all unchecked, spot-check git log (`git log --oneline --all --grep <distinctive-name>`) or grep for a distinctive symbol/file the plan would create. A plan whose work already merged is the worst kind of plan to re-execute. The 2026-05-30 status-audit found Phase 2B, v0.5.1 Streams A/B/C, and 1C-γ all stealth-shipped two-to-three weeks earlier because nobody ran this check.

5. **Pre-flight before develop.** Before running `action:"develop"` on any release, run `action:"preflight"` first. If preflight reports FAIL (baseline not green or version mismatch), fix the failure before proceeding. WARN results (orphaned worktrees, partially-done plan) require a judgement call — acknowledge them explicitly before proceeding.

6. **Cleanup after every lift.** Once all PRs for a release are merged into main, run `Workflow({name:"release", args:{action:"cleanup"}})` to remove the lift's worktrees and feature branches. Stale worktrees accumulate silently and create confusion for the next lift's branch-collision check.
