Forward-planning survey (not v0.8.1 scope). Two independent sweeps (PM 3-agent +
Dev-D 4-reader workflow with adversarial critic), reconciled and hand-verified
against source at b09e0ce. Headline: core item-CRUD at full parity (extension
often ahead); genuine extension gaps cluster in metadata management (group/tag/
filter editing limited to specific forms, zero favorites UI), backend-exists-no-
wire items (remove_attachment, per-item purge, isInTab attachment gate), autofill
hostname matching, and the org vault (largest, already specced/deferred).
20 KiB
Extension ↔ CLI Parity Gap Analysis
- Date: 2026-06-20
- Author: Dev-D, reconciled against an independent PM parity sweep
- Status: Draft for review — forward-planning, NOT v0.8.1 scope
- Anchor commit:
origin/mainb09e0ce(v0.8.0 org vault + v0.8.1 Dev-A foundation merged; Dev-B/C/D in flight) - Scope note: This plans a future milestone. Extension org writes remain explicitly out of scope for v0.8.1 per
docs/superpowers/specs/2026-06-20-relicario-v0.8.1-parity.md(Plan B-2).
Purpose
Survey the gap between the Relicario CLI (relicario) and the browser extension, classify every gap as a real parity gap, an intended CLI-only capability, or already-planned-in-a-spec, and produce a prioritized work list (with rough sizing) to bring the extension up to CLI parity. The driver is the project's CLI/extension parity philosophy: features should not ship "CLI-first, extension-later" without an explicit, recorded decision — this doc is that record for the current backlog.
Method
Two independent surveys were run and then reconciled:
- PM sweep — 3 inventory agents + synthesis.
- Dev-D sweep — 4 parallel readers (CLI / extension-UI / extension-SW / specs+roadmap) → synthesis → an adversarial completeness/accuracy critic, all reading from a worktree pinned at
b09e0ce.
The two sweeps were deliberately blind to each other. All load-bearing claims in this document were hand-verified against source (greps + line reads); where the two sweeps disagree, the disagreement is flagged explicitly in §Reconciliation. Line citations are point-in-time against b09e0ce and may drift.
Executive summary
Core item-CRUD parity is excellent. All 7 item types (Login, Secure Note, Identity, Card, Key, TOTP, Document) and the add / edit / view / list / trash / restore lifecycle are at full parity, and in several places the extension is the richer surface (live TOTP codes, custom fields/sections, TOTP-from-QR, password coloring, session auto-lock, autofill/capture). Where a per-type gap exists it is most often on the CLI side, not the extension's.
The genuine extension-side gaps cluster into three buckets:
- Metadata-management gaps (the headline finding): editing groups, tags, and filtering is wired into only specific forms/surfaces in the extension, while the CLI offers them uniformly across all types; favorites has zero extension UI (strictly worse than the CLI). These are real, currently-shipping parity gaps on the personal vault.
- Backend-exists-but-no-wire/UI: attachment removal (
removeAttachmentsFromItemhelper exists, noremove_attachmentrouter message), per-item purge (purge_itemhandler exists, only a bulk "empty trash" UI), and theisInTab()popup-mode gate that hides login/secure-note attachment editing in the popup window. - The org (enterprise) vault — the single largest gap. The entire org feature (shipped CLI-only in v0.8.0) has no extension presence (no org routes, no org context). This is fully specced and explicitly deferred (Dev-D org-read / Plan B-2 org-write).
Plus one quality gap on the personal side surfaced by the PM sweep: autofill hostname matching is a naive exact-equality match.
Intentionally CLI-only by design (not gaps): real git pull/push and .git-history backup bundling (the extension writes straight to the host Contents API and keeps no local repo), the imgsecret embed recovery subcommand, recovery-QR's deliberate no-file-write contract, org admin (members/collections/grants/rotate/audit), and shell completions.
Reconciliation with the PM sweep
The PM sweep concluded: extension at near-full parity on the personal surface, ahead in places, with the org vault as the one material gap and autofill hostname matching as the only personal-side quality gap.
Agreements (both sweeps, independently):
- Org vault is the largest gap; it is fully specced and deferred (Dev-D read / Plan B-2 write).
- The extension leads on live TOTP, custom fields/sections, password coloring.
- The intended-CLI-only set: git sync/push,
.gitbackup bundling, device-key deploy-key plumbing, org admin, shell completions.
Dev-D refines / partially refutes the PM: the personal surface is not "near-full parity with autofill as the only gap." There is a real cluster of personal-side extension gaps the PM sweep understated:
- Favorites — none in the extension (
favoriteonly round-trips through save fns; no toggle, no star in lists, no filter). The CLI is itself only add-only, so the extension is strictly worse. The PM hypothesis did not list this. - Group editing — Login-form only (
f-group+wireGroupAutocompletelive inlogin.tsonly; card/key/identity/totp/document forms passgroupthrough without an input). - Tag editing — Document-form only (
f-tagsindocument.tsonly; other forms preserve-but-don't-edit). - Filter — popup has no type filter (vault-tab only) and no tag filter anywhere.
- Per-item purge and attachment add/remove have working backends but no popup-reachable UI / no router wire.
PM caught, Dev-D's taxonomy missed: autofill hostname matching. service-worker/vault.ts (findByHostname, equality at :344) matches credentials by exact icon_hint equality ((e.icon_hint ?? '').toLowerCase() === hostname) — no www. strip, no registrable-domain (eTLD+1) match, so www.example.com will not match an item stored as example.com. Confirmed; folded in as a real LOW-MED personal-side gap. (Dev-D's capability taxonomy centered on item-CRUD/features and under-weighted the content-script autofill path — the PM sweep is the reason it appears here.)
Methodology correction (a Dev-D self-sweep error, struck here): the Dev-D extension-SW inventory referred to a messages.ts "that does not exist at that path." That is false — the file exists at extension/src/shared/messages.ts (227 lines): it holds the PopupMessage union (with delete_item // soft-delete at line 23), POPUP_ONLY_TYPES (line 168), and CONTENT_CALLABLE_TYPES (line 224). The inventory had merely dropped the shared/ directory prefix. The substantive findings it supported (the unwired searchItems/removeAttachmentsFromItem helpers) are independently verified correct; the "file doesn't exist" caveat is removed from this document.
Parity matrix
Support: full / partial / none / n/a. gap_class: at-parity · real-gap (extension work) · real-gap (CLI-side) (extension already ahead; CLI backlog) · cli-only-by-design · already-planned.
Item types
| Capability | CLI | Ext | gap_class | Notes (evidence @ b09e0ce) |
|---|---|---|---|---|
| Login: create/view/edit | full | full | at-parity | CLI add/get/edit login; ext form + add_item/update_item/get_item. |
| Secure Note: create/view/edit | full | full | at-parity | Both complete. |
| Identity: create | full | full | at-parity | Both; ext also exposes address. |
| Identity: view | full | full | at-parity | Both. |
| Identity: edit | partial | full | real-gap (CLI-side) | CLI edit_identity omits date_of_birth + records no history; ext edits all. CLI backlog. |
| Card: create/view | full | full | at-parity | Both. |
| Card: edit | partial | full | real-gap (CLI-side) | CLI edit_card = holder+number only (no CVV/PIN/expiry/kind); ext edits all. CLI backlog. |
| Key: create/view | full | full | at-parity | Both; ext takes public_key interactively. |
| Key: edit | partial | full | real-gap (CLI-side) | CLI edit_key = key-material only (no label/algorithm/public_key); ext edits all. CLI backlog. |
| TOTP: create | full | full | at-parity | Both; ext adds Steam Guard kind. |
| TOTP: view | partial | full | real-gap (CLI-side) | CLI shows metadata only; ext shows live rotating code. See "TOTP live code". |
| TOTP: edit | full | full | at-parity | Both. |
| Document: create | full | full | at-parity | CLI encrypts file as attachment; ext upload_attachment. |
| Document: view | partial | full | real-gap (CLI-side) | CLI metadata + extract; ext inline image preview. CLI backlog. |
| Document: edit | none | full | real-gap (CLI-side) | CLI edit on Document is a no-op redirect to attach/extract; ext changes primary/supplementary files. CLI backlog. |
Operations
| Capability | CLI | Ext | gap_class | Notes |
|---|---|---|---|---|
| add / edit / get / list | full | full | at-parity | All 7 types both surfaces. |
| rm / soft-delete | full | full | at-parity | CLI rm; ext delete_item (messages.ts:23, handler popup-only.ts). |
| trash (list) | full | full | at-parity | CLI trash; ext trash view. |
| restore from trash | full | full | at-parity | CLI restore; ext restore_item. |
| purge (permanent) | full | partial | real-gap | Ext UI only bulk "empty trash" (purge_all_trash, popup-only.ts:420); no per-item purge UI, though purge_item handler exists (popup-only.ts:409). CLI has single + bulk. |
Features
| Capability | CLI | Ext | gap_class | Notes |
|---|---|---|---|---|
| Attachments: add | full | partial | real-gap | Login/secure-note attachment editing gated behind isInTab() (login.ts:370,388; secure-note.ts:123,140) — unavailable in popup window; document renders unconditionally (document.ts). SW upload_attachment is full. |
| Attachments: view/download | full | full | at-parity | CLI extract; ext download + download_attachment. |
| Attachments: remove | full | partial | real-gap | SW helper removeAttachmentsFromItem (vault.ts:492) has no router wire (remove_attachment absent — confirmed). UI removes refs at form-save only, with the same isInTab() caveat. CLI detach is full. |
| TOTP: live code | none | full | real-gap (CLI-side) | CLI reveals raw base32 only; ext computes live codes. Extension leads. No spec mandates CLI OTP. |
| Generator: password / passphrase | full | full | at-parity | CLI generate; ext generator-panel + generate_password. |
| Settings: view / edit | full | full | at-parity | CLI settings; ext get/set_vault_settings. |
| Search | partial | partial | at-parity | CLI: title-substring. Ext: client-side over title/group/tags/icon_hint; SW searchItems (vault.ts:316) exists but unwired (no search_items message). Neither does field-value full-text. |
| Filter | full | partial | real-gap | CLI list filters type/group/tag/trashed. Ext: type filter is vault-tab-only; popup has none; no tag filter anywhere. SW list_items filters by group only. |
| Favorites | partial | none | real-gap | CLI add-only (--favorite on Login add, * in list; no toggle/filter). Ext: zero UI — favorite only round-trips. Ext strictly worse; needs a paired CLI+ext design. |
| Tags | full | partial | real-gap | CLI full create+filter all types. Ext: only Document form edits tags (f-tags in document.ts); no tag chips in lists; no tag filter. SW round-trips tags. |
| Groups/folders | full | partial | real-gap | CLI all types --group, list --group. Ext: only Login form has f-group+autocomplete; other forms set no group; vault-tab "group" filter is actually a type filter. SW list_groups/group-filter full. |
| Field history (view) | full | full | at-parity | CLI history; ext get_field_history. |
| Custom fields / sections | none | full | real-gap (CLI-side) | CLI has no custom-field/section commands (core supports them); ext renderSectionsEditor covers all 7 types. CLI backlog. |
| Autofill hostname matching | n/a | partial | real-gap | Ext-only feature; matcher (vault.ts findByHostname, :344) is exact icon_hint equality — no www. strip / eTLD+1. www.x.com ≠ x.com. (PM-surfaced.) |
Org (enterprise) vault
| Capability | CLI | Ext | gap_class | Notes |
|---|---|---|---|---|
| Org: read items | full | none | already-planned | CLI org get/list grant-filtered, all 7 types. Ext has zero org code. Planned Dev-D. Spec: 2026-06-06-relicario-enterprise-org-vault-design.md § Extension — Org Context; ROADMAP "Extension org parity — read". |
| Org: write (add/edit/rm) | partial | none | already-planned | CLI write = Login/SecureNote/Identity only (OrgAddKind, main.rs:560; Card/Key/Document/Totp absent — v0.8.1 lift in flight). Ext none. Planned Plan B-2. Spec: 2026-06-20-relicario-v0.8.1-parity.md § Out of scope. |
| Org: member/collection mgmt | full | none | cli-only-by-design | CLI full lifecycle (~19 subcommands). Ext none — org admin is intended CLI-only (high-trust, low-frequency). |
Vault lifecycle / infra
| Capability | CLI | Ext | gap_class | Notes |
|---|---|---|---|---|
| Vault init / setup | full | full | at-parity | CLI init; ext setup wizard + create_vault/attach_vault. |
| Git sync (pull/push) | full | partial | cli-only-by-design | CLI real git pull --rebase/push. Ext writes straight to host Contents API; no local graph (ahead/behind always 0). Functionally syncs; architecturally different by design (extension/ARCHITECTURE.md). |
| Device management | full | full | at-parity | CLI device; ext renderDevices + SW device CRUD. (GitHub/GitLab deploy-key API is the deferred edge.) |
| Backup / restore | full | full | at-parity | CLI .relbak + git-history bundling; ext export/restore_backup. .git bundling sub-aspect is cli-only-by-design (ext has no local repo). |
| Import (LastPass) | partial | partial | at-parity | Both LastPass-CSV only; other importers deferred both surfaces by policy. |
| Recovery QR | full | full | at-parity | CLI generate/unwrap; ext generate/unwrap_recovery_qr. Webcam scan deferred both. |
| Standalone generate (no vault) | full | none | cli-only-by-design (low-confidence) | CLI generate/rate work outside a vault; ext generator is embedded in login form + settings (needs unlocked vault). A browser extension lacks the "no vault" generator use-case a shell has. No spec; flag if user demand appears. |
Intended CLI-only (no taxonomy row; recorded so they are not re-litigated as gaps)
| Capability | gap_class | Notes / spec |
|---|---|---|
Recovery-QR file-write (--out) |
cli-only-by-design | Negative API contract — no surface writes the payload to disk; absence is the security property. 2026-05-01-recovery-qr-design.md. |
| Org delete-org push to remote | cli-only-by-design | Phase-1 delete-org is a local tombstone; pre-receive hook rejects protected-file deletion. Pushable delete-org is phase-2. 2026-06-06-...-design.md. |
imgsecret embed subcommand |
cli-only-by-design | CLI disaster-recovery tool; the extension setup wizard's image flow covers the equivalent. |
| Password coloring (CLI TTY) | cli-only-by-design (inverted) | Ext shipped it (v0.5.1); CLI TTY parity deferred until demand. 2026-05-01-password-coloring-design.md § Out of scope. |
| Shell completions | cli-only-by-design | No extension analogue. |
Gap classification summary
- Real extension gaps (extension work closes them): per-item purge UI; attachment add/remove UI +
remove_attachmentwire +isInTab()gate; popup type filter + tag filter; tag editing on all forms; group editing on all forms; favorites UI; autofill registrable-domain matching; org read (specced); org write (specced, behind CLI type parity). - CLI-side gaps (extension already ahead — separate CLI backlog, NOT extension work): Identity/Card/Key edit field coverage; Document view/edit; live TOTP code; custom fields/sections commands.
- Intended CLI-only (not gaps): git pull/push,
.gitbackup bundling, org admin,imgsecret embed, recovery-QR file-write, shell completions, standalone generate. - Already planned / deferred: org read (Dev-D), org write + org item-type breadth (Plan B-2), org attachments/multi-vault (behind org).
Prioritized forward work (extension)
Only items where extension work closes the gap. CLI-side gaps and intended-CLI-only items are excluded.
| Pri | Item | Size | Why | Depends on |
|---|---|---|---|---|
| P0 | Attachment remove + un-gate popup: wire a remove_attachment router message to removeAttachmentsFromItem (vault.ts:492); drop the isInTab() gate so login/secure-note attachment add & remove work in the popup. Closes both the add half (row "Attachments: add") and remove half. |
M | Backend exists and is unreachable — highest value-per-effort. The popup-mode gate is a UX cliff (can't manage login attachments without popping out). | — |
| P0 | Per-item purge UI: surface the existing purge_item handler (popup-only.ts:409) as a per-row permanent-delete in the trash view (today only bulk purge_all_trash). |
S | Pure UI wiring over an existing handler; CLI has single-item purge. | — |
| P1 | Group editing on all type forms: add f-group + wireGroupAutocomplete to card/key/identity/totp/document (Login-only today). |
M | SW (list_groups, group filter) already full; replicate one existing form pattern across 5 forms. |
— |
| P1 | Tag editing on all type forms + tag chips in lists: promote Document's f-tags to a shared affordance on all 7 forms. |
M | SW round-trips tags fully; only Document edits them today. | — |
| P1 | Filter parity: add a type filter to the popup (vault-tab has it) and a tag filter to popup + vault tab; optionally push type/tag params into list_items. |
M | CLI filters type/group/tag; ext type filter is fullscreen-only, tag filter absent. | Tag editing (so tags exist to filter on) |
| P2 | Favorites (paired CLI + ext): favorite toggle in detail/edit, favorites filter, star in list rows — and extend the CLI beyond add-only, to reach true parity per the parity philosophy. | M | Ext strictly worse than CLI (none vs partial); both surfaces weak. Write a short spec first. | — (spec TBD) |
| P2 | Autofill registrable-domain matching: replace exact icon_hint equality (vault.ts findByHostname:344) with www.-strip + eTLD+1 matching. |
S–M | www.x.com ≠ x.com today; the one personal-side quality gap. |
— |
| P2 | Search wire-up (hardening): expose searchItems (vault.ts:316) via a search_items message, or formally adopt client-side filtering and remove the dangling helper. |
S | Functionally at-parity, but an unwired helper is dead-code drift. | — |
| P3 | Org read in extension (Dev-D): org context switcher + SW org handlers (unwrap org master key into a Zeroizing session handle) + grant-filtered manifest browse/read in popup + vault tab. |
XL | Largest single gap; entire org feature is CLI-only in the extension. Specced, deferred. | — |
| P3 | Org offline read-only indicator: "org offline — writes disabled" banner when the git remote is unreachable in org context. | S | Spec-mandated UX. | Org read |
| P3 | Org SW acceptance tests: org context replaces personal manifest cleanly; org master key never in localStorage/IndexedDB; offline mode triggers on network error. | M | Spec-mandated coverage following the feature. | Org read |
| P3 | Org write in extension (Plan B-2): org add/edit/rm including Card/Key/Document/Totp. | XL | Closes org write + item breadth. Deferred past v0.8.1. | Org read and CLI reaching Card/Key/Document/Totp org-write parity (v0.8.1) |
Caveats
- Line citations are point-in-time against
b09e0ceand drift with edits. - This is a planning artifact, not a commitment; sizes are rough (S ≈ hours, M ≈ a day, L ≈ days, XL ≈ a multi-stream lift).
- Two analytical errors caught during cross-check and corrected here: (1) the struck
messages.ts-doesn't-exist claim (file exists atextension/src/shared/messages.ts); (2) a few inventory line numbers were off by single digits and have been replaced with hand-verified ones.