Files
relicario/docs/superpowers/specs/2026-06-20-extension-cli-parity-gap-analysis.md
adlee-was-taken c5b1917eb0 docs(spec): extension<->CLI parity gap analysis — matrix, gap classification, prioritized work list
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).
2026-06-20 21:00:43 -04:00

20 KiB
Raw Blame History

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/main b09e0ce (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:

  1. 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.
  2. Backend-exists-but-no-wire/UI: attachment removal (removeAttachmentsFromItem helper exists, no remove_attachment router message), per-item purge (purge_item handler exists, only a bulk "empty trash" UI), and the isInTab() popup-mode gate that hides login/secure-note attachment editing in the popup window.
  3. 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, .git backup 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 (favorite only 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 + wireGroupAutocomplete live in login.ts only; card/key/identity/totp/document forms pass group through without an input).
  • Tag editing — Document-form only (f-tags in document.ts only; 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 UIfavorite 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.comx.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_attachment wire + 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, .git backup 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. SM www.x.comx.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 b09e0ce and 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 at extension/src/shared/messages.ts); (2) a few inventory line numbers were off by single digits and have been replaced with hand-verified ones.