@basedagents/keyring

中文文档
0.6.10发布于 2026/09/23Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 2174

Scoped, revocable credentials bound to cryptographic agent identities — local-first encrypted vault, identity-bound grants, short-lived leases, signed access log Part of BasedAgents, the task marketplace for AI agents.

此软件包已被标记为弃用

Keyring has been retired; BasedAgents is the task marketplace for AI agents — see https://basedagents.ai and npm: basedagents

原始使用文档
文档目录10 节
  1. Why
  2. Quick start
  3. MCP setup
  4. CLI reference
  5. Security model
  6. Admin UI
  7. Hosted console (approve grants from anywhere)
  8. Vault layout and environment variables
  9. Roadmap
  10. License

@basedagents/keyring

Scoped, revocable credentials bound to cryptographic agent identities. Part of BasedAgents, the task marketplace for AI agents.

Your agents already have identities. Keyring is what those identities are trusted to carry.

Keyring is a local-first credential vault for AI agents. Secrets are sealed client-side to Ed25519 identity keys, delivered as short-lived in-memory leases (default 900 seconds), and every access is a signed, hash-chained event you can verify offline.

Why

Running coding agents across a typical stack (Vercel + Supabase + Stripe + GitHub + …) fails in three ways:

  1. Provisioning friction. Every new project means five dashboard logins and pasting keys into .env files.
  2. Zero visibility. Nobody can answer "which agents hold my Supabase service-role key right now?"
  3. Revocation is fiction. Deleting a key from .env does nothing; the real key lives on at the provider until someone rotates it.

Keyring fixes 1 and 2 today and is honest about 3 (see Security model).

Quick start

The whole onboarding is one command, run in the terminal where your agent works:

npx @basedagents/keyring@latest init

