# Read-only password-store domains `VaultReader` in `crates/storage` owns the semantics for `list`/`ls`, explicit and implicit `show`, `find`/`search`, and decrypted `grep`. Frontends receive typed models and render storage-provided paths; they do not inspect tree text, ciphertext names, or decrypted display strings to infer domain state. ## Trees and dispatch Tree models contain separate entry and directory node kinds, logical paths, names, and deterministic children. Entry names never contain the `.gpg` storage suffix. Policy files, signatures, other metadata, `.git`, and `.extensions` trees are not nodes. The plain renderer produces the stable uncolored tree used by command-line output. No show path selects the root tree. A path is resolved against the repository snapshot: an entry decrypts to redacted `SecretBytes`, while a directory returns its subtree. Missing and ambiguous paths remain typed repository errors and map to the normal `pass` failure status. Clipboard and QR requests use the parsed `Presentation` enum and a nonzero line number. Storage selects that line directly from decrypted bytes and returns a `PresentationSecret` containing the logical entry, line, channel, and redacted zeroizing contents. The adapter never parses rendered terminal output, and a missing or empty requested line is an explicit failure. ## Name and plaintext search Find performs Unicode case-insensitive substring matching against logical entry and directory names. Multiple terms are alternatives, as in upstream `pass`. Results include typed matches plus a pruned deterministic tree with the necessary ancestors. Hidden implementation directories, metadata, and ciphertext suffixes cannot become matches. Decrypted grep uses the Rust `regex` byte engine, which provides linear-time matching without invoking GNU grep. The accepted command contract is limited to case-insensitive, inverted, line-number, and fixed-string behavior; unsupported GNU options fail during command parsing. Entries are visited in repository order, each plaintext is decrypted only while its lines are examined, and the full plaintext buffer is zeroed when that iteration ends. Matched lines are copied into redacted `SecretBytes`; rendered grep output is also returned as `SecretBytes`, and both are zeroed with their result values. Debug output includes paths and counts but never matched contents.