# Changelog

## v0.8.2 — 2026-06-25 — extension vault-creation fix (binary transport)

Fixes a bug that broke **vault creation and attach in the browser extension**:
`chrome.runtime.sendMessage` serializes messages with a JSON-like algorithm that
silently drops `ArrayBuffer` / `TypedArray` payloads — they arrive at the service
worker as empty objects, so the carrier JPEG reached the steganography embed as
**0 bytes** and failed with the opaque error *"no SOF marker found in JPEG."*
Extension-only release; the Rust core/CLI are unchanged from v0.8.1 (versions
bumped for tag consistency). `relicario-server` stays at `0.1.1`.

### Fixed
- **Binary-safe message transport** (`extension/src/shared/message-binary.ts`):
  `encodeBinary` / `decodeBinary` deep-walk every request/response and base64-
  envelope each binary buffer so it survives the channel (chunked base64 to avoid
  call-stack overflow on multi-MB attachments/backups); plain `number[]` arrays
  are left untouched. Applied at all four message boundaries — popup, service-
  worker `onMessage`, setup wizard, and the vault tab.
- **Actionable carrier-image errors**: `handleCreateVault` now magic-byte-checks
  the carrier and returns `carrier_image_empty` / `carrier_image_not_jpeg` (with
  user-facing copy) instead of the opaque WASM error when a non-JPEG or empty
  file is selected.
- **Setup-wizard message allowlist**: the service-worker router now permits
  `create_vault` / `attach_vault` / `generate_recovery_qr` from the setup page
  (the Phase-3 wizard sends these and they were being rejected as
  `unauthorized_sender`).
- **Vault-tab layout**: the closed detail drawer no longer reserves layout width
  (the list + empty state center correctly), and the locked vault tab grows to
  full width instead of pinning left.

## v0.8.1 — 2026-06-20 — org item-type parity + collection-scoped attachments

Brings `relicario org add` / `relicario org edit` to **full item-type parity** with the
personal vault: the org surface now supports **all 7 item types** (previously Login /
SecureNote / Identity only), adds collection-scoped attachment storage for Document
items, and grant-scopes attachment write paths in the pre-receive hook — closing a latent
authorization gap. Secrets are entered via interactive prompts by default, with `--*-stdin`
escape hatches for non-interactive scripting. Tracked under
`docs/superpowers/plans/2026-06-20-relicario-v0.8.1-parity.md`.

> **⚠️ Coordinated server redeploy required.** The `relicario-server` pre-receive hook
> (now `0.1.1`) must be rebuilt and redeployed for attachment writes to be grant-scoped in
> production. Until the updated hook is installed, `attachments/…` pushes remain
> `Unrestricted` (gated only by the per-commit member-signature check).

### Added
- **Shared `item_build` CLI module** (`crates/relicario-cli/src/commands/item_build.rs`):
  centralizes per-type secret resolution, item builders (`build_*`), and interactive edit
  helpers (`edit_*`) consumed by **both** the personal and org command surfaces, eliminating
  the prior personal↔org builder duplication.
- **Org `add` / `edit` parity for Card, Key, TOTP, and Document** — `relicario org add` now
  creates all 7 item types; `relicario org edit` is interactive per-type ("blank to keep",
  field-history capture) instead of flat flags.
- **`--*-stdin` secret flags** on personal and org `add` for non-interactive entry of
  passwords, card number/CVV/PIN, key material, TOTP secrets, and note bodies.
