🔑 apwcli
Apple Passwords (iCloud Keychain) from the terminal. Read passwords and one-time codes, save logins, script it all.
Website · Commands · Python library · Examples · How it works
- Passwords & one-time codes — read, save, and update Apple Passwords entries
- ✨ Agent-ready — bundled Claude skill and MCP server (
apwcli mcp install) - Safe by default — passwords are masked on screen;
-ccopies to the clipboard instead - Scriptable — JSON/TSV output everywhere; Python API via
apwlib - Zero setup — everything starts and pairs automatically on first use
Install
brew install michel-tricot/tap/apwcli # or: uv tool install apwcli, pipx install apwcli
Or from a clone: uv sync, then uv run apwcli --help.
Requires macOS with a supported browser installed (Chrome, Brave, Edge, or Chromium); the iCloud Passwords extension itself is downloaded automatically from the Chrome Web Store.
Quick start
apwcli pw get github.com # saved entries (passwords masked)
apwcli pw get github.com me@example.com # narrow to one account
apwcli otp get github.com # current one-time code
The first command sets everything up. If pairing is needed, macOS shows a 6-digit PIN and apwcli prompts for it — that's the whole ceremony. Anything misbehaving? See Troubleshooting.
Security
This is a tool for your passwords, so here's exactly what it does with them:
- Nothing leaves your Mac. apwcli talks only to Apple's local iCloud Passwords helper, through the official extension running in a browser on your machine. There are no servers, telemetry, or network calls of our own.
- Apple's crypto does the crypto. Pairing (SRP) and per-command encryption (AES-GCM) run inside the real extension; apwcli is transport around it and never implements or handles key material itself.
- Secrets stay off your screen and out of scrollback. Tables mask passwords
by default (
--showto reveal);text/jsonoutput is unmasked for piping.-ccopies to the clipboard instead of printing, and the clipboard is auto-cleared after 20s (--clear-after). - Agents never see plaintext passwords by default. The MCP server exposes
one-time codes, saving, and pairing — but not password reads unless you
explicitly run it with
--allow-passwords(MCP results travel to the model provider). - Nothing sensitive is logged. The log records lifecycle and errors only; command bodies are encrypted inside the browser and never written in plaintext.
Full details — the launch constraint, the pairing handshake, the threat model — are in the design notes. Found a vulnerability? See SECURITY.md.
Commands
Passwords
apwcli pw get github.com # entries for a site, passwords masked
apwcli pw get github.com me@example.com # narrow to one account
apwcli pw get github.com me@example.com -c # copy to clipboard, print nothing
apwcli pw get github.com me@example.com --show # reveal in the table
apwcli pw save github.com me@example.com # create/update (prompts)
printf '%s' "$PW" | apwcli pw save github.com me@example.com # piped: no prompt
apwcli pw generate github.com me@example.com # make a strong password and save it
apwcli pw generate github.com me@example.com -c # …and copy it, don't print
Sites match by registrable domain: github.com, https://gist.github.com/x,
and www.github.com all find the same accounts. Clipboard copies (-c) are
wiped after 20 seconds; tune it with --clear-after (0 keeps them).
One-time codes
apwcli otp get github.com # the current code
apwcli otp get github.com -c # straight to the clipboard
apwcli otp list github.com # accounts that have codes
Scripting
Data commands take --format / -o: table (default), json, or text
(TSV for piping). Pipes always carry the real values — masking is only for
tables on screen.
apwcli pw get github.com me@example.com -o text | cut -f3
apwcli otp get github.com -o json | jq -r '.results[0].code'
Errors exit with the protocol status code (9 = not paired, or nothing to
talk to — see Troubleshooting) and print error: … to
stderr, or a JSON object with -o json.
Agents
apwcli ships with integrations for AI agents:
apwcli skills install # install the Claude skill into ~/.claude/skills
apwcli mcp install # wire the MCP server into Claude, Cursor, VS Code, …
The MCP server exposes one-time codes, saving, and pairing —
never plaintext passwords unless you start it with
apwcli mcp run --allow-passwords (MCP tool results travel to the model
provider; see the design notes).
Library
apwlib is the Python API behind the CLI:
from apwlib import ApplePasswords
pw = ApplePasswords(pin_provider=lambda: input("PIN: "))
for entry in pw.get_password("github.com", "me@example.com"):
login(entry.username, entry.password) # typed entries; nothing printed
Full guide and API reference on the
website; runnable scripts in
examples/.
Troubleshooting
You never launch or supervise anything: under the hood a background daemon starts on first use, and an unpaired command pops the macOS PIN dialog and prompts for the code (a small on-screen PIN window when there's no terminal). A pairing lasts as long as the daemon runs, so the PIN stays rare.
If something misbehaves, start with doctor — it checks the whole chain and
suggests the fix:
apwcli doctor # diagnose the setup (browser, extension, daemon, pairing)
apwcli daemon status # daemon / extension / pairing state (--json for scripts)
apwcli daemon pair # (re)pair; --pin 123456 to skip the prompt
apwcli daemon restart # replace a wedged daemon with a fresh one
apwcli daemon logs # tail the log (-f to follow, --clear to wipe)
apwcli daemon stop # stop the daemon and its browser
Contributing
Contributions are welcome. The repository is a
uv workspace with two packages: apwcli (this
project, src/apwcli) and apwlib. Set up a checkout:
git clone https://github.com/michel-tricot/apwcli
cd apwcli
uv sync
Before committing, run the full validation suite — format, lint, typecheck, tests — and keep it green; CI runs the same thing:
scripts/check.sh
Work on the documentation site (MkDocs Material):
uv sync --group docs
uv run mkdocs serve # live preview at http://127.0.0.1:8000
Contributor and agent guidelines live in AGENTS.md; design notes in docs/design/apwlib.md.
License
MIT © Michel Tricot · Not affiliated with Apple. Apple Passwords and iCloud Keychain are trademarks of Apple Inc.
Release files for apwcli 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| apwcli-0.1.2.tar.gz | 16.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| apwcli-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.4 kB
Release files / apwcli-0.1.2.tar.gz
| Download URL | apwcli-0.1.2.tar.gz |
|---|---|
| Size | 16.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ed5283bf8b8498b44b679c0c080294d92b74afd7af89e0ff5b52ee4c00b522e2
|
|
BLAKE2b-256 checksum How to use checksums |
d494d455409a79cfd8c66779dec1cd70eee8c6ddd93316f8a34e80459f7e1bc7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / apwcli-0.1.2-py3-none-any.whl
| Download URL | apwcli-0.1.2-py3-none-any.whl |
|---|---|
| Size | 21.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
88cecc235bb387672b79ca9706fc6e1f0a567703ebb91cbf42e3284306db8e46
|
|
BLAKE2b-256 checksum How to use checksums |
94f83e7ccc6771d39ba585bcae189c2363ee13ac8463cd8f83cb373b102b5c51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|