Profile Use
Use a private profile as the source of truth for repetitive registration and checkout fields. The skill helps map form labels to profile fields, fill only what is needed, and keep sensitive values out of chat, logs, screenshots, repos, and PRs.
Privacy Rules
- Never invent personal data. If a field is missing, ask the user or leave it blank.
- Do not store real personal data in the skill repo, memory, issue trackers, PRs, screenshots, or final responses.
- Use redacted summaries by default. Reveal full values only when the user explicitly asks and the current task requires it.
- Treat payment cards, bank accounts, government IDs, tax IDs, passwords, security answers, and medical fields as high sensitivity. Ask for explicit confirmation before entering or revealing them.
- Do not submit a registration, KYC, checkout, banking, or payment form until the user explicitly approves the final submit action.
- If browser automation is used, verify the real domain and purpose before filling. Stop on suspicious, unrelated, or typosquatted domains.
Profile Source
Prefer the helper script:
python3 scripts/profile_use.py path
python3 scripts/profile_use.py doctor
python3 scripts/profile_use.py init --profile personal
python3 scripts/profile_use.py show --profile personal
python3 scripts/profile_use.py values --profile personal
python3 scripts/profile_use.py values --profile personal contact.email address.postal_code
python3 scripts/profile_use.py get --profile personal contact.email address.postal_code
python3 scripts/profile_use.py set --profile personal address.postal_code "1000001"
python3 scripts/profile_use.py list-fields --profile personal --filled
Redacted vs. raw: pick the right command
This is the most important rule for autofill. Two output modes exist and they are not interchangeable:
values returns RAW values. Use it for every value you actually type into a form. With no fields it dumps all filled low/medium fields as a flat {dotpath: value} map ready to map onto form labels; it excludes high-sensitivity fields unless you name them or pass --include-sensitive.
show / get return REDACTED values by default (names, email, phone, address lines, card, bank, IDs, notes are masked). Use these only to orient or to report back to the user. Pass --reveal to unmask.
NEVER type a redacted/masked value into a form. get contact.email returns t***@example.com; filling that breaks the registration. To fill, use values contact.email (or get --reveal). When in doubt for filling: use values.
Default location order:
$PROFILE_USE_DIR (legacy $PERSONAL_AUTOFILL_DIR is still honored)
$HOME/Library/Mobile Documents/com~apple~CloudDocs/Agent Profiles/profile-use
$HOME/.config/profile-use
A pre-rename personal-autofill directory that still holds data is used as a fallback when the profile-use directory does not exist yet.
The iCloud rule checks the iCloud Drive root (com~apple~CloudDocs) and creates Agent Profiles/profile-use on first write. Use doctor when a profile unexpectedly lands in .config.
Use references/profile-template.json for the editable shape. Use references/profile-schema.json for field names and sensitivity hints.
Growing The Profile
Expect the profile to grow over time as real registrations reveal new fields. When a form asks for information that is not already in the profile:
- Ask the user for the value only if it is required for the current registration.
- Decide whether it is reusable. Save stable values such as alternate emails, shipping addresses, invoice names, furigana, company details, and country-specific address variants. Do not save one-time codes, session tokens, CAPTCHA text, temporary invitation links, or site passwords.
- Ask before writing high-sensitivity or newly invented field paths.
- Add the field with
set:
python3 scripts/profile_use.py set --profile personal identity.name_kana "..."
python3 scripts/profile_use.py set --profile personal address.jp.prefecture "..."
python3 scripts/profile_use.py set --profile personal preferences.newsletter_opt_in false --json
- Confirm with redacted reads:
python3 scripts/profile_use.py get --profile personal identity.name_kana address.jp.prefecture
Use flexible nested paths when a country, site, or tenant needs a special variant. Examples: address.jp.*, address.us.*, contact.work_email, invoice.jp.qualified_invoice_name.
Proactive Capture (offer to record, don't wait for a form)
Profile growth is not limited to autofill. During any task — answering a tax question, reading a chat, helping with onboarding paperwork — durable personal facts surface that the user will likely need again. When that happens, proactively offer to record them, then write only after the user agrees:
- Notice the fact is stable and reusable, not one-time. Good: family members' birthdates / relationships, dependent and tax-residency status, employer / salary structure, an HR- or authority-confirmed requirement (what document is needed, who handles it), a recurring address or invoice variant. Skip: one-time codes, transient amounts, session/case context that won't recur.
- Ask before writing. Say what you'd save and the dotpath (e.g. "记进
family.father.birthdate / tax.jp.dependents.*?"). Get a yes first; never silently persist. The exception is when the user already said "record this" / "记一下" — then write and report.
- Pick a sensible path under an existing section before inventing a new top-level one; flexible nested paths are fine (
family.*, tax.jp.dependents.*). Treat new high-sensitivity paths and any payment/bank/government_id/tax/birthdate value as confirmation-gated even when the user broadly agreed to "record stuff".
- After writing, confirm with a redacted
list-fields --filled / get, and report the dotpath — not the raw value — back to the user.
Keep all other rules in force: redaction by default, nothing high-sensitivity revealed in the final response, and the profile JSON stays the store of record (not chat, memory, or Git).
Fill Workflow
- Identify the form's site, purpose, and profile to use. Default to
personal unless the user names another profile such as work, family, or jp.
- Inspect the form labels and required fields. Build a mapping from labels to profile paths; do not rely only on placeholder text.
- Orient with redacted
show to see the shape, then read the exact values you will type with values (raw). Use values with no fields to get a flat map of all filled low/medium fields at once.
- Fill low-sensitivity fields directly when the user asked for autofill, using the raw
values output. Examples: name, email, phone, postal code, address.country / address.region / address.city.
- For high-sensitivity fields (
payment, bank, government_id, tax, birthdate, gender, and the street-address lines address.line1 / address.line2), show a redacted summary and ask for confirmation before filling; fetch the raw value with an explicit values address.line1 (or values payment.card.number) only at the moment of filling. These are excluded from the no-field values dump, so you must name them.
- Before submission, summarize the fields that were filled using redacted
show/get values and wait for an explicit submit approval.
Field Mapping Hints
identity.full_name: full legal name or display name, depending on the form.
identity.family_name, identity.given_name: split-name fields.
contact.email, contact.phone, contact.phone_country_code: email and telephone fields.
address.country, address.region, address.city, address.postal_code: address fields (low sensitivity). address.line1, address.line2: the precise street address — high sensitivity, masked in show and excluded from the no-field values dump.
payment.card.*: card fields; always high sensitivity.
bank.*: bank transfer or withdrawal fields; always high sensitivity.
government_id.*, tax.*: identity verification fields; always high sensitivity.
preferences.*: marketing opt-in, locale, newsletter, and delivery preferences.
invoice.*: billing name, tax invoice name, receipt name, or business invoice details.
site_overrides.<domain>.*: a value required only by one service; use this sparingly.
If a site has country-specific formatting rules, preserve the profile value unless the form rejects it. Normalize only after checking the visible validation message.
Output formats for values
Two flags on values, for the two conversions agents kept doing by hand at
fill time:
--phone-format domestic|e164 — contact.phone as the trunk-prefixed
national number (07012345678) or E.164 (+817012345678). Only applies when
contact.phone_country_code is on file; without it there is no honest way to
tell +81 70 from a national 070, so the value is returned as stored.
--format jp-fullwidth — ASCII digits, letters and hyphens in every returned
string as full-width (201-0001 → 201-0001, 25番57-402号 →
25番57-402号) for Japanese forms that reject half-width input. Kana
and kanji are untouched.
python3 scripts/profile_use.py values contact.phone --phone-format domestic
python3 scripts/profile_use.py values address.jp.kana_remainder --format jp-fullwidth
Conventional paths for recurring cases
The schema is free-form nested paths, so any of these can be stored today without
a code change. Use these exact paths anyway. The failure mode is not "the field
cannot be stored" — it is that each agent invents its own path (payment.hk_bank
one week, bank.hk the next), and the next agent cannot find what the last one
saved. Converging matters more than the names being perfect.
Names as printed on an ID. Residence cards, passports and driver's licences
print a romanised name whose order may not match identity.family_name /
identity.given_name. Japanese forms routinely want that exact string in the
漢字 slot plus a separate kana line.
identity.romaji.family_name, identity.romaji.given_name
identity.name_on_id: the name exactly as printed, including its order
identity.kana.family_name, identity.kana.given_name
Japanese structured address. Forms auto-fill 都道府県/市区町村/町域 from the
郵便番号 and then want only the remainder, "as written on the ID", in full-width
digits — which cannot be re-derived reliably from address.line1 / line2.
address.jp.{prefecture,city,town,chome,banchi,go,building,room}
address.jp.postal_code_hyphenated (201-0001)
address.jp.kana_remainder
Document metadata. eKYC flows reject cards by issue date and need the card
number for the IC read, so this saves reopening the image every time. All three
are high sensitivity.
documents.<doc>.{number,issued_on,expires_on} (ISO dates)
documents.<doc>.proves: list of what the document evidences, e.g.
[name] for 在留カード表面 and [address] for 裏面. Lets an agent pick the
right file for "one document proving name, one proving address" instead of
guessing from the label.
Bank and payout accounts. Use an array so multiple accounts coexist; always
high sensitivity.
bank.accounts[].{bank_name,account_name,account_number,branch_code,swift,clearing_code,currency,country,label}
Prefer bank.* over a new top-level section — the redaction rules and the
confirmation gate already key off that prefix.
Original Document Images (Attachments)
Some forms need the original image, not extracted text: residence card photos for KYC, bank card photos for payroll, My Number card scans. Keep these originals next to the profile so they sync with it and survive temp-file cleanup:
python3 scripts/profile_use.py attach /tmp/dl/img1.jpg --doc residence_card_front --label "在留カード 表面" --source "lark chat 2026-06-12" --move
python3 scripts/profile_use.py attachments --profile personal
python3 scripts/profile_use.py attachment-path --doc residence_card_front
python3 scripts/profile_use.py detach --doc residence_card_front
Files land in <profile-dir>/attachments/<profile>/<doc>.<ext> with mode 600; metadata (file, label, source, added date, sha256) is recorded under documents.<doc> in the profile JSON. This metadata is treated as high sensitivity — masked in show/get and excluded from the no-field values dump — because label/source often carry context (counterparty names, dates) you don't want in a redacted summary.
Conventional doc keys: residence_card_front, residence_card_back, my_number_card_front, my_number_card_back, bank_card, passport_photo_page, health_insurance_card, drivers_license_front. Free-form keys are fine (lowercase letters, digits, _, -, .).
Rules for originals:
- When a document image appears in a chat download or temp directory and is worth keeping,
attach --move it immediately, then delete any remaining temp copies. Do not leave ID images in /tmp, downloads, or the repo.
- Treat every attachment as high sensitivity. Uploading an attachment to a website requires the user's explicit confirmation for that specific upload, even if autofill of text fields was already approved.
- Use
attachment-path to get the file path for an upload widget; never re-screenshot or copy the image elsewhere.
- Do not attach one-time documents (CAPTCHAs, QR codes, temporary passes). Attach stable identity/payment documents only.
- Expired or surrendered documents:
detach them, or replace with attach --force when a renewed card arrives.
Login Credentials (Bitwarden / Vaultwarden)
Account passwords do not live in the profile JSON. They stay in the user's password manager and are read live through rbw (a Bitwarden-compatible CLI that also talks to self-hosted Vaultwarden). The skill reads one credential at the moment of fill and never copies it into the profile, memory, logs, or chat.
Setup is agent-driven — the user only types the master password
Do not hand the user a list of shell commands. When a credential is needed, the agent runs setup itself and stops only at the one step it must never perform (the master-password unlock).
Run vault-status. If rbw_installed is false or unlocked is false, set it up — don't ask the user to.
Install + configure in one command (the agent runs this):
python3 scripts/profile_use.py vault-setup --install --base-url <server-url> --email <account-email>
--install installs rbw via brew/cargo if missing. Get the server URL from the user (or a value they gave earlier, e.g. https://bit.leeguoo.com) and the email from contact.email if present; ask only for whatever is genuinely unknown.
vault-setup reports next_step. If it says to run rbw login, ask the user to run that one command themselves (in the ! prompt or their terminal) and type their master password. The agent never asks for, runs with, captures, or echoes the master password. Once rbw-agent holds the unlock, every later login call just works.
After setup, use:
python3 scripts/profile_use.py vault-status # rbw installed? server? unlocked? (no secrets)
python3 scripts/profile_use.py login --domain example.com # redacted: user t***@x.com / password ********
python3 scripts/profile_use.py login --domain example.com --reveal # raw user + password — only at the moment of filling
python3 scripts/profile_use.py login --name "GitHub" --user me@x.com # target an item directly / pick one account
python3 scripts/profile_use.py login --domain example.com --deep # no name match? scan stored URIs (slower)
Matching is by domain: the form's host (e.g. example.com) is matched against vault item names, including the bare second-level label (example). When several items match, the command lists masked candidates and asks you to disambiguate with --name/--user — it does not fetch any password until exactly one item is chosen.
Rules for credentials:
- Treat every credential as high sensitivity, like
payment/bank. Default to the redacted output; fetch --reveal only at the instant you fill the field, and never paste the raw password into a final response.
- Do not store, cache, or write credentials anywhere — not the profile JSON, not memory, not a temp file. Re-read from the vault each time.
- The vault unlock belongs to
rbw-agent. Never ask for, capture, store, or echo the master password. If vault-status shows unlocked: false, ask the user to run rbw unlock themselves.
- Verify the real domain before filling a password, exactly as for any autofill. Stop on suspicious or typosquatted hosts.
- Submitting a login/registration form still requires the user's explicit submit approval.
Sync Guidance
Read references/sync-model.md when choosing or explaining where profile data should live.
Default recommendation:
- Use iCloud Drive for a single user's private plaintext profile on Apple devices.
- Use a password manager for payment cards, bank accounts, passwords, and one-time codes.
- Use GitHub only for the public skill code, profile schema, examples, or encrypted profile backups. Never put plaintext personal data in a public repository.
Output Rules
- Final answers should say what was filled and what remains, using redacted values.
- Do not paste full card numbers, bank accounts, government IDs, or addresses into final responses unless the user explicitly asked to display them.
- If a profile file was created, report its local path and remind the user it contains placeholders until they edit it.
1---2name: profile-use-23description: Safely use a user's private local personal profile to help fill registration, signup, checkout, banking, KYC, and onboarding forms. Use when the user asks to enter or reuse identity details such as name, address, phone, postal code, email, birthdate, payment card, bank account, tax ID, or other personal data. Prioritize privacy, redaction, consent before submission, and local/iCloud/encrypted profile sources rather than storing personal data in chat or Git.4---56# Profile Use78Use a private profile as the source of truth for repetitive registration and checkout fields. The skill helps map form labels to profile fields, fill only what is needed, and keep sensitive values out of chat, logs, screenshots, repos, and PRs.910## Privacy Rules11121. Never invent personal data. If a field is missing, ask the user or leave it blank.132. Do not store real personal data in the skill repo, memory, issue trackers, PRs, screenshots, or final responses.143. Use redacted summaries by default. Reveal full values only when the user explicitly asks and the current task requires it.154. Treat payment cards, bank accounts, government IDs, tax IDs, passwords, security answers, and medical fields as high sensitivity. Ask for explicit confirmation before entering or revealing them.165. Do not submit a registration, KYC, checkout, banking, or payment form until the user explicitly approves the final submit action.176. If browser automation is used, verify the real domain and purpose before filling. Stop on suspicious, unrelated, or typosquatted domains.1819## Profile Source2021Prefer the helper script:2223```bash24python3 scripts/profile_use.py path25python3 scripts/profile_use.py doctor26python3 scripts/profile_use.py init --profile personal27python3 scripts/profile_use.py show --profile personal28python3 scripts/profile_use.py values --profile personal29python3 scripts/profile_use.py values --profile personal contact.email address.postal_code30python3 scripts/profile_use.py get --profile personal contact.email address.postal_code31python3 scripts/profile_use.py set --profile personal address.postal_code "1000001"32python3 scripts/profile_use.py list-fields --profile personal --filled33```3435### Redacted vs. raw: pick the right command3637This is the most important rule for autofill. Two output modes exist and they are not interchangeable:3839- **`values`** returns RAW values. Use it for every value you actually type into a form. With no fields it dumps all filled low/medium fields as a flat `{dotpath: value}` map ready to map onto form labels; it excludes high-sensitivity fields unless you name them or pass `--include-sensitive`.40- **`show` / `get`** return REDACTED values by default (names, email, phone, address lines, card, bank, IDs, notes are masked). Use these only to orient or to report back to the user. Pass `--reveal` to unmask.4142NEVER type a redacted/masked value into a form. `get contact.email` returns `t***@example.com`; filling that breaks the registration. To fill, use `values contact.email` (or `get --reveal`). When in doubt for filling: use `values`.4344Default location order:45461. `$PROFILE_USE_DIR` (legacy `$PERSONAL_AUTOFILL_DIR` is still honored)472. `$HOME/Library/Mobile Documents/com~apple~CloudDocs/Agent Profiles/profile-use`483. `$HOME/.config/profile-use`4950A pre-rename `personal-autofill` directory that still holds data is used as a fallback when the `profile-use` directory does not exist yet.5152The iCloud rule checks the iCloud Drive root (`com~apple~CloudDocs`) and creates `Agent Profiles/profile-use` on first write. Use `doctor` when a profile unexpectedly lands in `.config`.5354Use `references/profile-template.json` for the editable shape. Use `references/profile-schema.json` for field names and sensitivity hints.5556## Growing The Profile5758Expect the profile to grow over time as real registrations reveal new fields. When a form asks for information that is not already in the profile:59601. Ask the user for the value only if it is required for the current registration.612. Decide whether it is reusable. Save stable values such as alternate emails, shipping addresses, invoice names, furigana, company details, and country-specific address variants. Do not save one-time codes, session tokens, CAPTCHA text, temporary invitation links, or site passwords.623. Ask before writing high-sensitivity or newly invented field paths.634. Add the field with `set`:6465```bash66python3 scripts/profile_use.py set --profile personal identity.name_kana "..."67python3 scripts/profile_use.py set --profile personal address.jp.prefecture "..."68python3 scripts/profile_use.py set --profile personal preferences.newsletter_opt_in false --json69```70715. Confirm with redacted reads:7273```bash74python3 scripts/profile_use.py get --profile personal identity.name_kana address.jp.prefecture75```7677Use flexible nested paths when a country, site, or tenant needs a special variant. Examples: `address.jp.*`, `address.us.*`, `contact.work_email`, `invoice.jp.qualified_invoice_name`.7879### Proactive Capture (offer to record, don't wait for a form)8081Profile growth is not limited to autofill. During **any** task — answering a tax question, reading a chat, helping with onboarding paperwork — durable personal facts surface that the user will likely need again. When that happens, **proactively offer to record them**, then write only after the user agrees:82831. Notice the fact is **stable and reusable**, not one-time. Good: family members' birthdates / relationships, dependent and tax-residency status, employer / salary structure, an HR- or authority-confirmed requirement (what document is needed, who handles it), a recurring address or invoice variant. Skip: one-time codes, transient amounts, session/case context that won't recur.842. **Ask before writing.** Say what you'd save and the dotpath (e.g. "记进 `family.father.birthdate` / `tax.jp.dependents.*`?"). Get a yes first; never silently persist. The exception is when the user already said "record this" / "记一下" — then write and report.853. Pick a sensible path under an existing section before inventing a new top-level one; flexible nested paths are fine (`family.*`, `tax.jp.dependents.*`). Treat new high-sensitivity paths and any `payment`/`bank`/`government_id`/`tax`/birthdate value as confirmation-gated even when the user broadly agreed to "record stuff".864. After writing, confirm with a redacted `list-fields --filled` / `get`, and report the dotpath — not the raw value — back to the user.8788Keep all other rules in force: redaction by default, nothing high-sensitivity revealed in the final response, and the profile JSON stays the store of record (not chat, memory, or Git).8990## Fill Workflow91921. Identify the form's site, purpose, and profile to use. Default to `personal` unless the user names another profile such as `work`, `family`, or `jp`.932. Inspect the form labels and required fields. Build a mapping from labels to profile paths; do not rely only on placeholder text.943. Orient with redacted `show` to see the shape, then read the exact values you will type with `values` (raw). Use `values` with no fields to get a flat map of all filled low/medium fields at once.954. Fill low-sensitivity fields directly when the user asked for autofill, using the raw `values` output. Examples: name, email, phone, postal code, `address.country` / `address.region` / `address.city`.965. For high-sensitivity fields (`payment`, `bank`, `government_id`, `tax`, birthdate, gender, and the street-address lines `address.line1` / `address.line2`), show a redacted summary and ask for confirmation before filling; fetch the raw value with an explicit `values address.line1` (or `values payment.card.number`) only at the moment of filling. These are excluded from the no-field `values` dump, so you must name them.976. Before submission, summarize the fields that were filled using redacted `show`/`get` values and wait for an explicit submit approval.9899## Field Mapping Hints100101- `identity.full_name`: full legal name or display name, depending on the form.102- `identity.family_name`, `identity.given_name`: split-name fields.103- `contact.email`, `contact.phone`, `contact.phone_country_code`: email and telephone fields.104- `address.country`, `address.region`, `address.city`, `address.postal_code`: address fields (low sensitivity). `address.line1`, `address.line2`: the precise street address — high sensitivity, masked in `show` and excluded from the no-field `values` dump.105- `payment.card.*`: card fields; always high sensitivity.106- `bank.*`: bank transfer or withdrawal fields; always high sensitivity.107- `government_id.*`, `tax.*`: identity verification fields; always high sensitivity.108- `preferences.*`: marketing opt-in, locale, newsletter, and delivery preferences.109- `invoice.*`: billing name, tax invoice name, receipt name, or business invoice details.110- `site_overrides.<domain>.*`: a value required only by one service; use this sparingly.111112If a site has country-specific formatting rules, preserve the profile value unless the form rejects it. Normalize only after checking the visible validation message.113114### Output formats for `values`115116Two flags on `values`, for the two conversions agents kept doing by hand at117fill time:118119- `--phone-format domestic|e164` — `contact.phone` as the trunk-prefixed120 national number (`07012345678`) or E.164 (`+817012345678`). Only applies when121 `contact.phone_country_code` is on file; without it there is no honest way to122 tell `+81 70` from a national `070`, so the value is returned as stored.123- `--format jp-fullwidth` — ASCII digits, letters and hyphens in every returned124 string as full-width (`201-0001` → `201-0001`, `25番57-402号` →125 `25番57-402号`) for Japanese forms that reject half-width input. Kana126 and kanji are untouched.127128```bash129python3 scripts/profile_use.py values contact.phone --phone-format domestic130python3 scripts/profile_use.py values address.jp.kana_remainder --format jp-fullwidth131```132133### Conventional paths for recurring cases134135The schema is free-form nested paths, so any of these can be stored today without136a code change. Use these exact paths anyway. The failure mode is not "the field137cannot be stored" — it is that each agent invents its own path (`payment.hk_bank`138one week, `bank.hk` the next), and the next agent cannot find what the last one139saved. Converging matters more than the names being perfect.140141**Names as printed on an ID.** Residence cards, passports and driver's licences142print a romanised name whose order may not match `identity.family_name` /143`identity.given_name`. Japanese forms routinely want that exact string in the144漢字 slot plus a separate kana line.145146- `identity.romaji.family_name`, `identity.romaji.given_name`147- `identity.name_on_id`: the name exactly as printed, including its order148- `identity.kana.family_name`, `identity.kana.given_name`149150**Japanese structured address.** Forms auto-fill 都道府県/市区町村/町域 from the151郵便番号 and then want only the remainder, "as written on the ID", in full-width152digits — which cannot be re-derived reliably from `address.line1` / `line2`.153154- `address.jp.{prefecture,city,town,chome,banchi,go,building,room}`155- `address.jp.postal_code_hyphenated` (`201-0001`)156- `address.jp.kana_remainder`157158**Document metadata.** eKYC flows reject cards by issue date and need the card159number for the IC read, so this saves reopening the image every time. All three160are high sensitivity.161162- `documents.<doc>.{number,issued_on,expires_on}` (ISO dates)163- `documents.<doc>.proves`: list of what the document evidences, e.g.164 `[name]` for 在留カード表面 and `[address]` for 裏面. Lets an agent pick the165 right file for "one document proving name, one proving address" instead of166 guessing from the label.167168**Bank and payout accounts.** Use an array so multiple accounts coexist; always169high sensitivity.170171- `bank.accounts[].{bank_name,account_name,account_number,branch_code,swift,clearing_code,currency,country,label}`172173Prefer `bank.*` over a new top-level section — the redaction rules and the174confirmation gate already key off that prefix.175176## Original Document Images (Attachments)177178Some forms need the original image, not extracted text: residence card photos for KYC, bank card photos for payroll, My Number card scans. Keep these originals next to the profile so they sync with it and survive temp-file cleanup:179180```bash181python3 scripts/profile_use.py attach /tmp/dl/img1.jpg --doc residence_card_front --label "在留カード 表面" --source "lark chat 2026-06-12" --move182python3 scripts/profile_use.py attachments --profile personal183python3 scripts/profile_use.py attachment-path --doc residence_card_front184python3 scripts/profile_use.py detach --doc residence_card_front185```186187Files land in `<profile-dir>/attachments/<profile>/<doc>.<ext>` with mode 600; metadata (file, label, source, added date, sha256) is recorded under `documents.<doc>` in the profile JSON. This metadata is treated as high sensitivity — masked in `show`/`get` and excluded from the no-field `values` dump — because `label`/`source` often carry context (counterparty names, dates) you don't want in a redacted summary.188189Conventional doc keys: `residence_card_front`, `residence_card_back`, `my_number_card_front`, `my_number_card_back`, `bank_card`, `passport_photo_page`, `health_insurance_card`, `drivers_license_front`. Free-form keys are fine (lowercase letters, digits, `_`, `-`, `.`).190191Rules for originals:1921931. When a document image appears in a chat download or temp directory and is worth keeping, `attach --move` it immediately, then delete any remaining temp copies. Do not leave ID images in `/tmp`, downloads, or the repo.1942. Treat every attachment as high sensitivity. Uploading an attachment to a website requires the user's explicit confirmation for that specific upload, even if autofill of text fields was already approved.1953. Use `attachment-path` to get the file path for an upload widget; never re-screenshot or copy the image elsewhere.1964. Do not attach one-time documents (CAPTCHAs, QR codes, temporary passes). Attach stable identity/payment documents only.1975. Expired or surrendered documents: `detach` them, or replace with `attach --force` when a renewed card arrives.198199## Login Credentials (Bitwarden / Vaultwarden)200201Account passwords do **not** live in the profile JSON. They stay in the user's password manager and are read live through `rbw` (a Bitwarden-compatible CLI that also talks to self-hosted Vaultwarden). The skill reads one credential at the moment of fill and never copies it into the profile, memory, logs, or chat.202203### Setup is agent-driven — the user only types the master password204205Do not hand the user a list of shell commands. When a credential is needed, the agent runs setup itself and stops only at the one step it must never perform (the master-password unlock).2062071. Run `vault-status`. If `rbw_installed` is false or `unlocked` is false, set it up — don't ask the user to.2082. Install + configure in one command (the agent runs this):209210 ```bash211 python3 scripts/profile_use.py vault-setup --install --base-url <server-url> --email <account-email>212 ```213214 `--install` installs rbw via brew/cargo if missing. Get the server URL from the user (or a value they gave earlier, e.g. `https://bit.leeguoo.com`) and the email from `contact.email` if present; ask only for whatever is genuinely unknown.2153. `vault-setup` reports `next_step`. If it says to run `rbw login`, ask the user to run **that one command themselves** (in the `!` prompt or their terminal) and type their master password. The agent never asks for, runs with, captures, or echoes the master password. Once `rbw-agent` holds the unlock, every later `login` call just works.216217After setup, use:218219```bash220python3 scripts/profile_use.py vault-status # rbw installed? server? unlocked? (no secrets)221python3 scripts/profile_use.py login --domain example.com # redacted: user t***@x.com / password ********222python3 scripts/profile_use.py login --domain example.com --reveal # raw user + password — only at the moment of filling223python3 scripts/profile_use.py login --name "GitHub" --user me@x.com # target an item directly / pick one account224python3 scripts/profile_use.py login --domain example.com --deep # no name match? scan stored URIs (slower)225```226227Matching is by **domain**: the form's host (e.g. `example.com`) is matched against vault item names, including the bare second-level label (`example`). When several items match, the command lists masked candidates and asks you to disambiguate with `--name`/`--user` — it does **not** fetch any password until exactly one item is chosen.228229Rules for credentials:2302311. Treat every credential as high sensitivity, like `payment`/`bank`. Default to the redacted output; fetch `--reveal` only at the instant you fill the field, and never paste the raw password into a final response.2322. Do not store, cache, or write credentials anywhere — not the profile JSON, not memory, not a temp file. Re-read from the vault each time.2333. The vault unlock belongs to `rbw-agent`. Never ask for, capture, store, or echo the master password. If `vault-status` shows `unlocked: false`, ask the user to run `rbw unlock` themselves.2344. Verify the real domain before filling a password, exactly as for any autofill. Stop on suspicious or typosquatted hosts.2355. Submitting a login/registration form still requires the user's explicit submit approval.236237## Sync Guidance238239Read `references/sync-model.md` when choosing or explaining where profile data should live.240241Default recommendation:242243- Use iCloud Drive for a single user's private plaintext profile on Apple devices.244- Use a password manager for payment cards, bank accounts, passwords, and one-time codes.245- Use GitHub only for the public skill code, profile schema, examples, or encrypted profile backups. Never put plaintext personal data in a public repository.246247## Output Rules248249- Final answers should say what was filled and what remains, using redacted values.250- Do not paste full card numbers, bank accounts, government IDs, or addresses into final responses unless the user explicitly asked to display them.251- If a profile file was created, report its local path and remind the user it contains placeholders until they edit it.