Files
relicario/CLAUDE.md
adlee-was-taken a00a710e3b feat(workflow): add preflight, cleanup, artifact-scan, version/tag checks
Adds six sanity-check layers to the release workflow:
- preflight: orphaned worktrees, baseline green, plan-state grep, branch collision
- cleanup: removes merged worktrees + branches (git branch -d, never -D)
- debug artifact scan: dbg!/ console.log / TODO / unwrap() in diff (advisory)
- checkbox hygiene: unticked plan tasks before verify (advisory)
- pre-release version consistency across Cargo.toml workspace
- pre-release tag collision check

CLAUDE.md: discipline rules 5 (preflight before develop) and 6 (cleanup after lift).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 23:52:19 -04:00

13 KiB
Raw Permalink 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. 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 workmode:"single". One agent works through tasks sequentially; updates STATUS.md automatically on completion.
  • Multi-plan or multi-phase workmode:"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.