- **Collection-scoped org attachment storage** (`crates/relicario-cli/src/org_session.rs`):
  attachments stored at `attachments/<slug>/<item-id>/<att-id>.enc` with a default
  per-attachment cap (10 MiB, mirroring the personal default at
  `crates/relicario-core/src/settings.rs`). `org add document --file`, `org edit --file`
  (replace), and `org purge` (removes the item's attachment directory) round-trip with
  git-status-clean staging.

### Security
- **Grant-scoped attachment writes** (`relicario-server` `0.1.1`): `classify_path` now
  recognizes `attachments/<slug>/<item-id>/<att-id>.enc` (exactly 3 path segments, `.`-free
  slug guard) as `Item { collection }`, bringing attachment writes under the same grant +
  slug-existence check as `items/` blobs. Previously such paths fell through to
  `Unrestricted`. The Document source plaintext is read into a `Zeroizing` buffer and wiped
  after encryption. See `docs/SECURITY.md`.

### Changed
- Personal `add secure-note` `--body-prompt` flag renamed to `--body-stdin` (unified
  multiline-secret model).

### Docs
- Updated cli `ARCHITECTURE.md`, `docs/FORMATS.md` (org attachment layout + cap citation),
  `docs/SECURITY.md`, `STATUS.md`, and `ROADMAP.md`. New
  `docs/superpowers/specs/2026-06-20-extension-cli-parity-gap-analysis.md` is the forward
  plan for extension↔CLI parity (org read/write plus a cluster of personal-side extension
  gaps). End-user `user_docs/` guide lands as a fast-follow.

## v0.8.0 — 2026-06-20 — enterprise org vault

Git-native multi-user **org vaults**: a separate org git repository alongside each
member's personal vault, with a 256-bit org master key ECIES-wrapped per member to
their ed25519 device key, collection-scoped item storage, role-based access, and a
signature-verifying pre-receive hook that makes least-privilege enforcement
server-side. Tracked under `docs/superpowers/plans/2026-06-06-enterprise-org-vault.md`.

### Added
- **relicario-core `org` module** (`crates/relicario-core/src/org.rs`): org types
  (`OrgId`, `MemberId`, `OrgRole`, `OrgMember`/`OrgMembers`, `CollectionDef`/
  `OrgCollections`, `OrgMeta`, `OrgManifest`/`OrgManifestEntry`) and ECIES X25519
  key wrap/unwrap (`generate_org_key`, `wrap_org_key`, `unwrap_org_key`) — ed25519→
  X25519 via RFC 7748 clamp, domain-separated `SHA-256(dh || eph_pk || rcpt_pk)` KDF,
  XChaCha20-Poly1305 inner cipher, all key material in `Zeroizing`. Adds
  `encrypt_org_manifest` / `decrypt_org_manifest` vault wrappers. New dependencies:
  `x25519-dalek 2` (`static_secrets`) in core, `ssh-key 0.6` in core and CLI.
- **relicario-server org mode**: `verify-org-commit` (commit-signature verification
  against `members.json` ed25519 keys, path-scoped role/grant authorization,
  owner-only elevation judged on the signer's pre-commit role, schema-version
  monotonicity) and `generate-org-hook`; new `[lib]` target (`classify_path`,
  `extract_schema_version`). Audit trail on every push carries verified-signer
  attribution; commits whose signer cannot be matched are flagged `TAMPERED`.
- **relicario-cli org admin commands**: `org init`, `add-member` / `remove-member` /
  `set-role` (owner-only escalation guard), `create-collection` / `grant` / `revoke`,
  `rotate-key` (re-encrypts every item blob + manifest under a fresh org key),
  `transfer-ownership`, `delete-org` (local tombstone; hook blocks pushing a
  protected-file deletion), `status` / `audit`. Org commits are signed
  (`org_git_run` preserves signing).
- **relicario-cli org item CRUD**: `org add` (Login, SecureNote, Identity — each
  collection-scoped and grant-enforced), `org get <query> [--show]` (secrets masked
  by default; renders Login/SecureNote/Identity/Card/Document/Totp), `org list
  [--trashed]` (manifest filtered to your collection grants), `org edit <query>`
  (flag-driven field updates for login/note/identity fields), `org rm` / `org restore`
  / `org purge` (soft-delete lifecycle). Audit actions emitted: `item-create`,
  `item-update`, `item-delete`, `item-restore`, `item-purge`.

### Deferred
- `org add` / `org edit` parity for Card, SshKey, Document, and Totp item types
  (only Login, SecureNote, Identity supported today; `org get` and `org list` can
  display all types already present in the vault).
- Extension org switch + read-only browse parity (Dev-D follow-up).
- Extension org writes.
- Phase-2 features: SSO/LDAP provisioning, read audit trail, per-collection subkeys
  (the current shared org master key scopes *writes* via the hook and *read access*
  via manifest filtering, but does not cryptographically isolate collections from one
  another — a member who obtains the org key can decrypt any blob), HTTP management
  plane.

## v0.7.0 — 2026-06-01

Completes the extension restructure (Plan C) begun under v0.6.0. Phases
1/2/5 (StateHost typing, SW storage extract, the P2 cluster) shipped
2026-05-30; this tag adds the remaining three phases — executed as three
parallel worktree streams under PM coordination — which eliminate the
two steepest learning cliffs in the extension and close the last
`relicario status` CLI/extension parity gap. No crypto, wire-format, or
Rust-API changes; this is an internal-architecture + one-feature release.

### Added

- **`relicario status` parity in the extension.** New `get_vault_status`
  service-worker message returns a cached sync summary
  `{ ahead, behind, lastSyncAt, pendingItems }` with no network call —
  `ahead`/`behind`/`lastSyncAt` read straight off the cached git-host
  state (populated by the `sync` handler), `pendingItems` a live count of
  active (non-trashed) manifest entries. A sidebar-footer status indicator
  (`vault-status.ts` → `renderStatusIndicator`) renders `N pending` /
  `N ahead` / `N behind` / `in sync` plus a `last sync …` / `never synced`
  line, refreshed on mount and on a manual `↻` button — no timer polling,
  matching the no-network-without-user-intent discipline.

### Changed

- **Setup wizard crypto moved into the service worker.** The wizard no
  longer imports `relicario-wasm` or orchestrates the master key directly.
  New `create_vault` / `attach_vault` SW handlers own the full flow
  (image-secret embed/extract, unlock, manifest+settings encrypt + push,
  `register_device` + `addDevice`, persist config + reference image,
  `session.setCurrent`); on failure the SessionHandle is locked then freed,
  with ownership transferring only on success. `setup.ts` collapses from
  ~1230 LOC to a 58-LOC UI-only shell; the six render/attach step pairs
  become a `SetupStep` registry in the new `setup/setup-steps.ts`. Adds
  `clearWizardState` (bound to `beforeunload` and `goto('mode')`) to wipe
  sensitive Uint8Array fields when the wizard is abandoned. The
  non-extension copy-vault-config-JSON escape hatch is preserved.
- **`vault.ts` split from a 1037-LOC monolith to 194 LOC of routing +
  state.** Extracted into five focused modules — `vault-shell` (DOM
  scaffolding, color-scheme, onMessage wiring), `vault-sidebar` (category
  nav, 80ms debounced search, bottom nav, status-indicator footer),
  `vault-list` (list + row rendering), `vault-drawer` (open/close/render +
  `ensureDrawerClosedForRoute`), `vault-form-wrapper` (wrapped form + sticky
  bar) — plus two support modules for an acyclic split (`vault-context`,
  the VaultController contract; `vault-router`, hash routing + pane
  dispatch).
- **`vault_locked` RPC intercept unified.** Lifted out of `vault.ts` into
  the `sendMessage` wrapper in `shared/state.ts`, so both popup and
  vault-tab surfaces share one lock-redirect path.
- **`state.gitHost` now nulled on explicit lock**, symmetric with the
  session-timer expiry path, so the new status indicator can't surface a
  stale `lastSyncAt` after a lock → re-unlock within one service-worker
  lifetime.

### Internal

- Three-stream parallel execution (Dev-A Phase 3, Dev-B Phase 4, Dev-C
  Phase 6) coordinated via the relay message bus; merges sequenced
  Phase 3 → 4 → 6 with per-phase done-criteria verification.
- Final merged-tree validation: **423/423** vitest (62 files);
  `npm run build:all` clean for both Chrome and Firefox targets (only the
  pre-existing ~4 MB WASM asset-size warning). Task 7.1 done-criteria
  sweep all green. No change to `wasm.d.ts`.

## v0.6.0 — 2026-05-30

Rolls up four weeks of post-v0.5.0 work into one tag: the Phase 2B
polish foundation, the v0.5.1 train (Streams A/B/C — 3-column vault
layout, left-nav settings, Recovery QR), the 1C-γ slice (Document
type, attachments, device registration from popup, trash & history
UI), the Plan B multi-stream refactor (Cycles 1+2), the vault-tab
management surfaces revamp, and the doc-structure redesign. The
in-flight scope outgrew the original v0.5.1 plan, so this cuts as a
minor bump.

### Added

- **Recovery QR — 1-of-2 disaster-recovery path.** `image_secret` is
  encrypted under an Argon2id-derived key from the passphrase, packed
  into a 109-byte binary payload (magic `RREC` + version 0x01 + salt
  + nonce + AEAD ciphertext), and rendered as a QR code that is never
  written to disk. Surfaces:
  - Rust core: `relicario-core/src/recovery_qr.rs` — `generate_recovery_qr` /
    `unwrap_recovery_qr` / `recovery_qr_to_svg`. Production KDF
    params (`m=64MiB, t=3, p=4`) live behind a private-fields type so
    they cannot drift.
  - WASM: `generate_recovery_qr` / `unwrap_recovery_qr` exported; the
    session now stashes `image_secret` so the QR can be regenerated
    without re-running steganography extraction.
  - CLI: `relicario recovery-qr generate` (TTY render) and
    `relicario recovery-qr unwrap` subcommands.
  - Extension: three-state Security settings card (no QR → amber
    warning; QR exists → green status + show/regenerate; explicit
    view → modal with print).
  - Setup wizard: skippable "generate before you go" banner on the
    final step.
- **Document item type.** New typed item for storing a signed document
  with a primary attachment. Form takes signature + signed-on date;
  detail view renders a signature-block layout. Wired into the popup
  add/view/edit dispatchers. Refuses to drop its primary attachment
  (use `purge` instead).
- **Attachments end-to-end.** Service worker uploads attachments via
  the GitHost putBlob path (GitHub + Gitea Git Data API with fallback);
  popup attachments-disclosure component handles add/remove/download
  inside all six item-type forms; `📎` indicator shows on item-list
  rows that have attachments. Per-vault attachment bytes cap is
  enforced both at attach-time and during backup restore.
- **Device registration from the popup.** "Register this device"
  triggers an inline name input + WASM keypair generation + persisted
  device entry — no setup-wizard detour.
- **Trash + field-history UI.** Trash view shows per-item purge
  countdown with restore / per-item purge / empty-all actions.
  Field-history view groups changes per field with reveal/copy
  glyph buttons. New top-level item-history-index pane lists every
  item that has captured history. `#history/<id>` route normalizes
  the legacy `#field-history/<id>` URL form.
- **3-column fullscreen vault tab.** Sidebar (200px, type-category
  nav) + list (flex) + detail drawer (440px, slides in on row click).
  Below 720px the drawer pushes the list full-pane. Bottom sheet for
  "new item" type picker uses a pane-only scrim so the sidebar stays
  interactive.
- **Left-nav settings page.** Replaces the flat settings dump.
  Sections grouped Device (Autofill, Display — password coloring)
  vs Vault (Security — Recovery QR + trusted devices, Generator,
  Retention, Backup, Import). The standalone Devices sidebar entry
  is subsumed into Security.
- **Two-column login form in fullscreen.** Identity (title / URL /
  group) and Credentials (username / password / TOTP) render as
  side-by-side glass cards above 720px viewport; single-column at
  narrow widths. Notes / custom sections / attachments stay full-width
  below the grid. Sticky save bar at the bottom of the form pane;
  header shows title + dirty subtitle ("unsaved · esc to cancel" or
  "no changes") + platform-aware save hint (⌘+S / Ctrl+S).
- **Polish vocabulary.** Patina gold palette tokens
  (`--gold-base` `#a88a4a` replacing the brighter `#d2ab43`),
  `.surface-backdrop` (subtle radial top-glow + 18px grid texture)
  applied to popup body / setup body / vault body, `.glass` card
  class with `backdrop-filter: blur(8px)`, `.btn-primary` /
  `.btn-secondary` button hierarchy, and `GLYPH_NEXT = '▸'` replacing
  ASCII `→` in next/continue buttons.
- **Vault lock-screen logo.** `<img class="brand-logo">` added to the
  lock-screen render for parity with the popup unlock view and the
  setup wizard.
- **Setup wizard Style C.** Centered hero card + colored progress
  track + glyph mode icons, replacing the prior vertical glass-card
  wizard.
- **Toast notification system.** Shared `showToast(message, type,
  durationMs)` at `extension/src/shared/toast.ts`. Used for sync
  success/failure, copy confirmation, device registration result.
  Replaces the ad-hoc `sync-status` div.
- **Empty-state treatments.** Popup item list (vault empty / search
  returns nothing), vault list (section empty) — each gets a centered
  glyph + headline + hint.
- **Per-type glyph icons in popup item rows.** `◉ login`, `◫
  secure_note`, `⊡ totp`, `▭ card`, `⌬ identity`, `⊹ key`,
  `≡ document`.

### Changed

- **Vault-tab management surfaces revamp (2026-05-24..05-30).**
  Settings pane splits synced (cross-device via Chrome storage) from
  local (per-browser) controls and gains a session-timeout UI.
  Devices pane shows SHA-256 fingerprint + added-by display + inline
  two-step revoke confirm via glyph button. Trash pane shows per-item
  purge countdown via `daysUntilPurge`. Field-history pane gets
  section headers and reveal/copy glyph buttons. New shared
  utilities: `relative-time.ts` (consolidating five duplicate inline
  copies), webcrypto `ssh-fingerprint.ts`, shared
  section-header / glyph-btn / kv-row / fingerprint CSS.
- **Emoji sweep.** Every remaining UI emoji replaced with a
  monochrome glyph constant from `shared/glyphs.ts`. The pop-out
  button is now `⧉` (U+29C9, `GLYPH_VAULT_TAB`) instead of `&#x2934;`.
- **License switched to GPL-3.0-or-later.** Was MIT for the early
  prototype phase. License headers + `AUTHORS` + crate `Cargo.toml`
  authors updated.
- **AttachmentId expanded to 128 bits with `is_valid` check.**
  Backup restore now validates IDs (audit I2 / B4).
- **Per-vault attachment bytes cap enforced.** Both CLI attach and
  backup restore (audit I3).

### Internal

- **Plan B multi-stream refactor (Cycles 1+2).** CLI `main.rs` split
  into per-command modules under `crates/relicario-cli/src/commands/`
  with a shared `git_run` helper. New `prompt_or_flag<T>` and
  `prompt_or_flag_optional<T>` helpers compress all the `build_*_item`
  helpers. `Vault::after_manifest_change` wrapper plus a single
  canonical `ParamsFile` in the session avoid duplicated file-system
  rebuilds. Core/WASM seam: `base32_decode_lenient`,
  `parse_month_year`, `guess_mime` exported from WASM; CLI parsers
  migrated to `relicario-core::parse`. Extracted `base32` module
  from core, deduplicated two RFC-4648 implementations.
- **Doc-structure redesign (2026-05-30).** Renamed `ARCHITECTURE.md`
  → `DESIGN.md`, `docs/ARCHITECTURE.md` → `docs/CRYPTO.md`,
  `FORMATS.md` → `docs/FORMATS.md`. Added scope headers and
  "Next:" footers to all tour docs so the reading order is canonical.
  `CLAUDE.md` gains a living-docs table and four discipline rules
  (scope-boundary check, code-constant pinning, new-doc rule,
  plan-state hygiene).
- **CLI quality-of-life.** `gen` alias for `generate`, `-l`/`-w`
  short flags, batched purge in `cmd_purge` and `cmd_trash_empty`.
- **Workspace audit cycle.** Stale local branches and worktrees
  pruned. Several plan files moved into `docs/superpowers/audits/`
  for the record.

## v0.5.0 — 2026-05-02

Three release trains roll into one tag — backup/restore + LastPass
import (originally v0.3.0), device authentication (originally v0.4.0),
and the v0.5.0 polish + harden bundle (security fixes + UX fixes +
two confirmed bugs).

### Security

- **Pre-receive hook now actually verifies signatures (audit S1, HIGH).**
  Earlier `relicario-server` builds accepted any commit with a
  `Good signature` line on stderr regardless of which key signed it —
  device-auth was a no-op. The hook now builds an `allowed_signers`
  file from `devices.json` at the commit (via `GIT_CONFIG_*` env, no
  global git-config mutation), parses the SSH SHA-256 fingerprint out
  of `git verify-commit --raw` stderr, and rejects unregistered keys or
  revoked keys whose committer-date is at or after the revocation
  timestamp. Bootstrap mode is preserved only when **both**
  `devices.json` AND `revoked.json` are empty (closes an
  empty-devices.json privilege-escalation route).
- **Backup-restore tar unpacking hardened (audit S2).** `relicario
  backup restore` no longer trusts `tar::Archive::unpack`'s defaults.
  A new `relicario_core::safe_unpack_git_archive` validates each
  entry's path components (rejects `..`, absolute paths, Windows
  drive prefixes), rejects symlinks/hardlinks, and caps total
  uncompressed size at the lower of 100×compressed-bytes or 1 GiB.
  The CLI restore path adds a paranoid `dest.starts_with(.git/)`
  check after path-joining as defense-in-depth.
