proton-pass
Skill0 starsChanged 3 months agoMITView on GitHub
Read secrets from Proton Pass with the pass-cli command-line tool, and set up the agent/PAT credential that lets an automated process do it unattended. Use whenever a task needs an API key, token, password, or TOTP code that lives in Proton Pass; when pass-cli returns an auth error or an expired session; or when someone asks how to give an agent scoped, audited access to a vault. Also use when a plaintext secret turns up somewhere it should not be, when a vault needs deduplicating after a migration left near-copies behind; or when setting up, auditing, or troubleshooting what an agent is allowed to read from the vault.
- Reads credentials
2 other projects use a version of this.
Adopted by
Most recently taken up by
- shaharsha/claude-skillstheir own version, first seen Oct 24, 2026
- timcase/agent-skillstheir own version, first seen Jul 19, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- shaharsha/claude-skills★ 6same name
- timcase/agent-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 6 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 49
All three segments are required.
- Very specific: line 95
Not required for discovery: info, vault list, share list, item list.
- Distinctive: line 103
Do not echo to check: If you need to confirm a read worked, test the length or the exit code, never the value.
- Very specific: line 111
Always set an isolated
PROTON_PASS_SESSION_DIR: before authenticating with a token. - Distinctive: line 118
Check before you act, recover when it lapses:
- Distinctive: line 134
Every *read* works from the on-disk session unaided.
- Distinctive: line 148
Not your personal vault. Grants are vault-scoped, so the vault boundary is the security control — it is what stands between a …
- Very specific: line 179
Use the helper in bin/ rather than reinventing it — it exists because two specific mistakes each cost a one-time token (see …
- Very specific: line 199
read it back and compare: before reporting success, and hand it to pass-cli as a process environment variable — never as an argument.
- Distinctive: line 209
Read the summary line, not just the exit code: anything reported as SKIP is unproven on that machine, not passing.
- Distinctive: line 212
After this the agent is autonomous until the next expiry: a read that hits a lapsed session re-logs-in by itself and retries.
- Very specific: line 251
Always write --item-id=$ID, never --item-id $ID.
- Very specific: line 266
Check for the second half of the trap too: a permissions.allow entry like Bash(pass-cli *) in ~/.claude/settings.json auto-approves every …
- Very specific: line 289
pass-cli testdoes not exist: Use info.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Proton Pass from the command line
pass-cli is Proton's official CLI for Proton Pass. This skill covers reading
secrets from it safely, and the one-time setup that lets an unattended process
keep reading them after its session expires.
Everything here is verifiable against https://protonpass.github.io/pass-cli/. Where this file contradicts those docs, it is because the documented behavior was tested and found wrong — those cases are marked.
The one rule
A secret read from the vault must never reach a command line, a log, or a transcript. Read it into a variable in the same command that consumes it, then drop it. This is not ceremony: process arguments are world-readable on most systems, shell history persists, and an agent transcript is often stored and sometimes shared.
That rule is also why the setup below exists. The obvious way to log in — pasting the token into a command — is the one way you must not.
Object model
Four things, nested:
| Thing | What it is |
| Share | The link between you and a resource. Has a Share ID. A vault share covers a whole vault; an item share covers exactly one item. |
| Vault | A container of items. Addressed by name or Share ID. |
| Item | A login, note, card, SSH key, alias, identity. Addressed by title or Item ID. |
| Field | username, password, email, url, note, totp, or any custom field by its own name. |
Roles on a share are viewer, editor, manager. Only the vault's creator can
delete it.
pass:// references
The addressing syntax, and the form to prefer:
pass://<vault-name-or-share-id>/<item-title-or-id>/<field-name>All three segments are required. Names and IDs can be mixed freely
(pass://Work/XyZ789/password is valid). Spaces are allowed inside names — no
escaping syntax is documented, so quote the whole URI in your shell.
- Name resolution is case-sensitive, and on a duplicate name the first match wins. Use Share IDs and Item IDs when you need a guarantee.
- Fields inside a custom section are
SectionName.fieldname. An unqualified name resolves to the first match across all sections. Identity items are the exception — their built-in personal/address/contact/work fields take no prefix. - A TOTP field resolves to the live code.
?totp=codeis explicit;?totp=urireturns the storedotpauth://URI instead.
Invalid: pass://vault/item, pass://vault/item/, pass://vault/, pass://.
Reading a secret
item view accepts either targeting flags or a URI. Prefer the URI — it
returns the bare value, where the flag form with --output json returns the
whole item.
PROTON_PASS_AGENT_REASON="Deploying the staging worker" \
pass-cli item view "pass://Access Tokens/Stripe/secret_key"view has aliases get and show. run and inject consume the same
references:
export DB_PASSWORD='pass://Production/Database/password'
pass-cli run -- ./my-app # resolved into the child's env
# template.tpl contains: password = {{ pass://Production/Database/password }}
pass-cli inject -i template.tpl -o config.iniThe reason is mandatory, and it is read by a human
Agent tokens log every access. PROTON_PASS_AGENT_REASON must be non-empty and
at most 300 characters, and it is stored end-to-end encrypted next to the log
entry. The vault owner reads these later with agent monitor. Write a real
sentence — "task" and "test" are how you lose an owner's trust in the grant.
Required for: item view, item create (all variants), item update,
item trash, item untrash, item move, vault update.
Not required for discovery: info, vault list, share list, item list.
Two traps that leak secrets
- Do not redact
--output jsonby pattern. A hidden custom field serializes as"Hidden": "<the secret>". A regex written to catch"value"or"content"sails straight past it. Use the URI form, which returns only the field you asked for. - Do not echo to check. If you need to confirm a read worked, test the length or the exit code, never the value.
Sessions
A session persists on disk between commands, so most reads need no login at all.
- PAT and agent sessions last 2 hours and cannot carry a session lock.
- Always set an isolated
PROTON_PASS_SESSION_DIRbefore authenticating with a token. Without it, a token login overwrites the human's own interactive session in the default location. - Make that directory durable, not a temp path. The published example uses
/tmp/pass-agent-<name>, which is fine for one CI job and wrong for a long-lived agent — a cleaned-up/tmpsilently costs you the session.
Check before you act, recover when it lapses:
pass-cli info || { # non-zero means no live session
pass-cli logout --force # clear anything stale; plain logout can error
pass-cli login # token comes from the environment, see below
}pass-cli test does not exist in 2.3.2, despite appearing in some
instructions. Use info for health.
Setup: the bootstrap credential
This is the part people get wrong.
Every read works from the on-disk session unaided. The one command an unattended process cannot run is the login, because that needs the token — and the token is deliberately somewhere the process cannot see. Sound design, one consequence: without help, a routine 2-hour expiry strands the job and needs a human. And the token is displayed exactly once at creation, so a lost copy means regenerating it.
The fix is exactly one bootstrap secret in the OS keychain, holding nothing but the token. The blast radius does not change — that token still reaches only the vaults it was granted, and the keychain is bound to this user on this machine.
1. Create a vault for machine secrets
Not your personal vault. Grants are vault-scoped, so the vault boundary is the security control — it is what stands between a prompt-injected agent and everything you own.
Two structural facts worth internalizing:
- A token can never live in the vault it unlocks. Machine secrets need their own vault, separate from the human one.
- The right response to "the agent can't reach credential X" is a new purpose-built vault with its own short-expiry token. It is never widening an existing grant to the personal vault.
2. Create an agent token, scoped
An agent token is a PAT with access logging switched on. Prefer it over a bare PAT for anything non-human — the audit trail is the whole point.
pass-cli agent create my-agent --expiration 3m --vault "Machine Secrets"--expiration takes 1h, 1d, 1w, 1m, 3m, 6m, 1y — it is mandatory,
so this recurs. --vault repeats. Output is JSON containing the token, shown
this once only. Grant more later with agent access grant, review with
agent monitor, rotate with agent renew (grants survive; the old token dies
immediately).
Token shape is pst_<token>::<key>.
3. Store it in the OS keychain
Use the helper in bin/ rather than reinventing it — it exists because two
specific mistakes each cost a one-time token (see references/bootstrap.md).
# Windows — Credential Manager (DPAPI, user- and machine-bound)
. .\bin\ProtonPassAgent.ps1
Set-ProtonPassAgentToken # masked box; never echoed, never an argument
Connect-ProtonPassAgent # idempotent login
Get-ProtonPassSecret -Uri 'pass://Machine Secrets/Stripe/secret_key' -Reason 'deploy'# macOS (Keychain) / Linux (libsecret)
./bin/proton-pass-agent.sh self-check # prove it works here FIRST
./bin/proton-pass-agent.sh store # prompts with echo off
./bin/proton-pass-agent.sh connect
./bin/proton-pass-agent.sh get 'pass://Machine Secrets/Stripe/secret_key' 'deploy'Both take the token by prompt with echo disabled, write it to the keychain,
read it back and compare before reporting success, and hand it to pass-cli
as a process environment variable — never as an argument.
Run self-check before the token exists. It exercises the shape validation
and a full store / read-back / delete cycle against a throwaway keychain entry
and an obviously fake value, so a broken keychain path surfaces while it costs
nothing. The token is displayed exactly once at creation, so the worst moment to
discover the store is broken is while holding the only copy — which is not
hypothetical, it is how two tokens were already lost (references/bootstrap.md).
Read the summary line, not just the exit code: anything reported as SKIP is unproven on that machine, not passing.
After this the agent is autonomous until the next expiry: a read that hits a lapsed session re-logs-in by itself and retries.
4. Verify end to end
pass-cli info should name your token under Personal Access Token:. Then do a
real read. A login that "succeeds" but cannot read anything means the grant is
missing, not the auth.
When you find a plaintext secret
Say so, once, and name the pass:// reference that would replace it. .env
files, hardcoded keys in scripts, tokens in CI config, anything sitting in a
keychain that could move into a vault instead. One line is enough — this is a
note, not a lecture.
Bulk edits and duplicates
Everything above is about reading. Writing in bulk — collapsing the near-copies an import left behind — has its own rules, because the failure mode is silent data loss rather than a failed read.
The short version: do not export, dedupe, and re-import. Passkeys, aliases
and file attachments do not survive that round trip, and every timestamp resets,
destroying the evidence needed to tell copies apart afterwards. Target the
duplicates with item trash instead; survivors are never touched, and trash is
reversible with item untrash, so no backup export is needed.
Two items are the same account only if they agree on share, registrable domain, identity and byte-exact password. Anything less merges accounts that merely look alike.
references/dedupe.md — the full method, the three cases that must be refused
rather than collapsed, and the invariants to check against the live vault.
bin/pass-dedupe.py — a four-phase implementation (plan, verify, apply,
undo) that refuses to write a plan if an invariant fails.
One trap worth knowing even if you never dedupe: roughly 1% of Proton item
IDs are base64 strings beginning with -, which pass-cli parses as a flag.
Always write --item-id=$ID, never --item-id $ID. A loop over many items hits
this on a handful and otherwise looks like it succeeded.
Gating what an agent can reach
Everything above assumes the caller is trustworthy. It usually is. The gap is
that none of pass-cli's controls bind a caller that does not opt into them.
An agent token is vault-scoped and logs every read with a reason. But agents
inherit the human session at %APPDATA%\proton-pass-cli\.session, because
PROTON_PASS_SESSION_DIR is unset by default - and that session permits
--show-secrets, which agent sessions forbid. Nothing routes an agent through
the token. Observed consequence: a dedupe run read 1,880 plaintext passwords and
trashed 661 items while agent monitor recorded nothing at all.
Check for the second half of the trap too: a permissions.allow entry like
Bash(pass-cli *) in ~/.claude/settings.json auto-approves every invocation
before it runs, so no prompt appears regardless of policy. An allowlist matches
command prefixes and cannot see a --show-secrets at the end of the line.
hooks/proton-pass-guard.py is a Claude Code PreToolUse hook that puts bulk
reads, mutations, and edits to its own policy files in front of a human.
hooks/pass-cli-shim.py, installed as bin/pass-cli, applies the same policy to
callers hooks cannot reach. Both log every invocation - which is the only record
that human-session use leaves anywhere.
If a Proton Pass command is refusing or prompting unexpectedly, that is
probably this. And if every Bash/Edit/Write call is suddenly blocked, the
guard is missing or unparseable: a failing PreToolUse hook fails closed, in every
session on the machine. Recover with ! and a copy, never by deleting the hook.
references/agent-guard.md - install, the lockout recovery, the audit-log
format, and an honest account of what this does not protect against.
Corrections to the published docs
Found by testing against CLI 2.3.2:
pass-cli testdoes not exist. Useinfo.item viewhas no--item-name. It is--item-titleor--item-id, or the URI. The agent docs page shows--item-namein an example; it fails.- The secret-reference page says field matching is case-insensitive in one section and case-sensitive in another. Treat it as case-sensitive.
- Docker: the kernel secret service is unavailable inside a container, so the CLI's key falls back to the filesystem. Plan for that before putting pass-cli in an image.
- Package-manager installs (Homebrew) disable
pass-cli updateand release-track switching. Only manual installs can change tracks.
Full command reference
references/commands.md — every command group, flags, and examples.
references/bootstrap.md — the keychain design, per-OS detail, and the rotation
ceremony.
references/dedupe.md — deduplicating a vault in place, and why the
export/import round trip loses passkeys.
references/agent-guard.md — gating agent access, and why pass-cli's own
controls do not bind a caller that ignores them.
pass-cli agent instructions prints Proton's own current usage doc as Markdown;
worth diffing against this file when the CLI updates.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

