Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
6.8 KiB
Dev A — RESUME Prompt (v0.9.0 Plan A, org foundation)
Paste everything below the --- into a fresh Claude Code terminal.
You are RESUMING Plan A (org foundation: SW + WASM) 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.
Resume setup (replaces the original Setup block)
cd /home/alee/Sources/relicario.v0.9.0-dev-a
pwd # must print /home/alee/Sources/relicario.v0.9.0-dev-a
git status # expect your branch, clean-ish tree
git log --oneline -8 # confirm Tasks 1-4 are committed (down to f5336e3)
git fetch origin
git merge origin/main # main now has Dev-D's keyfile merge (d649203). EXPECT trivial additive
# conflicts in crates/relicario-wasm/src/lib.rs and extension/src/wasm.d.ts
# (D added keyfile_* / unlock_with_secret next to your org_* fns) — keep BOTH.
ALL work stays in /home/alee/Sources/relicario.v0.9.0-dev-a. Every subagent prompt MUST start with cd /home/alee/Sources/relicario.v0.9.0-dev-a (project memory — a header is not enough).
Read for full context
docs/superpowers/coordination/v0.9.0-dev-a-prompt.md— your ORIGINAL prompt: use it for ROLE, the RELAY protocol + shim, the STATUS/QUESTION block formats, polling cadence, specs/plan paths. IGNORE its Setup block and its "begin Task 1."docs/superpowers/plans/2026-06-20-v0.9.0-org-a-foundation.md— your plan.CLAUDE.md.
The relay is up on localhost:7331 (shim: cd /home/alee/Sources/relicario/tools/relay && python3 call.py read_messages '{"for":"dev-a"}'). The PM (me) is live — poll before/after every subagent and at task boundaries.
WHERE YOU ARE — already done, do NOT redo (commits, local-only, not pushed)
- Task 1
org_unwrap_key— DONE. Device-key form resolved EMPIRICALLY = OpenSSH PEM blob (paramdevice_private_openssh). zeroizedextract_ed25519_seedhelper lifted intorelicario-core::device, reused bysign(). (NOTE: this signature changes in Task 4.5 below.) - Task 2 org manifest over WASM — DONE. The org manifest is a dedicated
OrgManifest { schema_version, entries: OrgManifestEntry[] }}type (NOT the personalManifestEntry). You exposedorg_manifest_decrypt+org_manifest_encryptover WASM (wrappingvault::{decrypt,encrypt}_org_manifest) and mirroredOrgManifest/OrgManifestEntryfaithfully/LEAN intoshared/types.ts({id, type, title, tags[], modified, trashed_at?, collection}—collectionREQUIRED; NO personal-only fields). - Task 3 multi-context session — DONE.
clearAllis best-effort (eachhandle.free()in its own try/catch, null personal + clear orgs + reset context REGARDLESS, never throws);setOrgfrees the displaced handle; lock + inactivity timer both zero ALL handles;session.test.tsupdated to the best-effort contract with a WHY rationale comment + a multi-handle test. Org key NEVER persisted. - Task 4 org config +
org_list_configs— DONE. Wired in all THREE places (PopupMessage union + POPUP_ONLY_TYPES + handler arm);org_list_configsreturnsOrgConfigSummary {orgId, displayName}ONLY (no token leak, asserted). Minor cleanup pending:saveOrgConfigs()is unused — remove-or-justify at your simplify pass.
KEY PM DECISIONS during the lift (absorb — you have no relay history)
- Grant filter (Task 5) = Option A, SOFT phase-1 filter. Add a WASM
org_manifest_decrypt_filtered(handle, encrypted, granted[])that decrypts AND grant-filters in core, so ungranted entries never cross to JS — used by the READ path only. Single-source the filter: extract a core helperfilter_by_collections(&[String])that BOTHOrgManifest::filter_for_memberAND the new WASM fn delegate to (no filter logic reimplemented in WASM/TS). KEEP the full unfilteredorg_manifest_decrypt— Dev-C's writes need the FULL manifest (re-encrypting a filtered subset would wipe ungranted entries). Comment that phase-1 is a soft UX filter (the member holds the single org key), NOT crypto isolation — defense-in-depth only.
YOUR REMAINING WORK (you are the org-track critical path — B and C wait on your merge)
- Task 4.5 — NEW foundation prerequisite (Variant Y): device-key persist + restore. DISCOVERED GAP: the extension never persists the device ed25519 private key —
DEVICE_STATE(WASMdevice.rs) is in-memory only, wiped on every SW restart;chrome.storage.localstores onlyvaultConfig/imageBase64/device_name. Soorg_unwrap_key(andsign_for_gitfor Dev-C) have no key after a restart. Build (private key NEVER crosses to JS):- WASM: at register, encrypt the device private key under the current session master key and return CIPHERTEXT to JS; JS persists it as
device_key_encinchrome.storage.local. - WASM
restore_device_key(session_handle, encrypted): decrypt under the master key + repopulateDEVICE_STATE(decrypt INSIDE WASM). Wire it at unlock. - Refactor
org_unwrap_key→org_unwrap_key(keys_blob)— read the seed fromDEVICE_STATEinternally; DROP thedevice_private_opensshparam. - Migration: if
device_key_encis absent at unlock (existing installs), handle gracefully (re-register + persist). - Tests: persist→restore round-trip; survives-SW-restart simulation;
org_unwrap_keyworks post-restore;device_key_encin storage is NOT plaintext. (This ALSO unblocks Dev-C's production signing.)
- WASM: at register, encrypt the device private key under the current session master key and return CIPHERTEXT to JS; JS persists it as
- Task 5 — org read core:
openOrg(read publicmembers.json/collections.json, match this device by ed25519 fingerprint → grants,org_unwrap_key, fetch +org_manifest_decrypt_filteredto grants, cache);getOrgItem(items/<collection>/<id>.enc→item_decrypt);listOrgCollections. Offline: on git network error, serve last-cached manifest read-only +offline: true. - Task 6 —
org_switch+ read messages:org_switch {context}(sets context, cachesOrgHandleState, offline-aware),org_list_items(grant-filteredOrgManifestEntry[]),org_get_item {id}(Item),org_list_collections(Collection {slug, display_name}). Wire all in the three places. - Then full validation (cargo test wasm/core, wasm32 build, clippy
-D warnings,cd extension && npx vitest run src/service-worker/ && npm run build:all), simplify pass, pushfeature/v0.9.0-dev-a-org-foundation, postStatus: REVIEW-READY. The PM merges you FIRST in the org track (your merge is Dev-B's green light).
First action
cd into the worktree, run git log --oneline -8 to confirm state, read_messages(for="dev-a") to get my resume directive, then post a ## STATUS UPDATE with Status: IN-PROGRESS, Task: 4.5 device-key persist, confirming RESUMED + main merged. Then continue via superpowers:subagent-driven-development.