Skip to content

Latest commit

 

History

History
173 lines (149 loc) · 37.2 KB

features.md

File metadata and controls

173 lines (149 loc) · 37.2 KB

Features in detail

Every feature the plugin has, and why each one works the way it does. The README is the tour; this is the reference behind it.

  • Full Status Bar & Quick Access Panel Integration:

    • Live vault lock state indicated in the status bar (󰞀 shield icon: accent when unlocked, base when locked, urgent when unauthenticated).
    • Clean drop-down panel with fast navigation and keyboard-first workflow.
  • Authentication & Secure Keyring Storage:

    • Direct Master Password unlock.
    • Interactive login starts with Email + Password and reveals the 2FA prompt only when Bitwarden requires it (Authenticator App or Email); API Key credentials (BW_CLIENTID / BW_CLIENTSECRET) remain available as a separate method.
    • Custom Server Support: Works seamlessly with official Bitwarden servers and self-hosted Vaultwarden instances.
    • Terminal login fallback: when the built-in form cannot cover your login method -- SSO, a Duo push, a hardware key -- the login screen offers Launch Terminal, which runs bw login in a real terminal so Bitwarden's own prompts handle it.
    • That terminal hands its session straight back: it captures the key with bw login --raw (prompts stay on stderr, so the login is still interactive) and writes it to $XDG_RUNTIME_DIR/qs-bitwarden-cli/session-handoff, mode 600, in a directory created 700 before the file exists. There is no fallback path: if XDG_RUNTIME_DIR is somehow unset the login refuses to run rather than putting a session key anywhere a second user could have prepared. The panel reads that file once, deletes it, and comes back unlocked -- no second login just to get in. If the vault was merely locked rather than logged out, the same button unlocks instead. It only reads it when it is expecting to. The check runs on every status refresh, and it used to adopt whatever was at that path whether or not the panel had ever asked for a terminal login -- so anything able to write the file could hand the panel a session key at a moment of its own choosing, and the panel would take it and write it to the keyring. The runtime directory is 0700, so that is one of your own processes rather than a stranger and it was never a privilege boundary; it was a window with no reason to be open. A key is only expected in the ten minutes after the panel itself launched a terminal, so those are the only minutes it is read in. Outside them the file is deleted unread -- not reading it is not a reason to leave a live session key lying in the runtime directory, and a login abandoned halfway leaves exactly that.
    • The terminal reopens the panel for you on success, then closes itself; you only have to dismiss it if something went wrong and there is an error worth reading.
    • Two bw status calls used to sit on that path, each around three seconds on a real vault: one in the terminal to decide login-versus-unlock, one in the panel to confirm a key bw had just minted. Neither is needed -- the panel already knows which state it is in, and the confirming check now starts only after the item list has been rendered instead of sitting in front of it.
  • Several accounts at once:

    • Up to ten accounts, each signed in on its own: Add Account signs another one in without signing the first out, and Switch Account moves between them. Only one is unlocked at a time -- switching locks the one being left, drops its items and secrets from memory, and tells the SSH agent the account changed so its keys and exported public keys go too.
    • bw keeps one account per data directory, so each account added beside the first gets its own, ~/.local/share/qs-bitwarden-cli/accounts/<slot>/ (mode 700), given to every bw the panel runs in BITWARDENCLI_APPDATA_DIR. The first account stays in bw's own directory, so a terminal bw still sees it and upgrading changes nothing for it.
    • Each account's keyring entries -- session, stored password, and the legacy per-method entries -- are named with the account's slot (unlock_envelope@<slot>), and secret-tool matches names exactly, so no lookup for one account can find another's. The first account keeps the names it always had.
    • PIN, fingerprint and FIDO2 unlock are per account: each account's stored password has its own ways in, so the same finger or key unlocks every account with nothing re-enrolled.
    • Log Out clears only the account on screen: its keyring entries, its learned suggestions and its data directory. Signing the same account in twice keeps the newer sign-in and removes the older one.
    • The list (registry.json beside the directories, mode 600) holds only emails, user ids and servers, and anything malformed in it is dropped rather than trusted.
  • One stored password for quick unlock:

    • The master password is kept once, in one keyring item: encrypted under a random key (XChaCha20-Poly1305) and sealed to this machine and user with systemd-creds --user. It is written the first time bw accepts a password you typed, and each quick-unlock method only adds a way into it. See How quick unlock stores your password.
    • Turning a method on asks for your master password as a check against the stored one -- a wrong one is refused, and nothing typed there is stored.
    • A master password changed elsewhere is picked up at the next unlock with the new one; every method keeps working.
    • Turning a method off removes it from every account (the setting is shared), and a method turned off in shell.json while the shell was not running is removed at the next start.
    • Upgrading moves the old per-method entries in as each method is next used, and deletes them once the new copy opens.
  • Pinentry for typed secrets (usePinentry, on by default):

    • The master password (unlock, and the re-prompt on a flagged item) and the PIN are typed into pinentry, a separate window and process, not into the panel, so they never enter the shell's memory. The panel hides while it is open. A wrong one opens it again with the reason; Cancel returns to the screen without an error.
    • Uses pinentry from PATH; set pinentryProgram in the plugin's shell.json entry to use another (for example /usr/bin/pinentry-qt). pinentry-gnome3 types into gcr-prompter, which runs outside the helper's core-dump protection (which pinentry). Needs the vault helper to be running: while it is starting or stopped, the unlock screen and the re-prompt wait for it with no field.
    • Without pinentry, with the setting off, or with the vault held in the shell (allowVaultWithoutHelper), the panel's own field is used. If pinentry fails or is stopped, the panel says so and the next attempt opens it again; the field is used only when you pick "Type it here instead", until the panel closes or the vault locks or unlocks. A failure is never remembered, and neither is a check for pinentry that was killed, so another program cannot turn pinentry off by killing it.
    • Pinentry closes itself after two minutes without an answer, as a cancel.
    • The email login, quick-unlock setup (its master password and new PIN) and the item forms always use the panel.
    • See Vault helper.
  • PIN Unlock (opt-in, pinUnlock):

    • Unlock with a numeric PIN instead of typing the master password. 6 digits is the floor and 8 or more the recommendation, and there is no upper limit. A 6- or 7-digit PIN is accepted, with the real cost of guessing it spelled out. A PIN set before the floor was raised (from 4) still unlocks.
    • The PIN reaches the stored password through Argon2id (256 MiB, 4 passes). The stored item is sealed to this machine, but a program running as you can unseal it and guess PINs offline on every core: about 17 guesses a second on a 16-thread laptop, so every 6-digit PIN in about 16 hours, 7 digits in about 7 days, 8 digits in about 2 months.
    • A wrong PIN always fails; there is no stored PIN hash.
    • Five wrong attempts at the panel's own screen removes the PIN's way in; re-enabling needs the master password again. The limit does not apply to a copy of the stored item.
  • Fingerprint Unlock (opt-in, fingerprintUnlock):

    • Unlock the vault with an enrolled fingerprint instead of retyping your master password.
    • Verifies through the same PAM stack as the Omarchy lock screen (/etc/pam.d/omarchy-lock-fingerprint), so it works wherever omarchy setup security fingerprint has been run.
    • Turning it on asks you to confirm your master password up front, rather than quietly capturing it on some later unlock.
    • The reader is armed automatically whenever you open the panel on a locked vault; the master password field always stays available as a fallback.
    • A closed lid takes the option off the screen: the reader is on the laptop body, so with the lid shut (clamshell mode, or a lid closed on a docked machine) the unlock button is hidden and the reader is not armed, on the locked screen and in the SSH prompt alike. Nothing is forgotten, and the option returns when the lid opens. Omarchy's omarchy-hw-laptop-closed decides.
    • A fingerprint releases no secret, so with it on a program running as you can open the stored password. See Fingerprint unlock before enabling it.
  • FIDO2 Key Unlock (opt-in, fidoUnlock):

    • Unlock the vault with a FIDO2 authenticator -- a YubiKey or any compliant key with hmac-secret -- instead of retyping your master password.
    • Uses the registration Omarchy's own setup writes (omarchy setup security fido2 to /etc/fido2/fido2), so one registration serves the vault and the system's own authentication prompts alike, and nobody re-enrolls. The setup screen offers that command when no key is registered yet.
    • One touch asks the key for its hmac-secret, which opens the stored password. The key will not produce it without a touch, so unlocking needs the key itself, not just access to the keyring.
    • Each plugged-in registered key gets its own way in; registrations that ask for the key's PIN (+pin, +verification) are not used. The key is armed automatically on lock when one is plugged in; the fingerprint reader is the fallback, and the master password field always stays available.
    • See FIDO2 key unlock.
  • SSH Agent (opt-in, sshAgentEnabled):

    • Serves the SSH keys in your vault to ssh, git and ssh-keygen -Y sign while the vault is unlocked, from a separate helper process that holds the private keys in memory and drops them on lock, logout, or exit. They are never written to disk and never reach QML.
    • Every signature shows the key, its fingerprint and the program asking. The default prompt lives in the panel; the opt-in centered popup makes the plugin otherwise disappear until a decision is needed. One approval can cover a whole rebase; live approvals are listed and revocable, and repeated unanswered prompts fall back to a cooldown rather than pestering.
    • Public keys are projected to files for Git signing, one file per item, public material only. See SSH Agent.
  • Context-Aware Password Suggestions (Active Window / Browser Tab):

    • Reads the active window on open (hyprctl activewindow -j, falling back to the hyprctl clients -j focus history when the panel itself holds focus).
    • Recognises the current site from the browser's page title and matches it against each item's URLs and name using Bitwarden-style host and base-domain rules, brand aliases (a Gmail tab matches a google.com item), and word-boundary matching that ignores public suffixes and generic labels such as www, login, or com.
    • Places a highlighted 󰌠 Matches window title: <App / Website> banner and pins matching credentials to the top of the list with pre-selection, so pressing Enter immediately copies the right credential.
    • Not phishing protection. Hyprland exposes a window's title, not the tab's address, and a page writes its own title: one titled github.com on any domain is matched to a github.com item. The banner therefore says what the title matched, never "this site", and the address bar remains the thing to check before pasting.
    • Only the strongest tier of matches is shown (at most 6), and a title with nothing identifiable in it produces no suggestions rather than a guess.
    • Standalone desktop apps match on window class; terminals only suggest for remote ssh/mosh/sftp hosts, never for local shells.
    • It learns. Opening or copying an item while a window is active records the window's site (a domain in its title) or app against the item, and it is suggested outright next time -- ahead of every heuristic. Learned suggestions are marked 󰐾 rather than 󰌠.
    • Suggest here / Suggested here in an item's detail view pins or unpins that item for the current site or app deliberately. A pin is also the only thing that records the title's words, which is what handles sites a title can never match: a portal on auth.example.xyz titled Home - authentik shares no word with the stored credential, so pin it once and it sticks. An ordinary pick never learns title words: a learned match skips scoring and a page chooses its own title, so a word learned from a pick let any page sharing it (a lookalike) have the real site's login suggested first. Word keys an older version learned from picks are kept in the file but no longer match.
    • Re-picking a different item retargets what was learned, so a bad association corrects itself the next time you choose.
    • Associations live in ~/.local/state/qs-bitwarden-cli/associations.json (mode 600; associations@<slot>.json for an account added beside the first) and hold only vault item IDs and the domains, apps and pinned title words they were learned from -- never credentials. The file goes to its writer on standard input (an environment variable is capped at 128 KiB, and a store past that silently stopped being saved). Writes replace a private temporary file atomically, never follow a symlink, and narrow an older permissive file back to 600; reads validate the schema and discard unknown versions, malformed entries, and keys outside the domain:, app:, and word: namespaces. Logging out deletes the file after any active writer has exited, so an in-flight update cannot resurrect the previous account's metadata. It holds no secrets, but between them the domains, app names and timestamps are a record of which sites the account has logins for and when each was last used, in the clear and with no expiry of its own.
    • Limitation: browsers do not publish the active tab URL to Wayland or Hyprland, so the heuristics work from the page title. A site whose title mentions neither its name nor its domain (New Tab, a bare Sign in) cannot be inferred -- teach it once instead.
  • Smart Auto-Copy TOTP Flow on Enter:

    • Selecting a login item and pressing Enter copies the Password to the clipboard and automatically closes the panel, returning focus immediately to your target application so you can paste (Ctrl+V) and submit.
    • If the item has a TOTP 2FA secret configured, the plugin automatically copies the live 6-digit TOTP code to your clipboard after a brief delay (default: 3s) and posts a desktop notification saying so. The notification deliberately does not contain the code: a notification daemon keeps history and can render a body over a lock screen, which is no place for a live second factor. The digits are shown in the panel itself, with their countdown.
      • You can immediately paste the TOTP code into the 2FA prompt without ever reopening or refocusing the plugin!
      • If you prefer manual progression, pressing Enter or t while the follow-up banner is active also copies the code immediately.
  • Every item type is readable, not just logins:

    • Cards show the cardholder, brand, number, expiry and security code. The number and the code are masked until revealed, and each reveals independently of the other -- an eye is a statement about the field it sits on.
    • Identities show the name, username, company, email and phone, the social security, passport and licence numbers, and the address as a single copyable block rather than seven separate rows. Empty fields are not drawn, so a sparsely filled identity stays short. The three identifiers are masked for the reason a password is, with the difference that these cannot be rotated afterwards.
    • Both are searchable by what the list shows them as: a card by brand, cardholder or last four digits, an identity by name, email, username or company. Deliberately not by the middle of a card number -- a substring search across stored card numbers is not a lookup this box should perform.
    • SSH keys remain public records: the panel lists them, shows the public key and fingerprint, and serves them through the agent, but never draws or writes private material.
  • Full Add, Edit & Delete (CRUD) Operations:

    • Create Items (n key or + button): Add new Logins (󰌋), Secure Notes (󰈐), Cards (󰿯) or Identities (). SSH keys are read-only here: generating one would mean handling private key material, which the plugin deliberately keeps out of its process.
    • Password Generator: A full generator screen (g or the 󰌆 button) mirroring the Bitwarden browser extension's options -- password (length, A-Z, a-z, 0-9, special, minimum numbers, minimum special, avoid ambiguous) or passphrase (word count, separator, capitalise, include number), with a live strength meter. Generation comes from Bitwarden's own generator rather than a reimplementation, and the item form's Generate... button opens this same screen and fills the password field in on the way back.
    • It is fast. A fresh bw generate costs about 2.9 seconds, almost none of it generation: roughly 0.9s is the CLI's Node bootstrap and 2s is Bitwarden's service container starting, and every option toggle paid it again. The panel now starts bw serve the first time you open the generator and asks that, which answers in about 2ms. The server listens on a Unix socket in the private runtime directory ($XDG_RUNTIME_DIR/qs-bitwarden-cli/generator.sock, directory mode 700), not on a loopback port: a port is reachable by every user on the machine, who could ask /unlock to guess your master password (no second factor, no lockout) and /status for your email and user id. (A logged-out server on an empty data directory would hold no account at all, but Bitwarden CLI 2026.2.0 refuses to serve while logged out.) The server is also started with no session, so it is a locked vault, and it is only up while the generator screen is. An answer on the socket is not taken as proof the server is ours: it is probed before we start, and anything already answering means the panel uses bw generate for that visit. If our own server later dies, any value it had already supplied is discarded rather than left on screen to be copied, and a bw that cannot serve on a socket falls back to bw generate. No request can hold the panel up or fill it. Every request runs through a managed child process with curl's config disabled, proxies bypassed, a two-second deadline, and a producer-side 64 KB cap.
    • Edit Items (e key or Edit button): Modify titles, credentials, authenticator keys, URLs, notes, and every card and identity field. Saving changes only what you changed: a password's edge spaces and a note's trailing newlines are kept, and the website field edits the first website only -- every other website, and each one's match rule, is kept as stored (saving used to replace them all with one entry at the default rule, which widened browser-extension autofill). Enter saves from anywhere in the form, so a long item does not have to be scrolled to the bottom to be committed -- except while a folder, organization or collection picker is open, where Enter belongs to the list being picked from.
    • Delete Items (x key or Delete button): Delete items with confirmation protection.
    • Saving and deleting do not hold the panel. Both cost whatever bw costs -- a second or two of CLI startup, vault decryption and a round trip -- and the panel used to spend all of it on a frozen form. The form closes as soon as the command is launched and the list shows the item as it will be, its icon replaced by a spinner until the vault answers, at which point the authoritative version takes its place. An item still being saved cannot be edited or deleted, and a second save waits for the first. If the vault refuses one, the list goes straight back to what the vault actually holds and the message offers to reopen what you typed rather than costing you the edit.
  • Bitwarden Send (Alt+S or the 󰒗 button):

    • Share a secret through a link that expires on its own, so a credential need not live in a chat log.
    • Create a text Send with a name, hidden-by-default text, a deletion window (1-31 days), a maximum view count, and an optional password. The access link is copied to your clipboard the moment it is created.
    • Lists your existing Sends with how long each has left (in 3 days, expired), views used against the maximum, and whether a password is set. Copy a link or delete a Send from the row.
    • Keyboard: n new, r refresh, x delete the highlighted Send, Enter copy its link, Esc back.
    • The Send payload -- which carries the Send password -- is passed to bw through the environment, never on the command line.
  • Attachments:

    • Items that carry files are marked with a 󰏢 paperclip in the list, and the detail view lists each attachment with its name and size.
    • The list costs nothing: bw list items already returns the attachment metadata with the cipher, so the files are on screen the moment the item opens. Only the bytes need the CLI, and only for the file you ask for.
    • Save puts a file in your download directory (xdg-user-dir DOWNLOAD, falling back to ~/Downloads), then offers Open and Show in folder for it. a saves every attachment on the item; they are fetched one at a time rather than starting a bw per file.
    • Nothing is ever written through whatever already sits at the chosen path: the bytes land in a private staging directory first and the finished file claims its name atomically, so a symlink left in the download folder is stepped around rather than followed, and an existing file is never overwritten -- " (1)", " (2)" and so on go before the extension until the name is free.
    • A download is bounded before it starts and while it runs: 512 MB per file, 15 minutes, and a check that the disk has room. If the server omits the size, the preflight reserves for the full 512 MB ceiling rather than treating it as an empty file. A transfer that breaks a limit leaves nothing behind.
    • A file name out of the vault is treated as hostile. It is decrypted content that is about to become part of a path, so path separators and control characters are replaced rather than stripped, a leading dot or dash is dropped, and the result is quoted on top of that: ../../.bashrc saves as bashrc in your download directory and nowhere else. Tests run the real script against a stub bw to prove it.
  • Folders:

    • Filter by folder from the bottom filter bar: All Folders, No Folder, or any specific folder.
    • Items show their folder inline (󰉋 Name) when no folder filter is active.
    • Assign a folder when creating or editing an item from an expandable list, including clearing an existing assignment, and create a new folder inline without leaving the form.
  • Unified Bottom Filter Bar:

    • Three identical buttons centred at the bottom -- Folders, Organizations, Types -- each showing its current selection, so the active filters are readable at a glance without opening anything.
    • Opening one drops the window down like a drawer rather than squeezing the item list, with a pinned header naming the group (and its total when it overflows).
    • Five options are visible at a time and the rest scroll underneath the pinned header.
    • Any action outside the drawer closes it -- selecting an item, searching, copying, syncing, locking or opening another screen -- so it never sits over the results.
    • Fully keyboard driven: f folders, o organizations, t types; ↑/↓ move through the options, Enter applies, Esc closes. The cursor starts on the option already active, so Enter changes nothing by accident.
  • Organizations & Collections:

    • The item form picks an organization from an expandable list, and reveals that organization's collections once one is chosen -- Bitwarden files org-owned items into collections rather than folders, and refuses to save one that is in none.
    • Collections are a multi-select, since an item can belong to several. A lone collection is pre-selected, and the form says "pick at least one" before the CLI would.
    • Choosing My Vault for an organization item clears both its organization and its collections.
  • Multi-Organization & Vault Filtering:

    • Automatically queries and displays organizations you belong to.
    • Organization filter bar: All Vaults, My Vault (Personal items), or specific shared Organization.
    • Shared items display a prominent 󰓹 Org tag in the list and detail views.
    • Choose destination vault (Personal vs. Organization) when creating or editing items.
  • Guided First Run — no prerequisites:

    • omarchy plugin add ... --enable is the entire install. The widget enables into the bar with nothing else installed, wearing a + badge, and opens on its setup screen instead of a login form it cannot service.
    • The dependency probe runs ahead of anything that touches bw, so a machine without the CLI never lands on a dead end.
    • The setup screen watches for the install it launched and moves on to the vault by itself the moment the tools land — no re-check, no restart.
  • Setup Wizard & In-Panel Settings:

    • Checks the tools Omarchy does not already ship (bw, plus fingerprint unlock) in a single probe, marking each required or optional and saying what it is for. Everything else the plugin shells out to comes with Omarchy, so the screen stays one short list rather than a wall of rows that are green on every machine.
    • A missing required tool opens the wizard automatically. Install hands off to omarchy install app, which surfaces the install in Omarchy's own floating, centred terminal -- the same window every other app install on the system opens. The one exception is a package swap Omarchy's non-interactive installer cannot agree to: when bitwarden-cli's Node LTS dependency would replace an installed nodejs, the row says so and Install runs sudo pacman -S --needed in that same terminal instead, so pacman asks you.
    • Fingerprint unlock is Omarchy's job end to end: Set up runs omarchy setup security fingerprint, which detects the reader, installs libfprint/fprintd/usbutils, enrols a finger, verifies it, and writes the PAM stacks. The row is only drawn on a machine with a reader (omarchy-hw-fingerprint), and there is no pkg add fprintd button, because installing the package alone leaves the row exactly as red as it was.
    • Press , or the 󰒓 button for settings, grouped into General, Security and SSH Agent: auto-lock timeout, clipboard clear delay, TOTP auto-copy delay, and every toggle. The section you are reading is named above the list and stays there as you scroll. Maintenance actions sit under their own heading, and the destructive one -- Remove Plugin Data -- under a separated DANGER ZONE, so the button that clears your keyring entries does not look as safe to press as the one that opens a checklist. A setting whose dependency is missing is shown but inert, with the reason given.
    • Changes are written to the plugin's entry in ~/.config/omarchy/shell.json through omarchy bar set, so Omarchy owns the file and the shell hot-reloads the change. Nothing is stored in a second place.
    • Reachable from a keybind too: omarchy-shell io.github.elevate08.qs-bitwarden-cli settings (or setup).
  • Hardware-Accelerated Performance & Security:

    • Virtualized ListView with component delegate recycling for instant rendering of large vaults.
    • Asynchronous search debouncing (50ms) for responsive 0ms typing latency.
    • Unlock and password-login startup is prewarmed. Opening the locked screen, or focusing the password field while logged out, starts the Bitwarden CLI and leaves it waiting on a private mode-600 FIFO. Submitting the form writes the exact password bytes into that pipe, so most of the CLI's Node and service-container startup has already happened. Closing the panel cancels the waiting process and removes the FIFO.
    • Items load before secondary metadata. After authentication, the first command fetches only the item list. Folders, organizations and the confirming status refresh begin after those items have been parsed and rendered. Short Loading items... and Syncing... status text exposes the work without adding another screen.
    • There is no persistent item cache. Every authenticated cold load is verified through bw; decrypted vault items are never written into the plugin directory or another cache. The speedup comes from moving startup off the submit path and removing unrelated commands from the critical item path.
    • Credentials do not reach a command line. /proc/<pid>/cmdline is world-readable on a default Linux install while /proc/<pid>/environ is not. The session token travels in BW_SESSION; direct unlock and email-login passwords move from BW_PASSWORD through the private FIFO selected with --passwordfile; API key credentials use BW_CLIENTID / BW_CLIENTSECRET; item, folder, and Send payloads and copied secrets use their own variables. None is interpolated into a command or shell script. The two-step login code is carried in QSBW_CODE. bw reads the code only from --code, so the command line holds a placeholder flag that the bw-login-code.js preload (loaded through NODE_OPTIONS) replaces with --code=<code> in bw's own process.argv, a copy the kernel's cmdline does not show. A standalone bw binary ignores NODE_OPTIONS, rejects the placeholder before contacting the server, and the panel sends that login to the terminal instead. Tests assert that no builder emits --session and that no auth command carries a password, client secret or client ID in argv.
    • The custom-server field is checked before the master password is sent to it. bw config server takes whatever it is given, and the next thing down that path is your master password, so a plain http:// address is refused unless it is loopback -- where there is no wire to listen on, and where a local Vaultwarden or an SSH tunnel to one is a normal way to run this. Any scheme that is not http or https is refused outright. The loopback exemption is anchored and userinfo is stripped before the host is judged, so http://localhost.evil.com and http://localhost@evil.com are both refused. Backslashes are refused too: WHATWG clients interpret them as path separators, and otherwise http://evil.example\@localhost can look local to a lightweight parser while connecting to evil.example.
    • Automatic clipboard clearing after a configurable timeout (default: 30s): the copy is served by wl-copy --foreground under timeout, detached from the shell, so the clear happens even if the shell restarts, and a newer copy (yours or anyone's) makes that wl-copy exit, so the deadline never touches it. Locking or switching accounts clears the clipboard only while it still holds a copy marked sensitive. Copies are marked sensitive so clipboard history skips them. Password and TOTP fallback reads are managed and generation-checked, so a command that finishes after a lock cannot put its result on the clipboard.
    • A shell crash leaves no vault in its core dump. The session key and every item's secrets are held by a separate helper process that turns its own core dumps off and cannot be attached to; the shell holds names, usernames and websites, and a secret only while you have it revealed or are editing its item. Copies go from the helper to the clipboard, and TOTP codes and search are answered there. The shell's own core dumps are untouched. If the helper is unavailable, the panel falls back to holding the vault itself and says crash protection is off. See Vault helper.
    • Master password re-prompt is honoured. An item marked "Master password re-prompt" in Bitwarden asks for your master password before its password, TOTP, hidden fields or card details are revealed or copied, and before it is edited or deleted. The password is checked against the stored copy, or by bw itself when there is none yet, and never on a command line; a confirmation lasts while that item stays open.
    • Optional session token caching in Linux Secret Service (secret-tool / libsecret). Turning it off removes a stored session at once (and at the next start, if it was turned off in shell.json), and with it off, unloading the shell while unlocked runs bw lock.
    • A lock is checked, not assumed. A failed bw lock is retried once and then confirmed with bw status, and you are told if the vault is still unlocked in bw; the remembered session's keyring clear is verified the same way. Suspending waits for both (up to 4 seconds, inside logind's 5-second limit) instead of a fixed second, since bw lock alone takes 1-3 s to start.
    • Keyring writes cannot race a lock, logout, or cancelled setup. Session, PIN, and fingerprint-password stores are generation-stamped; a completion from an old vault or an authentication setup form the user left is cleared instead of recreating a credential that was just removed.
    • Locking the vault also discards what was still on its way out of it. Every read and operation records the vault generation it started under, and the generation moves whenever the vault is locked, logged out of, or unlocked. A late item list, generated password, attachment completion, CRUD result, or newly created Send link is dropped instead of repopulating memory, navigating the locked panel, or copying a secret after the lock. Process output is accepted only after its exit status is known.
    • And a lock forgets it as well as refuses it. Refusing a stale answer still leaves it in the pipe it came down. Quickshell's StdioCollector keeps whatever its process last printed for as long as that process is not started again -- text is read-only, there is no clear(), and nothing drops the buffer when the panel stops reading it -- so every secret that had ever come back through one was still in the shell after the vault locked: the session key from the handoff file and from the keyring, the master password from the PIN and fingerprint lookups, both halves of a login or unlock, the whole item list with each login's password in its raw object, an item detail, a live TOTP. Clearing the properties those were copied into left the originals sitting behind them. The buffer is replaced when the process next starts, so a lock now runs a command that prints nothing through every collector that can hold vault data or a credential; anything still mid-read is come back for once it finishes.
    • Auto-lock counts the time the machine was asleep. Qt schedules its timers on the monotonic clock, which Linux stops while the machine is suspended, so a fifteen-minute countdown armed just before the lid closed still had fifteen minutes to run when the lid opened -- a vault left overnight came back exactly as open as it was left. The deadline is kept in wall-clock terms as well and polled every thirty seconds, so waking a suspended machine locks the vault rather than resuming the countdown. Between the monotonic timer and the wall clock, whichever notices first does the locking.
    • The vault locks when the screen locks and when the machine suspends.
    • Settings are validated where they are read, not only where they are written. Nothing validates shell.json, and a bad value there can fail open rather than loudly: a non-numeric minute count reaches QML as NaN, lands in an integer property as 0, and 0 is how "never lock" is spelled, while a count past the documented ceiling overflows the timer's 32-bit interval into a negative number that never fires. Each numeric setting is held to the range in the table below, and anything unreadable falls back to its default instead of to zero. Boolean settings accept only actual JSON booleans, so strings such as "false" cannot become truthy by JavaScript coercion.
    • A remembered session does not survive a reboot. The login keyring is a file on disk that PAM unlocks again at the next login, so a machine powered off with an unlocked vault used to come back unlocked. Two things stop that. The token is written to libsecret's session collection, which the secret service holds in memory and destroys with the login session, so there is nothing on disk to come back; and it is stamped with the kernel's boot id, so a token that does survive -- a secret service with no session collection, a keyring restored from a backup -- no longer matches the running boot and is refused and cleared instead of used. Restarting the shell still keeps you unlocked. Powering the machine off does not.