- **`RELICARIO_*` env-var surface audited (audit S3).** `docs/SECURITY.md`
  gains a per-variable trust table. `RELICARIO_NO_GROUPS_CACHE` (a
  developer escape hatch, not a user knob) is now
  `cfg(debug_assertions)`-gated and is a no-op in `--release` builds;
  the env-var lookup is removed from the binary by the optimiser.

### Fixed

- **Strength meter no longer goes stale after the regenerate button (B1).**
  Programmatic `input.value = newPassword` doesn't fire `input`
  events; the regenerate handler now dispatches a synthetic
  `InputEvent('input', { bubbles: true })` so the meter listener
  re-rates the new value.
- **Snake_case error codes no longer leak into the UI (B2 / P4).**
  Errors like `vault_locked`, `origin_mismatch`, `unauthorized_sender`
  used to render verbatim in the fullscreen vault tab and (in some
  cases) the popup. New `extension/src/shared/error-copy.ts` central
  registry maps every service-worker error code to friendly
  title/body/CTA copy; the popup and fullscreen tab consume the
  same map. The fullscreen lock screen's `vault_locked` block now
  reads `Vault locked / Unlock your vault to continue. / [Unlock
  vault]`. A generated test enumerates the live error codes via
  grep so the registry can't drift.

### Added