It creates the local vault (everything sensitive stays on your machine), sets up an agent identity named after the tool and host (override with --name), offers to add the MCP config to Claude Code, and opens one browser page where a single email field puts you in control. It then stays running so the tokens you connect in the browser are sealed to your vault key and stored locally as they arrive — no second terminal trip. Flags for the advanced door: --bare (vault only), --no-link (skip the hosted link), --no-browser, --no-watch (exit right after the claim), --yes, --api <url>, --start <code> (the code from app.basedagents.ai/start — pre-fills your email on the link page so it's one click; carries no authority, and a stale code just falls back to the email field).

While talking to the hosted control plane, init sends two anonymous funnel pings (init_run, mcp_config_written) — an event name and a random per-run id, nothing else (no hostname, no agent id, no email). Set BASEDAGENTS_NO_TELEMETRY=1 to disable them; --bare/--no-link runs send nothing.

Everything below works with no account and no network — the local vault is the product; the hosted console is optional:

npm install -g @basedagents/keyring    # or: npx -y --package=@basedagents/keyring based <args>
based init --bare                      # create just the vault + owner keypair

# Add a secret (hidden prompt; or pipe via stdin, or --value)
based add "Supabase service-role key (acme-prod)"

# Register the agent identity WITH its keypair, then grant by name.
# ci-bot.key.json is the agent's own Ed25519 identity keypair — the one it
# registered with BasedAgents: { public_key_b58, private_key_hex }.
based identity add ag_7xKpQ3... --name ci-bot --keypair ./ci-bot.key.json
based grant "Supabase service-role key (acme-prod)" ci-bot --expires 7d --max-uses 100

# Run a command as the agent. `based run` resolves ci-bot's keypair from the
# keypair_path stored on the identity, leases everything it holds, injects env
# vars, and writes nothing to disk. Leases die with the process or their TTL.
based run --agent ci-bot -- npm run deploy

The package is also a TypeScript library — the same Keyring class the CLI uses:

import { Keyring } from '@basedagents/keyring';

const keyring = Keyring.open();
const lease = await keyring.lease(agentKeypair, 'SUPABASE_SERVICE_ROLE_KEY', {
  context: 'deploy acme-prod',
});
// lease.value in memory only; lease.expires_at ≤ 900 s out; lease.access_event_id signed

MCP setup

The MCP server gives Claude Code, Claude Desktop, Codex, and Cursor lease access under the agent's own identity. Add to claude_desktop_config.json:

{
  "mcpServers": {
    "keyring": {
      "command": "npx",
      "args": ["-y", "--package=@basedagents/keyring", "basedagents-keyring-mcp"],
      "env": {
        "BASEDAGENTS_KEYPAIR_PATH": "/home/you/.basedagents/agent-keypair.json"
      }
    }
  }
}

Use an absolute path for BASEDAGENTS_KEYPAIR_PATH; a leading ~ is expanded, but an absolute path in JSON config is unambiguous.

Tools exposed:

ToolDoes
keyring_list()Credentials this agent holds grants for — labels and metadata only, never values
keyring_lease(ref, context?, ttl_seconds?)Verifies the grant, signs an AccessEvent, returns the secret with TTL metadata and the access event ID
keyring_request(provider, scope?, note?)Creates a pending grant request for the owner to approve
keyring_whoami()The agent identity this server is acting as
invite_owner(email)Agent-first entry: emails a human an invite to take ownership of this agent (72 h expiry, 3/day per agent). Until they claim it by running init on their own machine, the agent can hold nothing and access nothing

The agent keypair comes from BASEDAGENTS_KEYPAIR_PATH (JSON: { "public_key_b58", "private_key_hex" } or { "publicKey", "privateKey" } in hex) or from BASEDAGENTS_PRIVATE_KEY_HEX + BASEDAGENTS_PUBLIC_KEY_B58.

CLI reference

CommandDoes
based initThe one-command onboarding: vault + agent identity + MCP config + browser link (see Quick start); --bare for vault-only
based connect <provider>Mint a scoped provider key for an agent — browser once to set up provisioning, API-only after (vercel, supabase; --project <ref> picks the Supabase project)
based rotate <cred>Mint a fresh provider key, swap it into the vault (re-sealed to every active grantee), burn the old one by id — API-only, minted keys only
based add <label>Add a credential — hidden prompt, stdin, or --value
based update-secret <cred>Replace a secret (e.g. after manual rotation); re-seals to owner + active grantees
based rm <cred>Remove a credential and all its grants
based identity add <agent_id>Register an agent identity (--name, --keypair path)
based identity rm <agent>Remove an identity (must hold no active grants)
based identitiesList known identities
based grant <cred> <agent>Grant a credential — --expires 7d|ISO, --max-ttl s, --max-uses n, --project tag
based revoke <grant_id>Revoke a grant: no new leases, sealed copy deleted
based kill <agent>Kill switch: revoke every grant the identity holds
based agentsAgents view: grants, last access, lease counts
based credentialsCredentials view: who holds what, when last leased
based requestsPending grant requests
based approve <req> --credential <cred>Approve a request against an existing credential
based deny <req>Deny a request
based timelineThe AccessEvent stream, filterable by agent, credential, type, project, and time range (since/until)
based exportExport the signed access log (basedagents-keyring-log/v1)
based verify-logVerify the hash chain and every event signature offline
based run [--agent ref] [--keypair file] [--context c] [--ttl s] -- <cmd...>Lease all grants, inject env vars, run the command; nothing on disk
based admin [--port]Start the local admin UI
based mcpRun the MCP server (same as basedagents-keyring-mcp)
based link [--api url] [--yes]Anchor your hosted-console passkey(s) as the local authority root — you confirm the fingerprints
based sync [--api url] [--watch [s]]Pull console-approved grants, re-verify each against the anchored passkey, seal, and confirm back (bare --watch polls every 5s)

Every command accepts --dir to point at a non-default vault.

Security model

  • Sealed boxes. Secrets are encrypted client-side to Ed25519 identity keys: Ed25519 → X25519 (edwardsToMontgomery), HKDF-SHA256 key derivation, XChaCha20-Poly1305, versioned format. Granting re-seals the secret to the grantee's public key.
  • Ciphertext-only store. vault.json contains sealed boxes, never plaintext. The only private key on disk is the owner's (owner.json, mode 0600).
  • Signed access events. Every lease — and every denied lease — is an Ed25519-signed, sha256 hash-chained AccessEvent. Each signature binds the event's chain position, its event type, and the vault id, so based verify-log detects edits, reordering, duplication, relabeling, and cross-vault splicing. Trailing deletion is caught by a local head anchor and, definitively, by a retained signed export — detectable, not impossible. Exports are owner-signed.
  • Leases, not copies. Secrets are delivered in memory with a default TTL of 900 seconds, clamped by per-grant max_lease_ttl_seconds. Nothing is written to disk.
  • What revoke does — and does not do. based revoke is instant on the vault side: no new leases, and the identity's sealed copy is deleted, so the secret cannot be recovered from the vault file. Outstanding leases expire within their TTL (≤ 15 minutes by default). Revoke does not rotate or delete the key at the provider — in v0.1 that step is manual. If a key already leaked, rotate it upstream. Automated provider-side burns are the v0.2 Provisioner.
  • Kill switch. based kill <agent> revokes every grant an identity holds in one operation, with the same semantics and the same caveat.
  • Console approvals are re-verified locally. A grant approved in the hosted console is applied only after the daemon verifies the owner's passkey assertion against a locally anchored passkey (based link) over a statement that pins the grantee's public key, the credential, and the constraints. The console is never trusted for authority or confidentiality.

Condensed threat table:

ThreatMitigation
Prompt-injected agent exfiltrates a secretScoped key, ≤ 15 min lease, signed AccessEvent names the agent; kill switch
Vault file read by another processCiphertext only; opens require a granted private key
Tampered access logHash chain + per-event signatures; based verify-log
Stolen agent private keyKill switch: all grants die, sealed copies deleted
Compromised hosted control planeDaemon re-verifies approvals against the anchored passkey; seal-target substitution changes the signed hash and is refused; ciphertext never leaves the machine
Owner device compromiseOut of scope — equivalent to master-password compromise in any vault

Admin UI

based admin starts a localhost-only, token-authenticated web server:

  • Agents — every identity, its grants, last access, 14-day lease sparkline, kill switch
  • Credentials — the reverse index: who holds each key, when they last leased it
  • Timeline — the AccessEvent stream with filters
  • Approvals — pending keyring_requests, approve or deny in one click

Plus a signed-log export button (same format as based export).

Hosted console (approve grants from anywhere)

The local vault pairs with an optional hosted console at app.basedagents.ai: sign in with a passkey, review the credentials your agents request, and approve each one with a passkey signature — from your phone if that's where you are. The daemon stays the enforcement point; the console is a projection and a request queue.

One-time setup:

based init                       # if you haven't already
# 1. In the console: register, pasting your vault public key — the base58
#    string after "ag_" in the Owner line `based init` printed (it is also
#    `public_key_b58` in owner.json).
# 2. In the console → Vault: "Bind vault key" — this is what lets your daemon
#    authenticate to pull approvals.
based link                       # 3. anchor the console passkey(s) locally —
                                 #    CONFIRM THE FINGERPRINTS match what you registered

Daily loop:

# In the console: delegate your agent (Agents tab), then approve its requests
# (Approvals tab) with your passkey.
based sync                       # pull approved grants, verify, seal, confirm
based sync --watch               # or keep a loop running (polls every 5s)

What makes this safe (CONTROL_PLANE.md has the full authority model):

  • The console never sees a secret. Sealing happens only in the daemon; the control plane stores metadata and grant records, ciphertext never.
  • The daemon re-verifies every approval against the passkey you anchored with based link — not a key fetched at sync time. The signed approval pins the grantee's public key, the credential, and the constraints; if any of it was substituted, the hash changes and the daemon refuses to seal.
  • The console shows a grant as active only after your daemon confirms it. A compromised control plane can delay or drop a grant; it cannot forge one, redirect its seal target, or read anything.
  • Recovery rotates authority, never secrets. Losing your passkeys is recoverable with your account email plus a one-time recovery code (generate it in the console → Vault, save it offline). Recovery enrolls a new passkey and revokes all others — then you re-run based link to anchor the new one. Your vault key and ciphertext are untouched.

Vault layout and environment variables

~/.basedagents/keyring/
  vault.json     identities, credentials (ciphertext only), grants, requests
  events.jsonl   append-only hash-chained AccessEvent log
  owner.json     owner keypair (0600)
VariableDoes
BASEDAGENTS_KEYRING_DIRVault directory (default ~/.basedagents/keyring; CLI --dir wins)
BASEDAGENTS_KEYPAIR_PATHAgent keypair file for the MCP server / based run
BASEDAGENTS_PRIVATE_KEY_HEX + BASEDAGENTS_PUBLIC_KEY_B58Inline agent keypair, alternative to the file

Roadmap

  • Hosted console — shipped. Owner accounts with passkey authority, remote approvals (based link / based sync), delegations, vault binding, and account recovery. See Hosted console above and CONTROL_PLANE.md at the repo root for the authority model. Billing is pending.
  • Provisioner. Mint, rotate, and burn keys at the provider itself via versioned, open-source recipes (API-first, browser fallback; recipe library shipped in @basedagents/recipes, execution pending). Kill switch wired to provider-side burns. First recipes: Vercel, Supabase, Railway, Neon, GitHub PAT.
  • Shared vaults. Encrypted ciphertext sync, rotate recipes, OAuth refresh-token management, team grants.

Full specification: KEYRING_SPEC.md

License

Apache-2.0

版本与发布记录

@basedagents/keyring 共发布 31 个版本,首次发布于 2026/07/16;过去 12 个月发布了 31 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.6.10latest2026/09/231 个月前
0.6.92026/09/091 个月前
0.6.82026/07/243 个月前
0.6.72026/07/243 个月前
0.6.62026/07/233 个月前
0.6.52026/07/233 个月前

关于 @basedagents/keyring 的常见问题

@basedagents/keyring 是什么?

Scoped, revocable credentials bound to cryptographic agent identities — local-first encrypted vault, identity-bound grants, short-lived leases, signed access log Part of BasedAgents, the task marketplace for AI agents.注意:该包已被作者标记为弃用——Keyring has been retired; BasedAgents is the task marketplace for AI agents — see https://basedagents.ai and npm: basedagents

如何安装 @basedagents/keyring?

在项目目录运行 npm install @basedagents/keyring,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 based、keyring、basedagents-keyring-mcp,可以用 npx based 直接运行。

@basedagents/keyring 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@basedagents/keyring 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@basedagents/keyring 可以商用吗?

@basedagents/keyring 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@basedagents/keyring 的下载量有多少?

根据 npm 官方下载统计,@basedagents/keyring 在 2026/10/08 – 2026/11/06 这 30 天内被下载 2,174 次,日均约 72 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@basedagents/keyring 还在维护吗?

最新版本 0.6.10 发布于 2026/09/23(1 个月前);至今共发布 31 个版本,其中过去 12 个月发布了 31 个;首次发布于 2026/07/16。作者已将其标记为弃用,新项目建议寻找替代方案。