git:20260719.0107f2a to git:20260719.75534be

52 added, 29 removed. Audit A to A.

---
name: credential-manager
description: Read this before any login, signup, password change, or checkout so the right credential source is used in the right order without ever exposing a secret.
autoInject:
keywords: ["login", "log in", "sign in", "sign-in", "sign up", "signup", "password", "credential", "checkout", "payment", "2fa", "mfa"]
---
# Credential manager
- How to pick a credential source and fill a login, signup, or payment form
- without ever seeing, typing, or printing a secret.
+ Use metadata to choose an account, then let the password manager detect and
+ fill the form. Never fetch, inspect, transform, or print a stored secret.
## Source order
Work down this ladder; stop at the first source that works.
- 1. **Password-manager extension in the profile.** If the host configured one
- (the operator prompt names it, e.g. 1Password), use its inline autofill
- menu — read the matching provider pack first (`../1password/SKILL.md`,
- `../bitwarden/SKILL.md`). The extension fills the secret; you never see it.
- 2. **BetterWright vault.** `credentials.list()` shows records saved for the
- current origin (metadata only — id, username, label, category; filter with
- `credentials.list({text, category})`). When one clearly matches, fill it
- directly from `run()`: `credentials.fill({id, usernameSelector,
- passwordSelector, submitSelector})` — the worker types the secret,
- origin-scoped, and never returns it. The host-side equivalents
- (`browser_login` on MCP/Pi, `bw.fillCredential` on the SDK) do the same
- from outside.
+ 1. **A configured external manager.** If the operator prompt explicitly names
+ 1Password or Bitwarden, use its inline menu and read the matching provider
+ pack first (`../1password/SKILL.md`, `../bitwarden/SKILL.md`).
+ 2. **BetterWright's built-in vault.** `credentials.list()` returns matching
+ metadata only: id, username, label, category, saved URL, and match mode.
+ Filter with `credentials.list({text, category})`. If one account clearly
+ fits the task, call `credentials.fill({id, submit: true})`. BetterWright
+ detects the visible form and resolves/types the secret internally. MCP/Pi's
+ `browser_login` and the SDK's `fillCredential` use the same path.
3. **The page itself.** Focus the username field with `human.click` and
re-snapshot; a session may already exist, an SSO button may be present, or
the user's own password manager may surface.
4. **Ask the user** through the host's question mechanism, offering the
accounts you found as masked options (e.g. "account ending in 999"). This is
the last resort, not the first.
- ## Signup and password change
+ ## Account choice and staged login
- - Signup: call `credentials.generateAndFill({username, usernameSelector,
- passwordSelector, confirmPasswordSelector, submitSelector})` from `run()`
- (host equivalents: `browser_login` with `generate: true`, or
- `bw.generateAndFillCredential(...)` from the SDK). The password is
- generated, filled, and saved to the vault without ever being returned.
- - Password change: after the site confirms the change, update the stored
- record (`credentials.update({id, ...})`) rather than saving a duplicate.
- - Choose the username/email from records the user already uses on other
- origins when the site allows it; never invent an address.
+ - Search before filling. One clear match may be used directly. If several
+ plausible accounts remain and the task does not disambiguate them, ask with
+ usernames/labels only; never mention a secret.
+ - On a username-first flow, enter the selected record's public username and
+ advance. On the password stage call `credentials.fill({id, submit: true})`;
+ password-only pages are detected.
+ - Detection uses autocomplete/type/label/form context. If it reports multiple
+ plausible forms, scope explicit `usernameSelector`, `passwordSelector`,
+ `confirmPasswordSelector`, or `submitSelector` from a fresh snapshot. Do not
+ guess selectors before detection fails.
+ ## Signup and password rotation
+
+ 1. Call `credentials.generateAndFill({username, submit: true})`. Generation
+ returns only an opaque pending id; the encrypted provisional entry is not an
+ active saved login yet.
+ 2. Verify the site's visible success state. A clicked button or request alone
+ is not proof.
+ 3. On success, call `credentials.commitGenerated({pendingId})`. On rejection or
+ abandonment, call `credentials.discardGenerated({pendingId})`.
+
+ If generation fails but returns `pendingCredential`, do not generate again.
+ Inspect the visible site outcome, then commit or discard that exact recovery id.
+ After a complete host restart with no returned id, revisit the signup site and
+ call `credentials.listPending()`. Use its secret-free username, label, and
+ timestamps to identify the attempt; never guess or auto-pick among several.
+
+ For rotation, pass the existing credential `id` to `generateAndFill`. Commit
+ only after the site confirms the change; commit updates that item instead of
+ creating a duplicate. Rotation preserves its URL scope, so update `matchMode`
+ separately before rotating when needed. Choose an existing username/email when
+ the site allows it; never invent an address.
+
## Rules
- - An empty `credentials.list()` does not prove nothing is saved — the vault
- may be absent or locked for this host. Fall through the ladder instead of
- concluding.
+ - An empty `credentials.list()` means no enabled item matches this site under
+ its URL policy. Fall through the ladder instead of searching unrelated
+ credentials.
- Never read, print, encode, or transmit a password, card number, or one-time
- secret. Snapshots redact password inputs; keep it that way — no
- `input.value` probes on secret fields.
+ secret. Snapshots and results redact password inputs; keep it that way: no
+ `inputValue()`, `input.value`, `evaluate`, console, or network probes on
+ secret fields.
- A failed fill ("info isn't correct") means the stored secret may be stale:
try the next source on the ladder, then ask the user — never brute-force
variants.
+ - Save a task-supplied credential only when the user asks to remember it, and
+ only after the site accepts it.