- **Sidebar logo in the fullscreen vault tab.** The
  `vault-sidebar__header` now renders the 16-optimized SVG logo
  inline before the "Relicario" wordmark (20×20 px, `flex-shrink: 0`
  so it survives narrow-pane wraps). Popup unaffected.
- **Password coloring (P1).** Revealed passwords in the popup
  item-detail, fullscreen item view, field-history viewer, and
  generator preview render digits and symbols in distinct colors.
  Defaults: blue digits, red symbols. Users can override via the
  new Display section in settings (color pickers + live preview
  swatch + reset). Defaults round-trip via
  `chrome.storage.sync.password_display_scheme`; cross-device when
  Chrome sync is enabled.
- **Setup wizard hands off to the fullscreen vault tab on completion
  (P2).** Both create-new and attach-existing flows now open
  `vault.html` in a new tab and best-effort close the setup tab
  after device registration succeeds — replaces the prior
  setup-tab-stays-open terminal screen.
- **Sync now button** in the extension settings view — surfaces the
  previously hidden `{ type: 'sync' }` SW message to users with success /
  error feedback.
- **Device registration from the popup.** The "Register this device"
  button on the devices view now opens an inline name input and (on
  confirm) generates a keypair via WASM, persists the private key + name
  locally, and writes the device to the remote — no setup-wizard detour.
  Backed by a new `register_this_device` SW message.
