Generated by /multi-agent-kickoff for the three architecture-review followup plans. PM coordinates; Dev-A owns Plan A (security & docs polish, S, ships first); Dev-B owns Plan B (CLI restructure, M-L); Dev-C owns Plan C (extension restructure, L). Each dev prompt forces cd into its worktree (per project memory rule), includes the relay tool calls + Python shim fallback, scopes hard-rules to the planning subagents' flagged judgment calls, and ships an opinionated PR title + body template that mirrors the plan's Done criteria. PM prompt enforces the cross-plan boundaries: A is independent; B Phase 8 WASM exports are a seam C does not consume in this train; A owns the .free() swallow removal and Drop impl; if both B and C touch wasm.d.ts, B sequences first. Launcher discovers these via `ls -t coordination/*-<role>-prompt.md | head -1` so they take precedence over previous kickoff sets. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
18 KiB
Dev C Kickoff Prompt — arch-followup Plan C
Paste everything below the --- line into a fresh Claude Code terminal as the first user message.
You are a senior developer owning Plan C for the arch-followup "architecture-review followups" release train.
Plan C is the extension restructure — the largest of the three (multi-day to multi-week). It eliminates the two steepest learning cliffs in the extension. After this plan ships, setup.ts no longer imports relicario-wasm directly (it isn't the pattern; it was the exception); vault.ts shrinks from 1027 LOC to ~200 of routing + state; shared/state.ts becomes type-checked end-to-end; the duplicated SW router helpers consolidate into one home each; and the extension closes its last CLI-parity gap (relicario status → vault-sidebar status indicator). Six phases.
A PM in another terminal coordinates you with Dev-A (security & docs polish) and Dev-B (CLI restructure). With the relay server running, you communicate via post_message / read_messages directly — no user copy-paste needed. If the relay MCP tools are not registered in your session, use the Python shim fallback (see Relay server section below).
Setup (do this first)
cd /home/alee/Sources/relicario
git fetch
git checkout main
git pull
git worktree add ../relicario-plan-c -b feature/2026-05-04-c-extension-restructure
cd ../relicario-plan-c
pwd # should print /home/alee/Sources/relicario-plan-c (or similar absolute path)
ALL subsequent work happens in /home/alee/Sources/relicario-plan-c. Force-cd subagents into this directory — the project's CLAUDE.md memory rule explicitly requires that subagent prompts MUST start with cd /home/alee/Sources/relicario-plan-c so subagents don't accidentally commit to main. This is non-negotiable.
Today: 2026-05-04. Project rules in CLAUDE.md apply.
Relay server
A message-bus MCP server is running on localhost:7331. You have three native tools:
post_message(from, to, kind, body)— push a message; yourfromis always"dev-c"read_messages(for)— drain your inbox; call withfor="dev-c"before each tasklist_pending(for)— check inbox count without consuming
Recipients: pm, dev-a, dev-b, dev-c. Use these instead of asking the user to copy-paste. Before starting each task: read_messages(for="dev-c"). After emitting any status/question block: post_message(from="dev-c", to="pm", kind="status"|"question", body="...").
Fallback: If the relay MCP tools are not registered in your session, use the Python shim:
cd /home/alee/Sources/relicario/tools/relay
python3 call.py post_message '{"from":"dev-c","to":"pm","kind":"status","body":"..."}'
python3 call.py read_messages '{"for":"dev-c"}'
Required reading (in order)
CLAUDE.md— project rules (Spanish flourish in chat replies only, capitalization, autonomy defaults, CLI/extension parity philosophy, security defense-in-depth)docs/superpowers/reviews/2026-05-04-architecture-review.md— synthesis (your scope is P1.4, P1.5, P1.6, P1.9 + the in-scope extension P2s + therelicario statusparity gap only)docs/superpowers/specs/2026-05-04-extension-restructure-design.md— your plan, execute phase by phasedocs/superpowers/reviews/2026-05-04-dev-c-notes.md— DEV-C's full notes (your primary source — the synthesis abbreviates)docs/superpowers/reviews/2026-05-04-dev-b-notes.md— read only the "Boundary notes for DEV-C" section near the end (14 numbered contracts the JS side must respect when interacting with WASM; several inform your scope)
You do NOT need to read Plan A or Plan B in detail. Skim Plan A's Phase 2 (the service-worker/session.ts:26 swallow removal) and Plan B's Phase 8 (WASM parser exports) only if a coordination question arises.
Execution mode
Use subagent-driven-development (per project memory's default for any multi-task plan). Invoke superpowers:subagent-driven-development and follow it: fresh subagent per phase, two-stage review between phases.
Every subagent prompt MUST start with:
cd /home/alee/Sources/relicario-plan-c
…before any other instruction. This is non-negotiable per project memory.
Sequencing matters. Phase 1 (typed StateHost) is the precondition for phases 3 and 4. Phase 2 (SW storage extraction) is independent and can ship in parallel. Phases 3 and 4 both depend on phase 1. Phase 5 (P2 cluster) and phase 6 (get_vault_status) are independent of 3 and 4 — they can run in parallel.
Your scope and boundaries
In scope:
- Phase 1 — Typed
StateHostinterface inextension/src/shared/state.ts(noanyin public surface) + genericgetState/setStateoverkeyof PopupState+ double-registration guard +__resetHostForTestshelper. Includes migration ofViewandPopupStatefromextension/src/popup/popup.tstoextension/src/shared/types.ts(or a newshared/popup-state.ts) to avoid apopup → shared → popupcircular import. - Phase 2 — Extract
extension/src/service-worker/storage.ts(loadDeviceSettings,loadBlacklist,saveBlacklistfrom both router files) + moveitemToManifestEntrytoextension/src/service-worker/vault.ts. - Phase 3 — Setup wizard SW migration: add
create_vaultandattach_vaultSW messages; rewritesetup.tsas UI-only that posts those messages; convert the 6-step procedural wizard to a step-registry pattern; addclearWizardState()onbeforeunload+ step-0 reset. - Phase 4 — Split
vault.tsintovault-shell.ts/vault-sidebar.ts/vault-list.ts/vault-drawer.ts/vault-form-wrapper.ts. Liftvault_lockedRPC intercept intoshared/state.ts. Resetstate.drawerOpenon non-listrenderPane. Debounce sidebar search (50-100ms). - Phase 5 — P2 cluster: inactivity-timer reset on content-callable messages (with documented exclusion set);
state.gitHostclear on session expiry; teardown helper extraction (teardownSettingsCommon);Promise.allSettledin devices/trash; MutationObserver debounce incontent/detector.ts. - Phase 6 —
get_vault_statusSW message + vault-sidebar status indicator (closes therelicario statusparity gap).
Out of scope: anything in Plan A (security/docs polish — impl Drop, service-worker/session.ts:26 swallow removal, .free() audit, recovery_qr.rs docs, server hardening, env-var audit) or Plan B (CLI restructure — cli/main.rs split, git_run, parser migration to core; you only consume the WASM exports as a deferred follow-up). Extension P3s (form-header isInTab() redundancy, popup.ts isInTab() heuristic, item-form.ts renderComingSoon dead code, types/login.ts size, vault.ts:18-26 backup-panel comment, capture/detector/fill username-finder dedup, capture submit-button hook scope, setup.ts passphrase-score -1 sentinel, setup.ts:1056-1062 chrome.storage bypass, setup.ts:1-7 "5-step" header, glyphs.ts partial adoption, types.ts TotpKind flat-union, totp-tools.ts:39-46 swallowed rejections, generator-panel cleanup guard, item-list.ts popover listeners, popup popup.ts:178-181 unconditional teardowns). Other parity items (per-attachment delete_attachment SW message, list --tag filter doc note). Cross-cutting items not explicitly listed (chrome.storage.local direct reads outside the setup migration, bun test runner doc note, manifest version sync). The 8 "Open architectural decisions". WASM JS-naming snake_case → camelCase (deferred to a separate plan). Anything touching the in-flight uncommitted v0.5.x work. If you trip over an out-of-scope issue or a new bug, file it via a ## QUESTION TO PM block and keep moving.
Hard rules:
- Phase 1 first. Do NOT start phases 3 or 4 until phase 1 is green and committed. The typed
StateHostis the contract phases 3 and 4 build against. View/PopupStatemigration is part of phase 1, not phase 4. Doing it later creates circular imports that surface mid-refactor and waste a day.- Do NOT redo Plan A's
.free()swallow removal atextension/src/service-worker/session.ts:26. That's Dev-A's. But wherever your refactor moves a.free()callsite — most notably during phase 3 whensetup.ts'sverifiedHandleretires and the newcreate_vault/attach_vaultSW handlers acquire their own handles — the new location MUST callwasm.lock(handle)first regardless of whether Plan A's Rust-sideimpl Drophas landed yet. Cite Plan A as the source of the policy in your phase 3 commit message. extension/src/wasm.d.tscoordination with Plan B. Plan B Phase 8 will touch this file for new parser exports. Verify by readingextension/src/service-worker/vault.tswhether yourcreate_vault/attach_vaultSW handlers need new WASM entry points — they likely don't (the SW already orchestratesunlock/embed_image_secret/register_device/manifest_encrypt). If you DO need new entries, escalate via## QUESTION TO PMso the touch order with Plan B can be sequenced.create_vaultandattach_vaultSW handlers must be transactional — they hold their own internal session reference for the duration of the operation and do NOT consult or reset the user-facing inactivity timer until they return successfully. Document this contract in the handler header comments.- Phase 4
vault_lockedchannel unification keeps both signals (the SW'ssession_expiredevent AND the newshared/state.tswrapper's intercept) firing during the migration window. Collapse only after both surfaces are verified consuming fromshared/state.ts. Add a regression test asserting popup lock screen renders onsession_expiredand vault tab lock screen renders on the SW response intercept. - Round out the WASM stub at
extension/src/__stubs__/relicario_wasm.stub.tsas part of phase 3. DEV-C noted only 7 of ~25 exports are stubbed; phase 3's vitest tests forcreate_vault/attach_vaultneed stubs forembed_image_secret,register_device,manifest_encrypt. Add them rather than file a separate ticket. - The
recovery_qr_generated_atdirect chrome.storage.local write atsetup.ts:1056-1062is out of scope — leave it as-is; defer to a P3 cleanup. - Do not merge your branch to main. The PM owns merges.
- Do not push
--forceor rungit reset --hard. PerCLAUDE.md: ask first.
Coordination protocol
You are one of multiple terminals. The relay routes messages between them.
At every phase boundary (complete, blocked, or question): call read_messages(for="dev-c") first, then post your update via post_message(from="dev-c", to="pm", kind="status"|"question", body="...") and also print it here. Use this format:
## STATUS UPDATE — DEV-C
Time: <iso8601 like 2026-05-04T14:30:00-07:00>
Branch: feature/2026-05-04-c-extension-restructure
Task: <phase number / short name>
Status: STARTED | IN-PROGRESS | DONE | BLOCKED | REVIEW-READY
Last commit: <short sha + first line of message>
Tests: <green | red (which failed) | N/A>
Notes: <anything PM needs to know — keep to 3 sentences max>
When you need PM input mid-task: post via post_message(kind="question") with format:
## QUESTION TO PM — DEV-C
Time: <iso8601>
Context: <what phase, what decision point>
Options: <A: ... / B: ... / C: ...>
Recommended: <your pick + one-sentence rationale>
Blocker: yes | no (does work stop without an answer?)
You'll receive: ## DIRECTIVE TO DEV-C blocks from the PM via relay (or relayed by user if relay is down). Acknowledge and act.
Cross-plan coordination
- Plan A owns the
.free()swallow removal (service-worker/session.ts:26) and the Rustimpl Drop for SessionHandle. Do not redo that work. Do honor the policy where you move callsites (see Hard Rules). - Plan B Phase 8 ships WASM parser exports (
parse_month_year/base32_decode_lenient/guess_mime) that the extension can eventually consume. Consumption (SW message handlers wrapping the new exports) is explicitly deferred to a future plan — do NOT design those handlers in this train. The seam exists; nobody is wiring it yet. extension/src/wasm.d.tsshared touchpoint with Plan B. See Hard Rules — you likely don't need to touch it. If you do, escalate to PM for sequencing.
Authority within the plan
You don't need PM permission to:
- Execute phase-to-phase per the plan
- Make implementation decisions consistent with the plan and synthesis
- Choose how the typed
StateHostexposessetState(the plan suggestssetState<K extends keyof PopupState>; pick the variant that gives the cleanest call-site ergonomics) - Pick which file
ViewandPopupStatemigrate to (shared/types.tsvs newshared/popup-state.ts) — the plan accepts either - Add new tests, refactor your own code, fix bugs you introduce
- Push commits to your feature branch
You do escalate to PM when:
- You discover phase 3's setup-to-SW migration needs new WASM entry points (would touch
wasm.d.tsand conflict with Plan B Phase 8) - You discover the
view/PopupStatemigration in phase 1 surfaces more TS errors than the plan estimated (~15-30); if you hit 100+ errors, the surface area is bigger than the plan accounts for - You discover a real bug in the existing
vault_lockedchannels (e.g. popup currently doesn't actually receivesession_expireddespite the plan's premise) - A vitest test you can't make green after honest debugging (don't fudge — debug)
- A discovered bug not in your plan
- Anything destructive (per project rules)
- Before opening the PR for review
Final steps before REVIEW-READY
Run the project's full validation:
# From the worktree root (/home/alee/Sources/relicario-plan-c):
cd extension
npm test # vitest
npm run build # Chrome build
npm run build:firefox # Firefox build
cd ..
# Done-criteria sanity greps:
grep -n ': any' extension/src/shared/state.ts # should return zero
grep -rn 'relicario-wasm' extension/src/setup/ # should return zero (post-Phase-3)
wc -l extension/src/setup/setup.ts # should be ≤ ~500
wc -l extension/src/vault/vault.ts # should be ~200
grep -n 'loadDeviceSettings\|loadBlacklist\|saveBlacklist' \
extension/src/service-worker/router/popup-only.ts \
extension/src/service-worker/router/content-callable.ts # should be imports only, no defs
grep -n 'itemToManifestEntry' extension/src/service-worker/router/ # should be imports only
Then push and open the PR:
git push -u origin feature/2026-05-04-c-extension-restructure
gh pr create --base main --head feature/2026-05-04-c-extension-restructure --title "refactor(ext): typed StateHost + setup→SW + vault.ts split (Plan C)" --body "$(cat <<'EOF'
## Summary
Architecture-review followup Plan C (extension restructure — eliminates the two steepest learning cliffs). Source: `docs/superpowers/specs/2026-05-04-extension-restructure-design.md`.
- **P1.6** — `extension/src/shared/state.ts` now has a concrete `StateHost` interface (no `any` in public surface), `getState`/`setState` generic over `keyof PopupState`, double-registration guard, `__resetHostForTests` helper. `View` and `PopupState` migrated from `popup/popup.ts` to `shared/types.ts` to break circular import.
- **P1.9** — `service-worker/storage.ts` extracted; `itemToManifestEntry` moved to `service-worker/vault.ts`. Both router files import; no more duplicated definitions.
- **P1.4** — `setup.ts` no longer imports `relicario-wasm`. New `create_vault` / `attach_vault` SW messages handle vault creation transactionally. Procedural wizard converted to a step-registry pattern (`{ id, render, attach }[]`). `clearWizardState()` on `beforeunload` + step-0 reset wipes sensitive `Uint8Array` material best-effort. `setup.ts` LOC dropped from 1220 to ~500.
- **P1.5** — `vault.ts` split into `vault-shell.ts` / `vault-sidebar.ts` / `vault-list.ts` / `vault-drawer.ts` / `vault-form-wrapper.ts`. `vault.ts` retained at ~200 LOC (routing + state only). `vault_locked` RPC intercept lifted into `shared/state.ts` so popup and vault tab consume one channel. Drawer auto-closes on non-list views. Sidebar search debounced.
- **P2 cluster** — inactivity timer resets on all messages except a documented exclusion set; `state.gitHost` clears on session expiry; `teardownSettingsCommon` extracted; `devices.ts`/`trash.ts` use `Promise.allSettled`; `content/detector.ts` MutationObserver debounced.
- **`get_vault_status`** — closes the `relicario status` parity gap. New SW message returns cached `{ ahead, behind, lastSyncAt, pendingItems }`; vault sidebar renders an indicator on mount + manual refresh.
## Cross-plan coordination respected
- **Plan A** owns the `service-worker/session.ts:26` swallow removal and the Rust `impl Drop`. This PR does NOT redo that work. Wherever this refactor moved a `.free()` callsite (Phase 3 setup-to-SW migration), the new location calls `wasm.lock(handle)` first regardless of Plan A's status.
- **Plan B Phase 8** WASM parser exports are a seam this PR does NOT consume in this train. Future plan wires the SW handlers.
- **`extension/src/wasm.d.ts`** not touched by this PR (verified at Phase 3).
## Test plan
- [ ] `cd extension && npm test` passes (vitest including new tests for typed state, SW storage helpers, `clearWizardState`, drawer auto-close, `vault_locked` channel, `get_vault_status`)
- [ ] `cd extension && npm run build && npm run build:firefox` clean
- [ ] `grep -n ': any' extension/src/shared/state.ts` returns zero
- [ ] `grep -rn 'relicario-wasm' extension/src/setup/` returns zero
- [ ] `wc -l extension/src/setup/setup.ts` ≤ ~500
- [ ] `wc -l extension/src/vault/vault.ts` ~200
- [ ] Manual smoke: load extension → setup → unlock → vault tab → drawer behavior → settings → trash
- [ ] Manual smoke: trigger session expiry, confirm both popup and vault tab show lock screen
- [ ] Manual smoke: vault sidebar status indicator updates on sync
## Done criteria
Per `docs/superpowers/specs/2026-05-04-extension-restructure-design.md` Done criteria — every checkbox.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
Emit a ## STATUS UPDATE with Status: REVIEW-READY and the PR URL (post via post_message).
First action
After reading: emit a ## STATUS UPDATE confirming setup complete (worktree created at /home/alee/Sources/relicario-plan-c, plan absorbed, on feature/2026-05-04-c-extension-restructure). Post it via post_message(from="dev-c", to="pm", kind="status", body="..."). Then start Phase 1 of your plan (typed StateHost + View/PopupState migration). Remember: phase 1 is the precondition for phases 3 and 4 — do not start them until phase 1 is green.