# Dev E — RESUME Prompt (v0.9.0 Plan 5, keyfile extension + positioning) Paste everything below the `---` into a **fresh** Claude Code terminal. --- You are **RESUMING** Plan 5 (keyfile extension + positioning pivot) for v0.9.0. The lift paused ~21h ago; you are a fresh session with no relay history. Your worktree, branch, and commits **already exist** — do NOT recreate the worktree and do NOT restart from Task 1. **You are UNBLOCKED:** Dev-D (keyfile core/cli/wasm) is MERGED to main — the real WASM bindings are available now. ## Resume setup (replaces the original Setup block) ```bash cd /home/alee/Sources/relicario.v0.9.0-dev-e pwd # must print /home/alee/Sources/relicario.v0.9.0-dev-e git status git log --oneline -6 # confirm Task 1 (wizard) + Task 6 (docs) + scaffold are committed (down to c79ff1c) git fetch origin git merge origin/main # PULLS IN Dev-D's keyfile WASM bindings (keyfile_encode/decode, unlock_with_secret) # + the SecondFactor params hint. Resolve any trivial wasm.d.ts conflicts (keep both). ``` ALL work stays in `/home/alee/Sources/relicario.v0.9.0-dev-e`. Every subagent prompt MUST start with `cd /home/alee/Sources/relicario.v0.9.0-dev-e`. ## Read for full context - `docs/superpowers/coordination/v0.9.0-dev-e-prompt.md` — your ORIGINAL prompt: ROLE, RELAY protocol + shim, STATUS/QUESTION formats, polling cadence, specs/plan paths. **IGNORE its Setup block and "begin Task 1."** - `docs/superpowers/plans/2026-06-20-v0.9.0-keyfile-ext-positioning.md` — your plan. - `CLAUDE.md`. Relay up on `localhost:7331` (shim: `cd /home/alee/Sources/relicario/tools/relay && python3 call.py read_messages '{"for":"dev-e"}'`). PM is live — poll before/after every subagent + at task boundaries. ## WHERE YOU ARE — already done, do NOT redo (commits, local-only) - **Task 1** wizard second-factor choice (Reference Image | Key File) — DONE. - **Task 6** positioning docs (README re-lead on the two-factor-KDF thesis; stego framed as one option) — DONE (1591fc7..9e19949). **Will need reconciliation with the FORMATS/SECURITY deltas below.** - Scaffold types committed (`create_vault` `secondFactor` request + `relkeyBytes` response) — c79ff1c. ## KEY FACTS from Dev-D (now on main — authoritative) - WASM: `keyfile_encode(Uint8Array)->Uint8Array`, `keyfile_decode(Uint8Array)->Uint8Array` (throws on bad armor/length), `unlock_with_secret(passphrase:string, secret:Uint8Array[32], salt:Uint8Array[32], params_json:string)->SessionHandle`. - **Pass the SAME `params_json` you already give `unlock()` — `second_factor` does NOT affect the KDF** (that is the equivalence guarantee; D's test proves byte-identical master keys). - `params.json` is a nested **ParamsFile** wrapper; `second_factor` is a **TOP-LEVEL** field on it (`image|keyfile`, absent ⇒ image). Read it pre-unlock to pick the image-picker vs key-file-picker. - Armor: `relicario-keyfile-v1\n` + base64(32 bytes) + `\n`; ext `.relkey`; the secret is IN THE CLEAR. ## YOUR REMAINING WORK (you merge after D — which is done — so you can REVIEW-READY as soon as you're complete) - **Task 2** SW `create_vault` key-file branch: generate the 32-byte secret (`crypto.getRandomValues`), `unlock_with_secret`, write `params.json` `second_factor: "keyfile"`, store `keyfileBase64` in `chrome.storage.local` (exactly like `imageBase64`), return `{ relkeyBytes }` (base64-enveloped via `shared/message-binary.ts`). - **Task 3** wizard key-file download: trigger a `vault.relkey` download from the `create_vault` response + "save this key file" copy. - **Task 4** SW `unlock` branches on the params hint: if `keyfile`, load `keyfileBase64` → `keyfile_decode` → `unlock_with_secret`; else the image path. Malformed → `invalid_key_file`. - **Task 5** attach-mode key-file picker: detect `second_factor` in the probe; render a `.relkey` input when `keyfile`; store `keyfileBase64`; verify via `unlock_with_secret`. - **Doc deltas to LAND (Dev-D deliberately left these to you — reconcile with your Task 6):** `FORMATS.md` (.relkey armor `relicario-keyfile-v1` + base64(32) + the params top-level `second_factor`), `SECURITY.md` (.relkey / `keyfileBase64` is the second factor IN THE CLEAR, gitignored + never pushed on CLI, local-only in `chrome.storage` on the extension — server only ever sees opaque ciphertext; same posture as the reference JPEG, NOT encrypted), `docs/CRYPTO.md` (pluggable-transport framing), `docs/user_docs/` if any extension-facing keyfile usage. - **Verify** the extension recovery-QR works for a key-file vault — it should already work because `unlock_with_secret` stores the secret in the WASM session and `generate_recovery_qr` reads from the session (NOT re-resolved from `imageBase64`); confirm it does not assume an image. If it re-resolves from the image, fix it. - **MANDATORY** `/security-review` on the key-file path before REVIEW-READY (equivalence-to-stego, armor parsing, in-the-clear-storage honesty, no oracle difference). Binary crosses `chrome.runtime.sendMessage` base64-enveloped only. - Then full validation (`cd extension && npx vitest run && npm run build:all`), simplify pass, **push** `feature/v0.9.0-dev-e-keyfile-ext`, post `Status: REVIEW-READY`. ## First action `cd` into the worktree, `git log --oneline -6`, `read_messages(for="dev-e")` for my resume directive, post a `## STATUS UPDATE` (`Status: IN-PROGRESS`, `Task: 2 create_vault keyfile`) confirming RESUMED + main merged + D bindings present, then continue via `superpowers:subagent-driven-development`.