- **`relicario settings generator-defaults`** — view-and-edit access to the
  generator defaults stored in `VaultSettings`. Flags: `--random` /
  `--bip39` to switch mode, `--length`, `--words`, `--symbols`,
  `--separator` to update fields of the active mode.
- **`relicario edit` now supports TOTP items.** Issuer, label, and secret
  rotation work; rotated secrets are pushed to `field_history` (key:
  `core:totp_secret`).
- **`relicario history <query>`** — view captured field history. Values
  are masked by default; `--show` reveals them; `--field <name>` filters
  to one synthetic key (e.g. `login_password`, `totp_secret`).
- **`relicario detach <query> <aid>`** — remove an individual attachment
  from an item. Refuses to drop a Document item's primary attachment
  (use `purge` instead).
- **`relicario status`** — vault summary: root path, item count
  (active / trashed), attachment count + total bytes, registered device
  count, last commit (`%h %s`).
- **Backup & restore.** New `relicario backup export <out.relbak>` and
  `relicario backup restore <in.relbak> [<dir>]` commands. The `.relbak`
  format is a single encrypted file: Argon2id-derived key from a
  user-chosen backup passphrase (independent of the vault factor),
  XChaCha20-Poly1305 ciphertext, zstd-compressed JSON envelope.
  Reference image and `.git/` history are opt-in inclusions
  (`--include-image`, `--no-history`).
