Features
- check for updates from the menu, and say who wrote this
- offer an update in a native dialog on launch
- update the app in place from a signed GitHub release
- flip UI flags at runtime from a shortcut, so a signed build can be tested
- put rotation behind a build-time flag, off by default
- rotate the vault's secret, with every consequence stated first
- open the highlighted entry from the panel, and separate the disconnect verbs
- fill the browser from the panel
- Enter copies the highlighted result's password
- send the hotkey to the vault window when locked
- search the vault from the panel and pick a result
- make Enter the fill action in the panel
- show the panel's shortcuts under the search field
- offer to carry a vault's entries into the shared one
- connect a browser in one code and one click
- let a browser claim the sync invite over the link
- sync with the desktop app over the link, not the relay
- hold the desktop link open so sync can arrive unprompted
- sync with browsers on this machine over the link, not the relay
- carry sync frames over the browser link
- compare pairing emoji instead of twelve digits
- admit the joiner in the process, not the window
- keep the vault in step with its group after enrollment
- run device-sync enrollment in the webview
- give this device a sync identity
- expose the sync host's crypto, and skip the native WebRTC bridge
- ask the desktop app what it holds
- carry queries over the established session
- index the vault for the browser link
- bundle the proxy so the browser link works from a real app
- link to the Bramble desktop app
- show a pairing code in Settings
- install the native-messaging host manifest
- add the native-messaging proxy
- serve the browser pairing handshake over a local socket
- keep the pairing key in the OS credential store
- pair with a browser extension over an allowlisted static key
- expose the Noise handshake to the native build
- outlive the main window, and leave the Dock with it
- add the spotlight panel shell
- let the single-column screens fill the window
- fix the window at 600x580, and name the scripts by verb
- scaffold the Tauri 2 app on the shared Rust core
- validate the expiry and security code too
- validate the card number against a zod schema
- copy a card's expiry and CVV from the row menu
- add an MDX blog, starting with the one-month write-up
- tag iOS releases, still without a GitHub release
- port the portable vault to iOS and Android
- read a .bramble export back in, merging into the vault
- export the selection as a .bramble file
- bulk-select entries in the list, with delete
- seal a portable vault under a file-only key
- mark logins that hold a passkey in the list
- keep the last few passwords a login rotated away from
- choose the destination vault for an inbound transfer
- reachable UI for OS credential transfer (phase 3)
- credential exchange plugin, plists and token handoff (phase 2)
- CXF 1.0 mapper, both directions (phase 1)
- import passkeys from Bitwarden JSON
- expose passkey key import across platforms
- convert imported P-256 PKCS#8 keys
- copy the verification code from the list row's copy menu
- link the Matrix room from the header and footer
- add well-known delegation files for federation
- recover a vault whose entries won't decrypt, from a verified snapshot
- write KeePass .kdbx files under a user-chosen password
- read Apple Passwords and Google Password Manager CSVs
- iOS one-time-code AutoFill, behind the keyboard-suggestions opt-in
- unlock iOS with the device passcode
- offer the password suggestion even when the vault is locked
- suggestion-only prompt on signup, tokenized light/dark colors
- offer the strong-password suggestion on change forms
- suggest a strong password on signup forms
- build android in the reproducible container, sign on host
- prepare F-Droid inclusion, commit build numbers to source
- add Buttondown newsletter signup form
- collapsible stats row on home, sticky
- graceful spinner fallback for slow lazy-route loads
- plain divider + "Create another vault" on single-vault unlock
- Astro + Starwind landing site on shared @vault/theme
- bolder, wider on-page picker
- make QR scan the primary Join experience on mobile
- wire back navigation - Android hardware back (#15) + setup-shell back button
- restore the QR-code scanner in the mobile Join flow
- always offer the "Join a device" tab
- active-vault-aware Android autofill + per-vault biometric
- per-vault biometric unlock (core + iOS)
- show 'Join a device' in the setup shell on a fresh device
- render 'Restore from backup' inline as a tab, not a page swap
- unify first-run 'open existing vault' with the multi-vault restore flow
- hide 'Create new vault' on unlock when multiple vaults exist
- join a P2P mesh from the setup shell (join = add a vault)
- per-vault VEK inc 6 - atomicity guard + lock-to-picker
- per-vault VEK inc 5 - hand the VEK to enrollment explicitly
- per-vault VEK inc 4 - tag the background consumers
- per-vault VEK inc 3 - scoped view adapter + create binding
- per-vault VEK inc 2 - the seam flip (offscreen + background)
- per-vault VEK inc 1 - inert threading (schemas + vek-store)
- forward the inviter's recovery slot to joiners (shared group recovery code)
- restore .bramble backups from the Add-a-vault screen
- scheduled backups cover every vault, not just the primary
- vault name inline on the home header + on the unlock screen
- always show the active vault's name in the header
- show the active vault's name in the header
- per-vault device sync (extension)
- share the active vault id with the background (multiple vaults phase 2)
- vault name input in General; delete moves to its own re-auth-gated section
- drop create/switch buttons from the settings vault section
- settings vault section acts on the current vault only
- inline recovery-code and switch-vault links with a dot separator
- per-vault picker cards + context-aware setup screen (multiple vaults)
- settings vault list + switch vault (multiple vaults phase 1)
- add 'choose a different vault' link on the unlock screen
- create parallel vaults + launch-time vault picker (multiple vaults phase 1)
- thread active vault id through VaultProvider (multiple vaults phase 0)
- vault registry + id-aware blob storage (multiple vaults phase 0)
- show/hide toggle on every password field
- separate "lock on screen lock" toggle + fix locked-prompt desync
- single-instance pop-out window (no tabs permission)
- accept patch/minor/major bump keywords
- Monero first + Lightning/on-chain toggle on the BTC card
- add the Bitcoin (Lightning) donation card
- replace "Total entries" with source-code links
- wire the real Monero donation address
- Support / donations section (Bitcoin + Monero)
- "Last synced" timestamp in the Sync settings (extension + mobile)
- live-refresh target status on background writes
- keep-last-N retention control in the target form
- enable .bramble backup restore
- open a .bramble file from the "Open existing vault" screen
- rename the "Data" tab to "Backups"
- sort the generic "Other" tiles last
- single alphabetical provider grid
- drop the Google Drive tile; Dropbox is the only OAuth provider
- configure the Dropbox app key + add files.metadata.read scope
- OAuth one-click providers (Dropbox), Phase 2
- automatic scheduled backups in the background
- accept a full bucket URL and show target errors in full
- persist the active tab in route search params
- restore a .bramble backup (extension-only for now)
- wire manual backup end-to-end
- S3 + WebDAV storage clients and backup orchestrator
- cloud backup settings UI
- auto-publish to the Chrome Web Store on
release chromium - macOS "touch your YubiKey" banner before each age decrypt
- "Immediate" auto-lock that locks when the last view closes
- carry Bitwarden URI match detection into subdomainMatch
- broadcast on local write so a change pushes immediately
- Phase 3 hardening (A2 doc, B3 DAL SSRF, B4 clock-skew)
- password-authority admission producer (iOS + Android)
- password-authority admission producer (extension)
- cross-language feature flags for the phase-1 -> phase-2 rollout
- password-derived admission signing key (Item A)
- admission gate (verify side) closes rogue-injection (Item A)
- sticky roster tombstones close the B1 re-add resurrection
- mirror sync status to the persistent host/background console
- reset sync state on new-vault creation
- activate roster signing on the extension (Item A #3b)
- sign this device's own roster entry at enrollment (Item A #3b, core)
- verify gossiped rosters before merge (Item A #3b, verify half)
- TOFU roster verification kernel (Item A #3a)
- Ed25519 device-key signer for roster mutations (Item A #2)
- roster-entry signing foundation; defer group-key rotation
- fail loud when an unverified caller supplies a browser clientDataHash (B2)
- verify native-app autofill domains via Digital Asset Links
- export an encrypted .bramble vault backup
- store the vault in chrome.storage.local, drop the FSA backend
- restore the popup route on reopen while unlocked
- declare data_collection_permissions (required: none)
- attach buildable source to the AMO listed submission
- Firefox ships listed to AMO; GitHub release carries source only
- metadata:firefox pushes by default, --dry-run to preview
- metadata:firefox pushes the localized AMO listing
- translate web store listings (Chrome + AMO) from the repo
- passkey provider via MAIN-world content-script transport
- relay-forward transport as a negotiated WebRTC fallback
- Firefox WebRTC host iframe — probe increment (option a step 1)
- request persistent storage so the only vault copy isn't evicted (Firefox port, phase 5)
- float current-site matches to the top of the list
- search, filter, sort, and lifecycle timestamps for the vault list
- attach SHA256SUMS to chromium releases (parity with android)
- registration (create) + pending handoff (step 3)
- assertion flow - sign in with a stored passkey (step 2b)
- vault passkey read + W3C response JSON builder (step 2a)
- register a Credential Manager provider (skeleton)
- finalize Bramble AAGUID; TODO to register it in the community list
- make a freshly-created passkey usable without opening the app
- register (create) passkeys + persist via a pending handoff
- assert stored passkeys (sign-in) in the credential provider
- surface stored passkeys to the OS credential store
- passkey rows in the login item edit + view
- get-time passkey picker for multiple accounts
- confirmation toast when the provider saves a passkey
- account picker when saving a passkey to an ambiguous domain
- differentiate save-passkey card for an existing login
- pause passkey proxy during Bramble's own WebAuthn unlock
- Settings toggle for the passkey provider (General)
- save-passkey corner prompt + create/get wiring
- webAuthenticationProxy passkey handler (orchestration)
- passkey provider vault logic (find + placement)
- WebAuthn JSON helpers for the passkey provider
- expose passkey crypto through TS adapter + transports
- passkey authenticator crypto + entry model (provider role)
- black splash with Bramble logo lockup, no white flash
- full internationalization across all targets
- modality-aware copy in the biometric Settings row
- label biometric unlock by modality (Face ID vs Touch ID)
- enforce matching master password when enrolling a device
- add ios release lane (versioning + TestFlight, build-tagged)
- native iOS WebRTC data channel via webrtc-rs
- surface transport status + state for on-device diagnosis
- native sync crypto on Android too (uniffi handshake/nostr)
- native iOS sync crypto so pairing works under Lockdown Mode
- per-device remove (revoke) with roster propagation
- stop streaming transport status into the Settings log box
- pre-fill + space the ICE/relay settings; tolerate more ICE shapes
- TURN relay + state-aware device UI, with relay diagnostics
- add Android system AutofillService at iOS parity
- build, sign, and publish Android APKs via
release android - add Android app launcher icon
- source app version natively and add per-target version bumping
- add ios:metadata script; lane pushes screenshots when present
- target the project marketing version in the metadata lane
- iOS autofill domain filtering + QuickType opt-in
- Android native crypto (uniffi Kotlin NativeCrypto plugin)
- "Immediately" auto-lock option (mobile default) replaces keep-unlocked toggle
- opt-in "keep autofill unlocked" window (15 min, off by default)
- autofill authenticates before revealing entries; encrypt the bundle
- autofill master-password unlock in the extension + passcode cache
- native iOS crypto + real autofill provider via shared uniffi core
- set the iOS app icon from icon/ios
- auto-resolve JDK 21 for android run/dev scripts
- iOS autofill credential-provider probe (Phase 3 go/no-go: GO)
- hide security-key unlock on mobile; biometric takes its slot
- re-probe biometric availability when Settings opens
- native BiometricVault plugin (iOS + Android) + adapter
- device-local biometric unlock seam (optional Platform.biometric)
- secure-storage substrate; move sync device keypair to Keychain/Keystore
- buffer recent sync status so the panel shows current state on open
- ongoing roster sync (continuous merge after enrollment)
- show status log + explicit success message on join
- hide pop-out affordance (supportsPopOut capability)
- route Settings import to in-app ImportShell with close-to-app
- camera QR scanning (getUserMedia + jsQR) for sync pairing + TOTP
- wire P2P sync enrollment (in-webview, via @core/sync/transport)
- inactivity auto-lock honoring autoLockMinutes (not lock-on-pause)
- lock vault on app background (lifecycle pause)
- streamline vault setup screen (hide file-location, pill tabs, compact)
- in-app vault setup navigation + safe-area insets
- upgrade Capacitor 7 -> 8 (SPM iOS project)
- scaffold Capacitor platform-mobile POC (Phase 0 walking skeleton)
- cap message size and subscriptions per connection
- default to hosted relay, fold URL under Advanced
- cloudflare worker relay; reorganize into node/ + cf-worker/
- cross-device P2P vault sync, with architecture, crypto, and UX hardening
- build, sign, and publish releases locally for CWS verified uploads
- support logins inside open shadow DOM (web components)
- inject content script in all frames for iframed logins (e.g. Apple ID); add reddit fixture/tests + screenshot seed
- gate release on lint + tests so a failure blocks the release
- tag releases as - with " Extension " name
- tagged-release workflow + platform-aware version-bump script
- theme-aware monochrome icon, light/dark/system selector, and entry-detail header actions
- harden the autofill UI behind an extension-origin iframe
- replace placeholder Shield logo with Bramble glyph
- Chrome toolbar/install icons + icon source bundle
- KeePass KDBX4 import — key files + WASM-side decrypt
- webauthn unlock with hmac-secret + 26 crypto/policy tests
- corner-prompt save/update card for captured logins
- a login can cover multiple websites (url:string → urls:string[])
- show the OpenSSH SHA-256 fingerprint on SSH-key entries
- lock the vault when the OS locks the screen (idle.onStateChanged)
- declare a lock-vault keyboard command (unbound by default)
- import from 1password, bitwarden, keepass and proton pass
- harden TOTP autofill and skip auto-submit on captchas
- typed entry modes with cards, notes, ssh keys + custom-field autofill
- retain state on pop-out, react to background locks, ui polish
Bug Fixes
- hide the desktop link where the browser cannot do it
- make a universal build actually produce a universal app
- make --universal actually release a universal build
- serve a valid update manifest before the first release
- arm nothing when no desktop app is paired
- reconnect the pipe and the relay after either drops
- say whether the vault on screen is the one the desktop app shares
- keep the vault and its metadata owner-only
- say which vault a desktop connect will leave you in
- three faults the first real pairing surfaced
- let the release build reach the sync relay
- let cargo run in this crate without a staged sidecar
- make a broken pairing key visible instead of silent
- read the pairing key once, not per connection
- scan this package for Tailwind classes, and collapse the panel
- give the app icon the macOS shape
- place the relayed picker in document, not viewport, coordinates
- host the picker in the top frame for hosted-fields checkouts
- translate the vault errors the UI renders
- make the session guards fail loudly instead of silently
- stop a superseded session from firing sync, backup and pop-out work
- make VEK install and removal transactional and fail closed
- bind the decrypted index to the vault session that built it
- deliver picker secrets on the requesting document's own channel
- keep app URIs out of the web hostname index
- say why a scanned QR was rejected instead of "none found"
- detect one-time-code and identifier fields beyond English
- capture logins on formless SPA submits
- keep a revealed secret inside its detail row
- say when a connection attempt fails without spending the invite
- restore a backup when the device has no vault yet
- stop dropping passkeys whose user handle exceeds 64 bytes
- translate ICU plurals instead of rejecting them
- actually show the passkey marker, and cover the seam
- tell Nextcloud users which URL the WebDAV field wants
- say which passkey field was rejected, and why
- stop re-importing the same file from duplicating everything
- converge the inviter's pairing prompt on the host, not one event
- let mobile pickers select .1pux, .kdbx and the other containers
- don't blame the user's data when the converter is missing
- re-export hexToBytes for the Bitwarden passkey importer
- wait for the pending-transfer peek before claiming
- ask for the destination vault on the condition that actually holds
- route to the import screen at a cold launch, not just on the event
- land on the preview, and stop advising a file cleanup
- passkey keys are PKCS#8 on the wire, raw scalars at rest
- register CredentialExchangePlugin with the bridge
- say why a transfer is unavailable instead of hiding it
- erase the provider mirror and biometric item on delete
- close GHSA-x4f5-4wq4-c6c8, a live pairing code grants the whole vault
- repair the escaped braces in the well-known client file
- revive the picker's iframe renderer under use_dynamic_url
- close the unlock pop-out and drop the stale locked row
- patch brace-expansion and postcss advisories
- build metadata paths from REPO, not dir
- stop gym littering the repo root with build artifacts
- keep the export path out of the ffi build
- require an explicitly captured VEK to send an enrollment bundle
- refuse a blind blob write when several vaults are registered
- verify the loaded key before overwriting a vault's entries
- record the active vault before the VEK swap, clear it on delete
- bind a mobile roster session to one vault for its lifetime
- stop Xcode re-stamping the build number at export
- stop the AutoFill unlock flashing "Keychain status -25308"
- re-translate fastlane metadata when the English source changes
- build the one-time-code identities inside the iOS 17 guard
- refuse blind blob writes, reap ghost vault records
- stop stranding ghost vaults, and land merges in the right one
- stop later list rows painting over an open row menu
- restore current-site matching in the detached pop-out
- close the TextField notch when focus is on an adornment button
- don't lose an "Unlock & save" capture, and confirm it with a toast
- refresh the dropdown after click-to-unlock (issue b)
- signups offer a NEW login, not update an existing one
- sign android without v1 or realignment for reproducibility
- container Node from nodejs.org binary, not apt
- commit Cargo.lock and pin std paths to the canonical form
- make Rust output independent of the checkout host
- scan rules for the remaining generated binaries
- satisfy the source scanner after the Rust cross-compile
- bump buildserver Node to 22.23.1 for rolldown's engine floor
- prebuild runs in one shell, so cd must not compound
- match fdroiddata CI rewritemeta formatting
- clear tar/sharp/shell-quote/fast-uri advisories; prune stale overrides
- drop public/_redirects (caused /support redirect loop)
- update brace-expansion to 5.0.7 (CVE-2025-5889)
- converge racing no-registry migrations on one vault id
- show a loader while decrypting, not an empty-vault flash
- 2FA verification-code fields no longer misdetected as CVV
- corner card / picker box model survives host-page CSS resets
- omit ambient cookies so WebDAV uploads authenticate
- override adm-zip to 0.6.0 (GHSA-xcpc-8h2w-3j85)
- refresh the on-page picker after unlock (#20)
- no white flash before the theme resolves
- stop hiding the "Keyboard suggestions" toggle behind a keyboard probe (#19)
- drive Android back through the router, not window.history
- show the real per-vault sync panel on mobile (drop the stale "primary vault" gate)
- use the extension's segmented tabs on mobile (drop the rough pill variant)
- disconnect removes the ACTIVE vault's namespaced group, not flat sync.group
- push the ACTIVE vault's password slot to iOS autofill
- target the active vault in sync + persist active-vault; scope the migration
- add the joiner to the roster in the enroll host, not just the popup
- per-vault VEK - locking is a clean slate (single-view UX)
- joining a group provisions a fresh recovery code for the device
- 'Back up now' backs up the active vault, into its own folder
- keep Firefox's event page alive during enrollment
- start ongoing sync as soon as a vault's group exists
- land on the unlocked vault's home, not the picker
- restore never overwrites an existing vault (adds a new one)
- scope the sync panel to the primary vault (stopgap)
- restore the unlocked vault on reopen instead of the picker
- use the shared TextField for the vault-name input
- make the vault picker scroll when there are many vaults
- keep unlock-screen links at text-xs
- suppress OS autofill + smart keyboard on password fields
- hide biometric unlock when OS biometry is off
- obvious tab scroll chevrons + working BTC toggle size
- move DerivedData off /tmp to a repo-local path
- accept v2 uploadState SUCCEEDED (not v1.1 SUCCESS)
- upload verified CRX via the CWS REST API v2
- upload the signed .crx to CWS (Verified CRX Uploads)
- strip manifest
keyfrom the CWS package - one YubiKey touch for chromium (decrypt both CWS secrets together)
- secretFromKeychain returns string | undefined, not null
- smaller BTC method toggle, placed below the QR
- pin donation copy buttons to the card bottom
- lay the donation cards in a row
- stop "Last synced" flickering between "now" and "N seconds ago"
- add a dot separator between the GitHub and Codeberg links
- format dates with the active app locale, not the browser default
- run the OAuth connect in the background service worker
- keep saved credentials when editing a provider
- browser passkey allow-list + fail-loud on declined create
- make Face ID biometric unlock reliable (keychain group + presence check)
- recovery-code Download saves via the native share sheet
- resolve Keychain access group from the signed entitlement (-34018)
- chunk the vault across Noise frames so large vaults sync
- clear all sync state on new-vault creation
- prune the mesh known-set on peer close so bounced peers reconnect
- mint a fresh device id on join so a revoked device can rejoin
- model multiple runtime.onMessage listeners in the bg harness
- render multi-candidate update-login prompt as markup, not text
- accept extension pages hosted in a tab (popout regression)
- sender-gate crypto/sync host and corner-update origin (A3, A4)
- enforce revocation on inbound frames and reap on gossip
- verify the privileged caller before signing a passkey clientDataHash
- only trust webDomain from a verified browser for autofill
- enforce device revocation on a live roster-sync session
- reject future-dated HLC stamps from remote peers (revocation integrity)
- scope autofill fill and corner prompt to the requesting frame
- keep the vault unlocked across the import file picker
- bump web-ext 8.10.0 -> 10.4.0 to clear dev-dep advisories
- give a clear error for an encrypted Bitwarden export
- suppress native autofill on fields the picker takes over
- await hydration in the webAuthn proxy listeners
- make background passkey vault reads FSA-safe
- decode TOTP QR in the offscreen host, not the service worker
- cache the VEK on security-key unlock
- set the AMO category on listed submissions
- set the GPLv3 license on listed AMO submissions
- resolve web-ext signed .xpi basename against artifactsDir
- pass amoBaseUrl to web-ext sign (8.x makes it required)
- close the unlock window after a locked passkey unlock
- wrap content scripts in an IIFE so they don't clobber each other's globals
- keep-alive alarm so background sync survives event-page suspension
- localize manifest via _locales (default_locale + MSG)
- Firefox testing round 1 (popup close, FSA/security-key/theme gating, sync log)
- set Firefox gecko id to firefox@bramble.app
- gate passkey provider off on Firefox (Firefox port, phase 4)
- preserve \n/\t escapes; escape stray quotes in it/es strings
- escape backslash in strings.xml encoder (CodeQL #30)
- sync screenshots instead of overwrite to stop duplicates
- replace deprecated kSecUseOperationPrompt with LAContext
- squash duplicate toasts (same message + variant)
- sign in with a single unlock (bridge list->sign)
- use a freshly-created passkey before the app drains it
- sign the browser-provided clientDataHash (fixes sign-in)
- empty save toast - use i18n._(msg
…) not the useLingui macro - rename usePendingPasskeys to .tsx so its lingui macro is transformed
- registration response needs response.publicKey (SPKI)
- set BE+BS backup flags on synced passkeys
- registration response needs authenticatorData + publicKeyAlgorithm
- attach a new passkey to the right account by username
- route background passkey crypto through the offscreen
- render the passkey card account row as markup, not text
- resolve passkey request origin from the active tab
- generate notes from conventional commits, not PRs
- skip keychain access group on iOS Simulator for biometric VEK
- run build-crypto-ffi.sh under the macOS system bash (3.2)
- release script
- hide security-key pairing option on mobile
- native iOS QR scanner for pairing/TOTP codes
- clean up helper copy and gate platform-specific rows
- trim App Store subtitle to the 30-char limit
- harden QuickType identity-store population
- flatten the 1024 marketing app icon (remove alpha)
- fastlane uses a monotonic timestamp build number (race-free)
- keep-autofill-unlocked window reuses the auto-lock timeout
- autofill unlock shows the device's biometry (Face ID / Touch ID) + passcode
- autofill UI matches the app auth screen + list (logo, card, padding)
- autofill biometric via Keychain prompt + visible error alerts
- autofill persists while locked, app-styled list, biometric hint
- autofill App Group JSON + extension Face ID, fastlane internal DerivedData
- add AutoFill entitlement to the main app target (App Store validation)
- inset safe area at #root so screens keep their own padding
- lock viewport scale to stop WKWebView rendering content off-screen
- sort imports to satisfy
biome ci - re-tag an already-bumped version instead of failing on an empty commit
- disable happy-dom resource loading so fixture fetches don't fail CI
- clear unconditionally instead of reading it back
- cap untrusted KDBX Argon2 params to prevent OOM/hang on import
Performance
- virtualize the entry list
- code-split non-first-paint routes to shrink the initial bundle
- batch native decrypt so a large vault opens in one bridge call
- decrypt the whole vault in one offscreen round-trip
- lazy-load jsqr to halve the service-worker bundle
- code-split the import flow into an on-demand chunk
Refactors
- drop the link's Test button and site probe
- let a session take its peers from somewhere other than the relay
- share the file-picker row and the notched field outline
- fold three duplicated helpers into single homes
- one ES256 constant, shared by both import paths
- one PKCS#8 conversion, in the Rust core
- group the three suites under e2e/ and document them in one place
- group Import & backup by whose format it is
- move the iOS lanes to the repo-root fastlane/
- finish the Button sweep - ErrorBoundary + BackupSection
- add a shared cva Button and adopt it across the app
- delete the dead inline-capability probe + trim comments
- drop the always-true
restorecapability - namespace every vault by id via a one-time copy migration
- remove the dead primaryId, fall back to the legacy/default vault
- drop the Settings 'Join with a pairing code' path
- single verified delete path (useVault.deleteVault)
- rename/remove act only on the active vault (never another)
- central localized date formatter; picker shows 'Created on Jan 13, 2026'
- rename passkeyProvider capability -> passkeyProviderToggle
- central per-target capability registry
- use cn() for dynamic classNames
- validate OAuth token responses with zod
- extract the scheduled-run orchestration to core
- support multiple backup targets
- split sections into scrollable tabs
- drop reducible
as unknown ascasts across TS (20 -> 5) - switch dispatch + drop wasm-view double casts
- rip out dead FSA / file-picker code
- transport-select the crypto+sync host (Firefox port, phase 2)
- cross-browser
apishim for chrome.* (Firefox port, phase 1) - split vault context into state + actions; share prefs provider
- centralized reusable Toast (success/error/info)
- rename packages/crypto-wasm to packages/core-rust
- resolve the Keychain team prefix at runtime
- dedupe shared autofill identifiers + tidy native plugins
- SwiftUI autofill UI styled from the app design tokens
- share the wasm->CryptoAdapter mapping via buildCryptoAdapter (mobile + offscreen) + unit test
- hoist VaultCrypto type to @core/wasm; split mobile vault-session lifecycle off the crypto adapter
- extract EntriesBlobStore as the one entries-format writer; build VaultSyncPort over it
- move pure P2P transport/host modules from extension to core
- rename manifests/chrome dir to chromium for accurate cross-browser naming
- move content-only detection into content/
- rename folder entry index.ts to match its folder name
- move entries into background/ and content/, point vite at them
- decompose content-script into concern modules under content/
- split background into concern modules under background/
- replace onMessage if-chain with a typed handler registry
- extract card-brand and ssh key-type helpers to util
- lean on tanstack router for route guards + ui fixes
Documentation
- the bundling gap is closed
- record the browser link, and that pairing needs signing
- design extension unlock delegation as operation delegation
- write out the extension pairing's security model
- bring the port plan up to what was actually built
- plan the Tauri 2 desktop app
- record the versions carrying the xm22 transport fix
- rewrite the GHSA-xm22 audit as a record, not a plan
- publish the GHSA-xm22 transport audit
- keep the contributed single-pass field-inventory plan
- release notes for the bulk-selection work, and translate them
- name why browser passkeys fail, and allow-list Vivaldi
- cover the portable vault, and correct what .bramble now means
- release notes for the next build, and translate them
- say plainly how long a superseded password is kept
- map every reason a passkey is skipped on import
- release notes for 1.5.0, and translate them
- export verified on device, including a passkey sign-in
- mark phase 3 done, phase 4 is the device pass
- fold the phase 1 result back into the plan
- plan credential exchange on iOS, with the wire-format probe
- record the versions carrying the pairing fix
- release notes for 1.4.3
- add CONTRIBUTING.md with the contribution requirements
- add Matrix chat badge
- rewrite the 1.4.2 store copy and re-translate
- record the mobile hardening for issue #27
- note the AutoFill unlock fix in the release notes
- trim the release notes to what's actually new
- note the one-time-code AutoFill in the release notes
- retarget recipe to 0.9.1, enable reproducible builds
- add device-sync (P2P mesh) section to the support page
- privacy reflects backups + passkeys; clean /support + /privacy
- release notes for multi-vault + device sync since 1.2.0
- record the no-registry migration convergence guard
- refresh the gallery, add six new shots
- device-verification status (2026-07-18)
- record the phase-1 ship date + a phase-2 flip checklist
- reconcile status after biometric/autofill/join/restore work
- correct the stale perVaultSync comment (mobile now targets the active vault)
- mobile Tier 1 core landed (active-vault + per-vault sync)
- Firefox multi-vault is done, not pending (survey + user testing)
- add mobile multi-vault Tier 1 to the backlog
- record the setup-shell UX (create/restore/join tabs)
- record host-side enrolled-roster fix for Firefox inviter
- Settings join removed (follow-up done)
- mark join-from-setup landed; note the Settings-join follow-up
- mark per-vault VEK landed; call out join=add-a-vault as the next gap
- per-vault VEK design (supersedes single-VEK + primary vault)
- record the sync-panel stopgap ahead of increment 3
- note picker cards + context-aware setup screen
- mark multiple-vaults phase 1 complete (create + picker + management)
- mark multiple-vaults phase 1 create + picker landed
- mark multiple-vaults phase 0 complete; clarify migration staging vs release cadence
- plan for multiple vaults
- add Bitcoin donations (Lightning + on-chain), 3-col table
- cloud backups shipped (Dropbox + S3 + WebDAV)
- record the MEGA + Proton Drive evaluations (both deferred)
- Dropbox OAuth verified on Chromium + Firefox
- refresh roadmap to cloud backups + multiple vaults
- record the built revocation/admission state + this session's decisions
- add admin-authority (server-free) re-admit variant to revocation note
- mark B2 pending Android device testing; flag IronFox/Vanadium
- note the CRYPTO_* router path A3 gate found during implementation
- add sec-audit-7726 recheck+fix plan with execution risks
- design note for roster signing and group-key rotation
- add iOS App Store link
- tighten the cloud-like convenience bullet to match the others
- add cloud-storage-backups design note
- backups section and cloud-manager updates
- add a Screenshots section (thumbnail grid)
- add app screenshots
- add Chrome Web Store listing copy (en + translations)
- rename kdbx-import.md -> encrypted-import.md; add Bitwarden section
- correct the durability note
- add the encrypted-export feature to the Firefox listing
- reflect chrome.storage.local backend; drop false claims
- reflect the chrome.storage.local vault backend (FSA retired)
- correct conflict-loser section to match code (loser dropped, history unbuilt)
- Firefox ships listed on AMO (release-signing + firefox-port)
- current state (passkey verified, i18n done); export/import is what's left
- add Status section + specifics for passkey provider & security-key unlock
- mark relay-forward hardening implemented (timeout, reaper, epoch room, padding)
- decide relay-forward transport + privacy hardening
- correct the WebRTC-in-event-page assumption (RTCPeerConnection absent in FF background)
- fix Vivaldi typo; move file attachments + iframe/shadow-DOM autofill to shipped
- broaden README to mobile + passkeys, add passkeys to iOS store metadata
- correct passkey + P2P sync findings
- Android provider built (assertion + registration), compile-verified
- Android dep check — androidx.credentials is Play-Services-free
- mark iOS provider device-verified (register + sign-in on webauthn.io)
- document the seamless-create refinements (foreground drain + immediate-use bridge)
- mark iOS provider built (assertion + registration + handoff)
- record the device-verified registration-response field set
- spec item edit (passkey row below TOTP + remove) and view badge
- update phased route with shipped status
- plan passkey-provider role across extension + mobile
- native iOS WebRTC sync, ipa slimming, Android autofill done
- mark TURN, configurable relays, and device management as built
- update privacy policy for iOS app + P2P sync
- add Bramble support page + set App Store privacy/support URLs
- record build 204423099 (iOS autofill filtering + QuickType opt-in)
- iOS autofill working on device; refresh status + next steps
- refresh 'Next steps' handoff after autofill confirmation
- autofill confirmed end-to-end on real hardware (TestFlight)
- autofill probe confirmed on real device (OS discovers the provider)
- iOS Lockdown Mode disables JIT -> WASM crypto fails on device
- add a consolidated 'Next steps (where to resume)' section
- record iOS verification, security-key hiding, mobile test harness
- record biometric unlock (OS-gated) in port plan + dev guide
- bring mobile-port.md up to date with what's built (status, plan markers, answered questions)
- TODO for device management UI + revocation
- add development guide + sim:reset script
- add README with run instructions and live-reload gotcha
- switch mobile-port plan from Tauri to Capacitor
- add security policy and point README to it
- note Firefox storage.local durability (unlimitedStorage, uninstall, eviction)
- add P2P device-to-device vault sync design
- add Firefox-port feasibility findings
- disclose the optional HIBP breach check; tighten wording
- collapse to a single unstyled privacy-policy page
- add static site to host the Web Store privacy policy
- add design docs and function docblocks
- PLAN — multi-URL logins and the legacy-url normalizer
Other
- build(android): build releases on macOS, drop the F-Droid container
- build(desktop): build universal everywhere, not just for a release
- test(desktop): give the desktop tests room for the first import
- build(desktop): release universal by default
- test(desktop): make the update smoke server usable in practice
- build(desktop): skip notarization for the local update test build
- build(desktop): cut releases with
pnpm release desktop <version> - test(desktop): serve a fake update locally to exercise the update path
- build(desktop): notarize with the App Store Connect key iOS already uses
- build(desktop): unlock the updater key with the YubiKey, like every other release key
- chore(i18n): translate the desktop strings and restore catalog ordering
- chore(desktop): take the signing identity from .env.local
- chore(desktop): add run:desktop, and sign build:desktop by default
- test(desktop): cover the reconnect path, and add an extension stand-in
- test(desktop): cover the storage layer, and make it testable
- test(autofill): cover nesting, scrolling and COEP for the relayed picker
- chore(deps): patch the nanoid zero-size loop advisory
- chore(deps): patch the js-yaml omap CPU advisory
- test(sync): bound flushUntil in real time so it survives a loaded machine
- test(e2e): move the transport-race gate under e2e/extension
- test(e2e): record four more login shapes, and make the recorder headed
- chore(e2e): add --skip to the HAR recorder, and measure the size tradeoff
- test(e2e): replay skanetrafiken from a HAR to verify capture on the real app
- chore(deps): patch undici, brace-expansion, and fast-uri advisories
- chore(git): ignore docs/private for pre-disclosure security notes
- test(sync): stop one test paying the module-load cost for the whole file
- test(export): cover the .bramble round trip end to end, and fix the id collision it found
- build(release): let android signing be retried without rebuilding
- test(e2e): import the kdbx round-trip into a second vault
- style(sync): cut the comment blobs down to one-liners
- test(extension): pin the duplicated html escaper against its original
- test: share the vault mount harness and the chrome storage-area fake
- test(fixtures): a Bitwarden export with passkeys, for manual import testing
- Revert "chore(ios): temporary diagnostics for the passkey bundle handoff"
- chore: delete dead code found in a repo-wide sweep
- chore(ios): read the provider diagnostic on-device, no Mac needed
- chore(ios): temporary diagnostics for the passkey bundle handoff
- test(autofill): cover the picker's iframe renderer end to end
- chore: remove Codeberg links from the website and About screen
- ci: run the extension e2e suite, opt-in per PR via an
e2elabel - test(android): pair the extension with the shipped app on a real device
- test(sync): assert the joiner can read the inviter's data, not just pair
- test(sync): pair the extension and the mobile app over a real relay
- test(android): drive the shipped app on-device over CDP via adb
- test(mobile): integration-test the issue #27 corruption with real crypto
- test(e2e): cover KDBX export through the real extension
- test(import): flesh out the CSV import fixtures
- chore(website): drop dead parentHandler state from the Starwind Tabs handler
- i18n(extension): translate the suggestion strings, fix + gate the tooling
- chore(fdroid): install rustup from Debian apt (maintainer request)
- chore(fdroid): AuthorName flythenimbus
- chore(fdroid): retarget recipe to 0.9.5
- chore(fdroid): retarget recipe to 0.9.4 (commit as full hash)
- build(fdroid): reproducible Android build container matching F-Droid
- chore(fdroid): retarget recipe to 0.9.3
- chore(fdroid): retarget recipe to 0.9.2
- chore(ios): point App Store privacy/support URLs at bramble.sh
- ci(website): deploy to Cloudflare Pages via wrangler + API token
- ci(website): deploy to Cloudflare Pages instead of GitHub Actions
- chore(scripts): dev runs chrome + firefox + website together
- chore(docs): new fable security audit
- chore(website): add CNAME for the bramble.sh custom domain
- test(e2e): picker refreshes after unlock without refocusing (#20)
- test(e2e): guard lock-pref persistence across a browser restart
- test(vaults): pin the createVault sync-reset guard; retire the stale "still open" note
- test(e2e): end-to-end namespacing-migration test; fix stale registry after lazy migration
- chore(ext): add a Firefox dev watch (dev:firefox)
- a11y(ui): raise the vault-name contrast to text-foreground/70
- test(e2e): per-vault sync isolation (tier 2, increment 4)
- test(e2e): create + lock + unlock vault flow (tier 2, increment 3)
- test(e2e): playwright setup + extension loading (tier 2, increments 1-2)
- test(vault): per-vault sync unit coverage (tier 0)
- docs+feat(sync): phase 2 design + per-vault sync-key helper
- chore(i18n): vault-name + delete-reauth strings
- chore(i18n): current-vault settings strings
- chore(i18n): 'Created on {0}' string
- chore(i18n): extract + translate add-a-vault / picker strings
- chore(i18n): extract + translate vault management strings
- chore(i18n): translate vault picker strings (de, es, fr, it, pt-BR)
- chore(i18n): extract + compile vault picker strings
- chore(readme): remove status section
- chore(ios): App Store release notes for this update
- chore(i18n): translate "lock on screen lock" settings strings
- build(chromium): pin the CWS public key for a stable unpacked ID
- chore: local nextcloud compose for backup testing
- ci(codeql): advanced setup so Swift gets scanned
- chore(ios): update App Store release notes for the Face ID + P2P hardening update
- chore(mobile): link @capacitor/share into the native projects (cap sync)
- chore(i18n): translate the 3 device-authorization strings (de/es/fr/it/pt-BR)
- test(sync): grow screenshot seed to 1100 items for large-vault repro
- chore(ios): bump marketing version to 1.1.0
- chore(scripts): per-platform mobile version bump (bump:ios / bump:android)
- style(sync): move signOwnEntry helper below the import block
- ci: name the job 'CI' so branch protection can require it
- test: cover the legacy FSA->local migration and vault export
- i18n(store): Firefox listing translations (de hand-polished, es/fr/it/pt-BR first pass)
- i18n: translate the content-script UI via _locales + browser.i18n
- i18n: translate the 12 missing vault-list strings (de/es/fr/it/pt-BR)
- polish(ext): explain what unlocking is for on the locked passkey card
- polish(ext): passkey rows act on click; chevron instead of checkmark
- polish(ext): passkey card — Bramble glyph, account list, gradient bg
- polish(ext): passkey corner card gets a key-glyph badge in the header
- chore: reconcile pnpm-lock after rebase onto main
- build(release): firefox bundle + AMO-signed .xpi release pipeline
- harden(sync): epoch-rotating sync room so the relay can't link a group across time
- harden(sync): reap stale relay peers (liveness for the connectionless transport)
- harden(sync): relay-forward handshake timeout + payload size padding
- chore(ext): remove throwaway FF WebRTC-context probes + sync-frame iframe
- chore(ext): probe content-script + page-main-world WebRTC contexts (Firefox)
- chore(ext): surface an RTCPeerConnection probe in the Device-sync panel (Firefox diag)
- build(ext): output Chromium build to dist-chromium (symmetry with dist-firefox)
- chore(ext): rename build/bundle -> build:chromium/bundle:chromium
- build(ext): Firefox manifest + TARGET build wiring (Firefox port, phase 3)
- chore(ios): make app iPhone-only (drops 13-inch iPad screenshot requirement)
- chore(ios/metadata): add 7th App Store screenshot, reorder to sequence
- i18n(extension): localize manifest description + lock command via Chrome _locales
- chore(i18n): translate passkey strings (web catalogs + iOS String Catalog)
- test(extension): cover the passkey ceremony flow (incl. the account picker)
- i18n(passkeys): extract + compile the passkey provider setting strings
- chore(ios): add App Store screenshots (en-US, 6.5")
- test(core-rust): serialize the global-VEK-slot round-trip tests
- build(ios): drop webrtc from the autofill extension binary
- chore(settings): hide debug sync status log
- chore(mobile): set App Store category to Productivity / Utilities
- chore(mobile): manage App Review info in ASC, not fastlane
- chore(mobile): optimize App Store subtitle + keywords (no title overlap)
- chore(mobile): scaffold App Store Connect metadata (en-US) + deliver lane
- chore: update .gitignore to ignore app bundles
- chore(mobile): commit shared Xcode schemes, gitignore android .idea
- chore(mobile): fastlane lanes for iOS TestFlight + IPA builds
- chore(mobile): declare ITSAppUsesNonExemptEncryption=false
- test: stand up mobile test harness + cover biometric paths
- style(mobile): inset setup pills from edges + black active border
- style(mobile): full-width, larger Create vault button
- style(mobile): wider pill gap + thicker active border on setup tabs
- chore(mobile): auto-target newest iPhone sim for cap run (skip picker)
- chore(mobile): make dev:* the live-reload scripts, bundled run under run:*
- chore(mobile): rename mobile:build script to core:build
- chore(mobile): add live-reload dev scripts
- build(mobile): commit generated iOS + Android native projects
- test: migrate DOM test environment from happy-dom to jsdom
- build(deps): bump esbuild, ws, wrangler for security advisories
- ci: set least-privilege GITHUB_TOKEN permissions
- chore(lint): migrate biome config to 2.5.0 and apply safe fixes
- build: block commits/releases on type errors (pre-commit + release gate)
- chore(build): migrate from bun to node/pnpm
- chore(dev): local/CI lint parity hook + bump to Node 24 LTS
- add web store link
- chore(fixtures): repassword kdbx imports to 123456, add keyfile variant, fix key-file label spacing
- chore: add tag:delete script to remove a tag locally and from all remotes
- chore(biome): exclude import fixtures folder
- test(fixtures): add sample import files for every supported provider
- release: set extension version to 1.0 for the initial Web Store submission
- build(ext): add 'bundle' script (build + zip dist to bramble.zip)
- ci: deploy only website/ to GitHub Pages via Actions
- style(manifest): biome-format permissions array (one line after activeTab drop)
- chore(manifest): drop redundant activeTab, add use_dynamic_url to WAR
- test(crypto): add an ignored benchmark for the vault Argon2id cost
- test(bg): move the chrome-mock harness to src/test/
- test(bg): add handler unit tests for the background modules (73 tests)
- update readme
- ci: exclude vendored icon/ export from biome
- add monero qr code image
- style: biome format fixes for ci
- recovery codes, optional master password, and settings cleanup
- test: extract detection helpers, add 10 real-world site fixtures, fix bmo card-vs-login bug
- ci: pin wasm-pack version and cache cargo deps between runs
- ci: pin Rust to rust-toolchain.toml and add a WASM verify gate
- brand: rename app to Bramble
- chore: centralize the user-facing brand on the manifest, swap Vault→Titanpass
- ui: show real extension version in Settings (was hardcoded 0.0.1)
- security: make HIBP breach check opt-in, with a clearer disclosure (L6)
- security: stop persisting the decrypted autofill index (M2)
- security: gate every autofill on user focus, never on page load (M1)
- chore: prune unused shadcn/Radix UI scaffold and supporting deps (M6b)
- data-integrity: snapshot-and-recover writes + verify-after-rotate (H1, H2)
- security: quick-wins audit batch (M3, M4, M5, M6a, L2, L3, L4, L5, L7)
- move to multi-key vault slots, full rotation on password change
- wire settings, clipboard auto-clear, hibp checks, per-entry overrides
- add crud elements and manage window size
- update plan
- implement autofill in website fields
- implement vault crypto, vault creation and loading
- set up fe arch: screens, router, rhf
- wire up ui
- initial commit