Files
relicario/CLAUDE.md
adlee-was-taken bae3f7c946 docs(CLAUDE.md): update living-docs table + add discipline rules
Table row labels now reference DESIGN.md / docs/CRYPTO.md /
docs/FORMATS.md. Adds three new discipline rules attacking the
structural causes of the 2026-05-30 drift audit findings:

  1. Scope-boundary check — content goes in the doc whose scope
     header claims it; if it doesn't fit, move it instead of
     stretching the header.
  2. Code-constant pinning — docs that cite code constants must
     cite source file + line; constant changes update doc and
     code in the same commit.
  3. New-doc rule — adding a tour doc also requires updating
     DESIGN's code-map, the Next: footer chain, and this table.

Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
2026-05-30 18:11:06 -04:00

9.5 KiB
Raw Blame History

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 12 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

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.

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).

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

Three rules to prevent the kind of drift the 2026-05-30 audit 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.