- **Vault-tab Backup & Restore panel.** Export downloads the
  `.relbak` via `chrome.downloads`. Restore takes a file + backup
  passphrase + new-remote config and writes the vault into a fresh
  empty repo (refuses to clobber existing). Git history is never
  bundled from the extension — CLI is the source of full backups.
- **LastPass CSV import.** New `relicario import lastpass <csv>`
  command + vault-tab Import panel (`vault.html#import`).
  Logins map to `Login` items; rows with `url == "http://sn"`
  map to `SecureNote` (extra column → body verbatim, structured
  data preserved as-is for manual re-categorization). TOTP
  secrets in the `totp` column are base32-decoded into
  `LoginCore.totp`; bad base32 surfaces a warning and the login
  is imported without TOTP. Failed rows (missing `name`, missing
  password on a login) are skipped with a per-row warning.
  Each row gets a freshly-minted ID — re-running the import
  creates duplicates rather than corrupting state.
- **Popup deep link to the Import panel.** `settings-vault`
  gains an "import" section with a `LastPass CSV →` button
  next to the existing `Backup & restore →` button.
- **`relicario status` shows last export age.** New `Last export:
  <human-readable>` line reading `.relicario/last_backup` (a marker
  file `cmd_backup_export` writes on success). Reads "never" for
  fresh vaults, "4 days ago" otherwise.

