A personal password manager for humans and AI agents on Apple devices. AutoFill everywhere on Mac, iPhone and iPad · end-to-end encrypted peer-to-peer sync between your own devices — no cloud, no server · AI agents that use and tidy your vault — only with your Touch ID or Apple Watch approval.
面向人和 AI Agent 的个人密码管理器:Apple 全端自动填充,自己设备之间点对点端到端加密同步(不用任何云和服务器),Agent 在你的 Touch ID / Apple Watch 批准下取用并帮你打理保险库。
- For you: AutoFill credential provider (passwords, passkeys, TOTP) on iOS/iPadOS/macOS, Safari extension, menu-bar quick search, import from 1Password / Apple Passwords / Chrome / Firefox / Bitwarden / CSV. (apps: roadmap)
- For agents:
agentkeyd+agentkeyCLI + MCP server. Agents get secrets injected into processes (never shown by default), read vault health findings (metadata only), and propose cleanup plans that you approve. - Personal, zero external services: every device holds the full encrypted vault. Devices sync directly with an
always-on home node (e.g. your Mac mini running
agentkeyd --sync-node) over LAN / Tailscale / WireGuard, using a Noise XX channel and QR-code pairing. No iCloud, no accounts, nothing hosted.
Status: v0.3 (Phase 1.6) — core crypto & vault, Mac daemon/CLI/MCP, importers, vault health + cleanup plans, peer-to-peer sync (Noise XX, pairing, revocation + key rotation, encrypted offline backup). The protocol and TCP transport are tested on Linux; Bonjour / Network.framework transports and Secure-Enclave key storage still need Mac validation. Not audited.
中文说明 · Design doc (zh) · Security
┌───────────── agent (Claude Code / Cursor / script) ─────────────┐
│ agentkey exec --env TOKEN=ak://OpenAI -- curl ... │
│ agentkey-mcp (MCP stdio: list_items / run_with_secret / ...) │
└───────────────┬─────────────────────────────────────────────────┘
│ Unix socket ~/Library/Application Support/AgentKey/agent.sock (0600, same uid only)
│ 4-byte length + JSON (JSON-RPC 2.0 semantics), "progress" notifications
┌───────────────▼─────────────────────────────────────────────────┐
│ agentkeyd (LaunchAgent, Aqua session) │
│ policy → ApprovalCoordinator (serialized, 60 s timeout) │
│ → LAContext (fresh, reuse 0, no password fallback) │
│ policy .deviceOwnerAuthenticationWithBiometricsOrCompanion
│ = Touch ID keyboard OR Apple Watch │
│ hash-chained audit log (audit.jsonl) │
└───────────────┬─────────────────────────────────────────────────┘
│ AgentKeyCore
┌───────────────▼─────────────────────────────────────────────────┐
│ vault.akv JSON envelope, AES-256-GCM per item (AAD = vault/item/rev)
│ VK wrapped by AUK = KDF(master password) ⊕ HKDF(Secret Key) │
│ Secret Key in Keychain (ThisDeviceOnly, not synced) │
└───────────────┬─────────────────────────────────────────────────┘
│ vault ⇄ sync replica bridge (HMAC snapshot)
┌───────────────▼─────────────────────────────────────────────────┐
│ P2P sync: Noise XX (X25519/ChaChaPoly/SHA-256), per-device key │
│ ⇄ home node (agentkeyd --sync-node, TCP 7373) ⇄ other devices │
│ transports: TCP (LAN/Tailscale/WireGuard) · Bonjour _agentkey._tcp · Multipeer (opt.)
└─────────────────────────────────────────────────────────────────┘
| Target | What |
|---|---|
AgentKeyCore (macOS 14+/iOS 17+, also Linux) |
Importers (1PUX, 1Password/Apple/Chrome/Firefox/Bitwarden/generic CSV, Bitwarden JSON, otpauth), Hygiene (VaultHealth, CleanupPlan), Sync (Lamport Stamp, RecordMeta, tombstones, MergeEngine 3-way merge), P2P (Noise XX channel, device identity, QR pairing, PeerReplica delta sync, revocation + key rotation, SyncNode, memory/TCP transports, Bonjour/NW transports for Apple, encrypted BackupFile; legacy CloudKit adapter off by default), CryptoKit AES-GCM + HKDF, 2SKD key hierarchy, PasswordKDF (PBKDF2-SHA256 600k today, Argon2id TODO), Secret Key, vault model (login / secure note / API token / TOTP), encrypted store, RFC 6238 TOTP, password generator, policy, prompt sanitizer, redactor, audit log |
AgentKeyIPC |
Unix-socket framing, peer credentials, daemon client |
agentkeyd |
per-user daemon; Touch ID / Apple Watch approval (ApprovalGate.swift) |
agentkey |
CLI (ak alias via installer) |
agentkey-mcp |
MCP stdio server |
App/ |
placeholder SwiftUI multiplatform app |
| mode | plaintext goes to | default |
|---|---|---|
run |
child process env (agentkey exec, MCP run_with_secret); output redacted |
✅ |
totp |
only the current code | ✅ |
reveal |
caller (agentkey get, MCP get_secret) |
❌ must be enabled for the agent and the item |
http, inject, fill |
roadmap | — |
Requirements: macOS 14+ (tested target: macOS 27, Xcode 26.2, Swift 6.2). Command Line Tools only (no Xcode) is enough
for swift build; swift test needs XCTest, which some CLT releases lack — use Xcode for tests in that case. For approvals you need either a
Magic Keyboard with Touch ID or an Apple Watch with System Settings → Touch ID & Password → Apple Watch enabled.
git clone https://github.com/neardws/AgentKey && cd AgentKey
swift build
swift test
# install binaries to ~/.local/bin and load the LaunchAgent (runs in your GUI session)
./Support/install-launchagent.sh
export PATH="$HOME/.local/bin:$PATH"
agentkey init # prints your Secret Key once — write it down
agentkey unlock # master password → daemon
agentkey status # touchIDReady / watchReady
agentkey add token --title OpenAI # prompts for the token
agentkey add login --title GitHub --username neardws --generate
agentkey add totp --title AWS --secret 'otpauth://totp/...'
agentkey list
agentkey exec --agent claude-code --env OPENAI_API_KEY=ak://OpenAI -- python my_script.py
agentkey totp ak://AWS
agentkey generate --length 32
agentkey audit verify
# migrate (export file is read into memory only; delete it afterwards)
agentkey import auto ~/Downloads/1PasswordExport.1pux --dry-run
agentkey import apple-csv ~/Downloads/Passwords.csv
agentkey import csv export.csv --map title=Account,password=Secret
# let an agent tidy up — it can only propose; you approve
agentkey health --json
agentkey plan create # or MCP propose_cleanup
agentkey plan show plan-1a2b3c4d
agentkey plan apply plan-1a2b3c4d --actions a1,a3 # Touch ID / Apple Watch# on the Mac mini (home node): TCP 7373 + Bonjour _agentkey._tcp on the LAN
./Support/install-launchagent.sh --sync-node # LaunchAgent runs `agentkeyd --sync-node` (add --no-bonjour to disable advertising)
agentkey device pair --host mini.tailnet.ts.net # Touch ID → one-time code (QR text) + node fingerprint
# on the new device
agentkey device pair 'agentkey-pair:eyJ…' # verifies the node fingerprint, receives the vault key encrypted
agentkey sync now # also runs every 5 min in the background
agentkey sync status --json
agentkey sync discover --json # AgentKey nodes on this LAN (Bonjour), marked paired / not paired
agentkey device list
agentkey device revoke <id|name|fingerprint> # lost device: blocked at handshake + vault key rotated
# encrypted offline backup (your last line of defence; passphrase ≥ 12 chars)
agentkey backup export ~/agentkey-2026-10.akbackup
agentkey backup restore ~/agentkey-2026-10.akbackupPairing, revocation, backup export and restore all require Touch ID / Apple Watch. Agents get none of these as MCP tools. Keep the home node's port off the public internet; reach it from outside via Tailscale/WireGuard.
LAN discovery (Bonjour): the home node advertises _agentkey._tcp with instance name agentkey-<8 chars of its key fingerprint> and TXT v=<protocol>, fp=<8-char fingerprint> only — no device name, no vault info. Pairing codes list
bonjour:<name> first and fall back to host:port (LAN IPs, --host names). Discovery only finds an address: every
connection still pins the node's full fingerprint in the Noise handshake, so a spoofed advertisement gets nowhere.
Disable with agentkeyd --no-bonjour or AGENTKEY_NO_BONJOUR=1.
Different networks / NAT traversal (no AgentKey server): devices race candidates ICE-style — LAN Bonjour → direct
IPv6 → configured/forwarded host:port → UDP hole punching → relay (off by default, your own only). Public address via
a built-in STUN client (Google, Cloudflare, Xiaomi, Tencent servers by default; configurable). Candidates are exchanged
through the BitTorrent Mainline DHT (BEP 44 items signed with per-pair keys and encrypted to the peer — unlinkable to
your devices), or by copy-paste (agentkey sync signal export|import), or from last-known endpoints. The Noise handshake
with the pinned fingerprint remains the only trust anchor.
agentkey net probe # STUN results, NAT type, global IPv6, our candidates, DHT status
agentkey sync now -v # race all candidates, show every attempt
agentkey sync now --via udp -v # force hole punching (or lan | ipv6 | tcp)
agentkey sync signal export # if the DHT is unreachable: paste the blob on the other device…
agentkey sync signal import 'akr1.…'Config: ~/Library/Application Support/AgentKey/sync/net.json —
{"stunServers":[…], "dht":true, "udpPort":7373, "forwardedEndpoints":["203.0.113.5:7373"], "relay":null};
agentkeyd --no-net disables STUN/DHT/UDP entirely. Hole punching fails if both sides have symmetric NATs or UDP is
swallowed by a proxy/VPN — then use IPv6, a forwarded port, or Tailscale/WireGuard.
macOS Local Network prompt: SwiftPM-built CLI binaries have no Info.plist, so macOS attributes their LAN access to the
responsible app. agentkeyd started by the LaunchAgent gets its own entry; agentkey sync discover --local or
agentkeyd run from a shell may trigger the prompt for your terminal app (Terminal / iTerm / Ghostty). Allow it in
System Settings → Privacy & Security → Local Network. The App target needs NSLocalNetworkUsageDescription and
NSBonjourServices — see App/AgentKeyApp/Info.plist.template.
MCP tools: list_items, run_with_secret, get_totp, get_secret (off by default), vault_health,
propose_cleanup, get_plan_status. There is deliberately no tool to apply a plan.
Agent-native output: every command accepts --json (or AGENTKEY_OUTPUT=json); metadata commands
(status, list, add, init, unlock, lock, audit) emit JSON automatically when stdout is not a TTY.
Errors look like {"ok":false,"error":{"code":"POLICY_DENIED","exit":65,"message":"..."}}. For exec, the child's
output stays on stdout/stderr (redacted) and JSON metadata goes to stderr. get/totp/generate print the raw value
when piped unless --json is given.
Redaction: exec / run_with_secret redact every released secret on stdout and stderr, streaming-safe across chunk
boundaries. Secrets shorter than 8 characters are still redacted, but trigger a SHORT_SECRET warning because
redaction of short values is unreliable.
Optional policy: copy Support/policy.example.json to ~/Library/Application Support/AgentKey/policy.json.
claude mcp add agentkey -- ~/.local/bin/agentkey-mcp --agent claude-code{ "mcpServers": { "agentkey": { "command": "/Users/<you>/.local/bin/agentkey-mcp", "args": ["--agent", "cursor"] } } }Set the client's tool timeout ≥ 90 s — approvals wait up to 60 s.
| Phase | Scope | Status |
|---|---|---|
| 1 | Mac core + agent channel: crypto, vault, agentkeyd Touch ID/Watch approvals, CLI, MCP, audit, --json, redaction |
✅ v0.1 |
| 1.5 | Importers, vault health + cleanup plans, sync model (Lamport, tombstones, 3-way merge) | ✅ v0.2 |
| 1.6 | No external services: home-node + P2P sync (Noise XX, QR pairing, revocation + key rotation), encrypted backup, device/sync/backup CLI; CloudKit demoted to an off-by-default legacy module |
✅ v0.3 (Bonjour discovery: Mac runtime validation pending) |
| 1.7 | NAT traversal: STUN, candidate racing, BEP 44 DHT rendezvous, manual signalling, UDP hole punching + reliable UDP stream, net probe |
✅ (live STUN/DHT: Mac validation pending) |
| 2 | Encrypted SQLite record store, Bonjour discovery + Multipeer, iOS background sync, QR scanner UI, Argon2id, Secure Enclave unlock, signed app + App Group | ⏳ |
| 3 | iPhone / iPad / Mac apps, AutoFill extension (passwords + TOTP), menu-bar quick search, import wizard | ⏳ |
| 4 | Passkeys provider, Safari web extension, Chrome extension | ⏳ |
| 5 | Rotation assistant, http/inject/fill modes, grants & revoke, remote approval on iPhone, encrypted audit |
⏳ |
AgentKey 是一个个人使用、开源、类似 1Password 的密码管理器,覆盖 Mac / iPhone / iPad。人和 AI Agent 都是一等用户:
你在所有 App 和网站里享受自动填充(密码、通行密钥、验证码),从 1Password / Apple 密码 / Chrome / Firefox / Bitwarden 一键迁移,
在自己的设备之间点对点端到端加密同步(家里的 Mac mini 做常在线“家庭节点”,不依赖 iCloud、任何云或服务器);Agent 则可以取用秘密、体检保险库并提出清理计划——
Agent 可以"使用"你的密码和 API Key,但每一次释放都必须由你本人在 Mac 上用 Touch ID(妙控键盘)或双击 Apple Watch 侧边按钮 确认;
推荐的 run 模式下,秘密只注入子进程环境变量,Agent 自己看不到明文;Agent 提出的清理计划(合并重复、归档、标记轮换等)也必须由你批准才会执行,且可撤销、全程审计。
- 双因素密钥派生(2SKD):AUK = PBKDF2(主密码) ⊕ HKDF(Secret Key)。只拿到加密的 vault 文件,没有本机 Secret Key 无法离线爆破。
- 逐条加密:每个条目 AES-256-GCM,AAD 绑定保险库 ID / 条目 ID / 版本号,防止密文互换。
- 每次释放都要人确认:每个请求新建
LAContext,复用时长 0,不允许退回登录密码;两种认证都不可用、超时(60 s)或非 GUI 会话时 一律拒绝。 - 防伪造提示:系统弹框里的 Agent 名、条目名经过净化(去掉控制字符 / 双向文字覆盖 / 零宽字符,并截断),并显示 4 位关联码,与终端里的码对照。
- 明文默认不出门:
reveal需要在策略里为该 Agent 开启,并且条目本身也允许。 - 审计:追加写的 JSONL,SHA-256 哈希链 + HMAC(密钥由保险库密钥派生),
agentkey audit verify可检测篡改。
- 家庭节点:Mac mini 上运行
agentkeyd --sync-node(TCP 7373,局域网 / Tailscale / WireGuard)。 - 配对:节点上
agentkey device pair显示一次性二维码(含节点地址、一次性密钥、节点公钥指纹,10 分钟过期、单次有效);新设备agentkey device pair <码>。Noise XX + psk 双向认证,新设备先核对指纹再暴露身份;保险库同步密钥在加密信道里交给新设备。 - 跨网络 / NAT 穿透(不需要 AgentKey 服务器):候选竞速——局域网 Bonjour → IPv6 直连 → 配置/端口转发的
host:port→ UDP 打洞 → 中继(默认关闭)。内置 STUN 客户端(默认含小米、腾讯等国内可达服务器);候选通过 BitTorrent DHT(BEP 44,每对设备派生的密钥签名并加密,外人无法关联)或手工agentkey sync signal export|import交换。agentkey net probe查看 NAT 类型和候选,agentkey sync now --via udp -v查看每次尝试。两边都是对称 NAT 或 UDP 被代理/VPN 拦截时无法打洞,请用 IPv6、端口转发或 Tailscale/WireGuard。 - 局域网发现:家庭节点通过 Bonjour 广播
_agentkey._tcp(实例名agentkey-<指纹前 8 位>,TXT 只有协议版本和短指纹,不含设备名或保险库信息);agentkey sync discover --json列出局域网内的节点。配对码优先写bonjour:<名字>,失败再回退host:port。发现只提供地址,信任仍由 Noise 握手中的完整指纹决定。--no-bonjour/AGENTKEY_NO_BONJOUR=1可关闭广播。macOS 上从终端运行的 SwiftPM 命令行程序可能会让终端 App 弹出“本地网络”权限请求,在“系统设置 → 隐私与安全性 → 本地网络”里允许即可。 - 同步:
agentkey sync now | status --json,后台每 5 分钟一次;增量、可断点续传、幂等,线上只有加密记录;冲突用三方合并,落败的秘密进条目历史。 - 丢失设备:
agentkey device revoke,所有设备握手时拒绝它,并立即轮换保险库同步密钥。 - 离线备份:
agentkey backup export|restore,备份口令 + AES-GCM 加密文件。 - 配对、撤销、备份导出 / 恢复都需要 Touch ID / Apple Watch 批准。
swift build && swift test
./Support/install-launchagent.sh # 安装到 ~/.local/bin 并加载 LaunchAgent
agentkey init && agentkey unlock && agentkey status注意:Mac mini 没有内置 Touch ID,需要配对带 Touch ID 的妙控键盘,或在"系统设置 → 触控 ID 与密码"中打开 Apple Watch 解锁。
agentkeyd 必须运行在你登录后的图形会话中(LaunchAgent 已设置 LimitLoadToSessionType=Aqua),从 SSH 启动将无法弹出确认框,请求会被拒绝。
Phase 1 ✅ Mac 核心 + Agent 通道 · Phase 1.5 ✅ 迁移导入、保险库体检与清理计划、同步模型(三方合并)·
Phase 1.6 ✅ 零外部服务:家庭节点 + 点对点同步、二维码配对、撤销 + 密钥轮换、加密离线备份(Bonjour 待 Mac 验证)·
Phase 2:加密 SQLite 记录库、Bonjour 自动发现 + Multipeer、iOS 后台同步、Argon2id、Secure Enclave 快速解锁 ·
Phase 3:iPhone / iPad / Mac App、自动填充扩展、菜单栏快速搜索 · Phase 4:通行密钥、Safari / Chrome 扩展 ·
Phase 5:轮换助手、http 模式、iPhone 远程审批。
详细设计见 docs/DESIGN.zh.md。
MIT © Neil Xu