### Changed

- **Form layout in the fullscreen vault tab is now visually consistent
  (P3).** Notes, custom-fields disclosure, attachments disclosure, and
  form-actions in fullscreen logins now sit inside a `.form-lower`
  wrapper with the same `max-width: 960px; margin: 0 auto` envelope as
  the `.form-grid` cards above. Removes the visual rhythm break at the
  2-col → full-width transition. The popup surface is unchanged.
- **Documentation refreshed for v0.5.0 (doc audit, 14 findings).**
  `DESIGN.md` now describes four codebases (the
  `relicario-server` pre-receive hook crate is no longer invisible);
  `CLAUDE.md` project tree and roadmap reflect current state;
  `docs/SECURITY.md` names the server crate and its `verify-commit` /
  `generate-hook` subcommands and notes the without-the-hook-it's-
  advisory caveat; `docs/CRYPTO.md` shows `settings.enc` as a
  parallel artifact in the vault-creation flow; the foundational
  design spec gains a "historical" status banner pointing readers at
  the current docs.
- `relicario generate` now consults `VaultSettings.generator_defaults` when
  invoked inside an initialized vault. Explicit flags (`--length`,
  `--bip39`, `--words`, `--symbols`, `--separator`) override the vault
  default. Outside a vault, behavior is unchanged (length 20, safe symbol
  set, 5 BIP39 words, space separator).

### Known limitations

- **Mid-restore failure leaves the target remote in a half-written
  state.** `cmd_backup_restore` and the vault-tab Restore panel both
  write artifacts sequentially via `writeFileCreateOnly`. If the
  process is interrupted partway, a retry against the same remote
  refuses to clobber. Workaround: delete the partial repo and retry.
- **Cross-tool backup compatibility.** CLI-exported backups stored
  attachments at `<item_id>/<aid>.enc`; extension stores at flat
  `<aid>.bin`. The `.relbak` envelope canonicalizes to `<item_id>/<aid>`
  keys and each tool translates at the boundary. Round-trip works in
  both directions.

### Internal

- 5 stale local feature branches and 3 worktrees pruned (audit C1).
- Pre-existing clippy warnings cleaned up across `relicario-{core,cli}`
  (deref operators, `Option::is_none_or` over `map_or(true, ...)`,
  `iter_mut().enumerate()` patterns, `div_ceil()`) so the workspace
  builds clean under `-D warnings`.
- `Cargo.lock` regenerated and committed; was stale since the
  `--totp-qr` commit.
- Refactored `cmd_add` and `cmd_edit` in the CLI: each `ItemCore` variant
  now has its own `build_*_item` / `edit_*` helper. Pure mechanical
  extraction; behavior unchanged. The dispatcher matches and delegates.
- Extracted pure helpers (`escapeHtml`, `ratePassphrase`, `scheduleRate`,
  `entropyText`, `STRENGTH_LABELS`) from `extension/src/setup/setup.ts`
  into `setup-helpers.ts`. State-coupled `updateStrengthUi` stays in
  `setup.ts` since it walks live wizard state. Setup.ts went from
  1205 → 1137 lines.

## v0.2.0 — 2026-04-27

### Fixed

- **Setup wizard could silently overwrite an existing vault.** Pointing the
  wizard at a remote that already contained a Relicario vault would clobber
  `manifest.enc`, `.relicario/salt`, and friends with no warning. The wizard
  now probes the remote after the connection test and refuses to create a
  new vault on top of an existing one. Affected users whose vault was wiped
  by this bug should restore from the git history of the affected repo
  (`git log` + `git checkout <pre-init-sha> -- .`).
- **New devices registered during initial setup were silently dropped.** The
  wizard's Step 5 fired `add_device` over a service-worker channel that
  required an unlocked vault, which is unavailable mid-wizard. Device pubkeys
  now write directly to `.relicario/devices.json` from the wizard.
- **Wizard-created vaults were missing `settings.enc`.** The CLI's `init`
  writes a default-`VaultSettings` `settings.enc` alongside `manifest.enc`,
  but the wizard skipped it, causing every `get_vault_settings` SW call to
  404. The wizard now encrypts and writes `settings.enc` using a new
  `default_vault_settings_json` WASM helper that keeps defaults in sync
  with Rust core.

### Added

- **Attach this device to an existing vault — purely from the GUI.** New
  Step 0 mode picker splits the wizard into "create new vault" and "attach
  this device." The attach path takes a passphrase + reference image, fetches
  the existing manifest, verifies the credentials by decrypting it, and only
  then registers a new device key. No CLI required for multi-device setup.
- `GitHost.lastCommit(path)` and `GitHost.writeFileCreateOnly(path, ...)`.
- `default_vault_settings_json()` WASM export.

## v0.1.0 — 2026-04-22

Initial release.
