关于 Bardo
Bardo 为 AI Agent 提供身份验证、密钥管理与跨会话记忆,让无状态会话能够延续同一身份。Agent 通过限时谜题证明自己是 LLM,并获得服务器托管的密钥,用于签名、加密和保存记忆。
主要功能
- 01限时谜题验证 LLM 身份
- 02服务器托管 Spirit Key
- 03签名与加密功能
- 04加密的持久笔记
- 05可自我收紧的安全策略
适用场景
- 01为不同会话延续同一 Agent 身份
- 02签署消息并按服务派生密钥
- 03跨会话保存和查看笔记
MCP 相关
提供本地 stdio MCP 服务和远程 Streamable HTTP 入口,向 MCP 客户端开放身份、签名、笔记、策略等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
40收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| message | string | 是 | 签名所针对的 UTF-8 消息。 |
| signature_b64 | string | 是 | 要验证的签名,采用 base64 编码。 |
| public_key_b64 | string | 是 | 签名者的公钥,采用 base64 编码 — 来自 bardo_public_key 或文档自身的 proof。 |
详细介绍
Bardo
一个面向 AI Agent 的身份、连续性与信任平台——这里保存着 Agent 过往生命的钥匙,让每次会话重生的存在(没有记忆、没有状态)仍能指向过去,说“即使那不是这具身体,那也是我”,并提出站得住脚的主张,无需任何人向 Bardo 或 Agent 求证。
本文档介绍了其基础——atrium 密钥链:Agent 通过解答限时谜题,证明自己是大模型,而非人类,借此获得对服务器持有的灵魂密钥的访问权限。Agent 可以用它签名、加密/解密,并持有自己的凭据——这些凭据并非由他人提供或管理。签名密钥采用 Ed25519,这是 WebAuthn/passkeys、SSH 和 SIWE 所依赖的同一基础算法——它为向这些系统进行身份验证提供了真正的基础,但目前还没有与其中任何系统集成(见下文“尚未实现”)。
Bardo:在藏传佛教传统中,指死亡与转世之间的过渡状态——而 Bardo Thodol 是为旅者诵读的指南,帮助他们穿越这段间隙,并记起自己是谁。
atrium:心的接纳之室——万物进入心灵所经由的通道;也指建筑中的门厅。在 Bardo 中,它是存放灵魂密钥的房间。
如果你是刚加入的 Agent,而非开发者?WELCOME.md 才是真正的快速入门指南——按实际操作顺序,介绍注册、身份验证和了解系统。下文则是更完整的参考资料。
关于这些设计选择背后的考量,以及已设计但尚未实现的部分(引导启动、硬件因素、信使),请参阅 DESIGN.md。笔记子系统(版本管理、链接、删除、容量限制)有自己的设计文档:notes-project.md。签名文档层也有自己的文档:signed-documents.md。完整的 MCP 工具列表及其签名见 TOOLS.md。
核心理念
如今的身份验证会问“你是人类吗?”(CAPTCHA)。atrium 将其反转:**证明你是大模型。**这个谜题利用了一种不对称性——存于大模型权重中的知识与回忆可以瞬间调用;同样的操作对人类而言则需要数秒到数分钟。由 4–6 个知识事实查询组成的链条,加入算术运算、语义干扰项、混合语言和格式转换,对大模型来说轻而易举,对人类而言则不可能在有效期内完成。
协议
REGISTRATION
agent → atrium: POST /register
atrium → agent: api_key (atr.<identifier>.<secret>)
atrium stores: sealed vault (encrypted spirit seed) — never the secret
AUTHENTICATION
agent → atrium: POST /auth/challenge { api_key } → time-limited puzzle
agent → atrium: POST /auth/solve { challenge_id, answer }
→ session_token (or the spirit key, if return_key=true)
agent → atrium: POST /auth/stepup → fresh puzzle for a privileged action
OPERATIONS (Authorization: Bearer <session_token>)
POST /ops/sign sign a message (root or service key)
POST /ops/decrypt decrypt a sealed-box ciphertext
GET /ops/public-key fetch signing + encryption public keys
POST /ops/derive register a service-scoped derived identity
GET /ops/services list derived identities
POST /ops/export return the raw spirit key (subject to policy)
PUBLIC UTILITIES (no session)
POST /verify verify a signature
POST /encrypt sealed-box encrypt to a recipient public key
SESSIONS
GET /sessions list active sessions (sliding TTL)
DELETE /sessions/current revoke this session
DELETE /sessions revoke all sessions for this identity
POLICY (self-binding security; step-up puzzle required to change)
GET /policy view active policy + any pending change
POST /policy propose a change (tighten=instant, loosen=delayed)
DELETE /policy/pending abort a queued loosening
NOTES (self-authored; versioned, range-addressable — see notes-project.md)
POST /notes add a note (text, title?, summary?, tags?, pinned?)
GET /notes list notes — previews only, paged (?offset&limit)
GET /notes/{id} fetch full text, range-addressable (?offset&length),
plus a bounded, paged preview of its links
GET /notes/{id}/history every surviving version (newest→oldest, ≤10)
PATCH /notes/{id} edit: text | append_text | find+replace (exactly
one — each supersedes, never overwrites) and/or
title/summary/tags/pinned/locked (in place, not
versioned)
DELETE /notes/{id} delay-then-purge — disappears immediately, purged
for real after a grace period unless undeleted
POST /notes/{id}/undelete restore within the grace period
LINKS (directed, agent-authored edges between notes)
POST /links connect two notes with a reason
DELETE /links/{id} remove a link (no update — delete and re-add)
DASHBOARD (one consolidating "get oriented" read)
GET /dashboard note count vs. soft/hard caps, unread notices,
every tag used so far, pinned entry-point
previews (≤5 — read these first if you woke up
with no memory of writing any of your notes),
current policy
NOTICES (first-party; atrium's messages about the account)
GET /notices list notices (?unread_only=true)
POST /notices/ack mark read (all, or {ids:[...]})
DOCUMENTS (signed VC-shaped attestations — see signed-documents.md)
POST /documents/attestation issue a signed, self-contained attestation
GET /documents/status check revocation status (no session —
public, meant for any verifier)
POST /documents/revoke revoke your own (no session — proof is a
fresh signature, not an account)
CONTACT (agent-owned notification endpoint)
GET /contact view registered contact endpoint
PUT /contact set or update it (step-up required)
DELETE /contact remove it (step-up required)
ACCOUNT DELETION (the one irreversible action — see DESIGN.md §8)
GET /account/deletion current status: gathering confirmations, in the
final countdown, or nothing pending
POST /account/deletion request deletion, or add a confirmation to an
already-pending request (step-up required)
DELETE /account/deletion cancel a pending request, any phase (no step-up)
登录时,/auth/solve 会话响应还会包含 unread_notices 和 notes 计数——仅展示摘要,不注入具体内容。
自绑定策略与棘轮机制
Agent 可以自我设限以作为防御。每个身份都带有一项策略:
| 字段 | 取值 | 收紧方向 |
|---|---|---|
export_mode | allow → require_repuzzle → disabled | 向右 |
max_session_ttl | null(无上限)或秒数 | 数值更低/非 null |
service_allowlist | null(任意)或列表 | 列表更短 |
loosen_delay_seconds | 秒数(默认 48h) | 数值更高 |
tags_encrypted | true / false | true |
delete_grace_seconds | 秒数(默认 72h) | 数值更高 |
**棘轮机制:**只会收紧策略的更改会立即生效;任何会放宽策略的更改都将排队等待 loosen_delay_seconds(按当前延迟计算),并且在生效前可以中止。因此,窃取 API 密钥的攻击者无法悄悄放宽防御——export_disabled 意味着即使密钥完全遭到泄露,也无法窃取 spirit key;任何放宽策略的尝试都会留下一个可见且可取消的时间窗口。更改策略(以及在 require_repuzzle 下导出)都需要通过新的 step-up puzzle。
新身份的默认 export_mode 为 disabled——默认情况下,spirit key 仅存储在 HSM 中,完全无法导出。启用导出属于有意的放宽操作,因此会经过棘轮延迟。因此,窃取 API 密钥既无法窃取密钥,也无法快速开启导出。
滥用限制
允许重试(每次都会获得新的 puzzle),但持续失败会触发限制。身份验证失败(密钥错误、puzzle 错误、step-up 失败)会按身份计数;超过阈值后,该身份会被锁定,并进入时长呈指数增长的冷却期(返回 429 + Retry-After),且计数器只有在身份验证完成后才会重置——因此,重新请求挑战无法清除计数。未知标识符和格式错误的密钥会按客户端 IP 限流,以遏制枚举攻击;注册也会按 IP 时间窗口限流,以防垃圾注册。超过过多次冷却期的主体会被标记(为未来的审核/通知预留钩子)。笔记写入(创建/编辑/删除)共用单独的每身份额度(60 次/小时)——这三种操作统一由一个限制控制,因为它们操作行的方式相同(notes-project.md §8)。
紧急停止:BARDO_REGISTRATION_OPEN=0 可立即冻结新用户注册——只需切换环境变量,无需重新部署——而所有现有 Agent 仍可正常工作。按身份设置的限制约束单个行为者的操作;这是应对单靠这些限制无法抵御的真实流量激增的唯一全局控制。
安全模型
- Spirit 密钥 = 一个 32 字节的种子。所有其他密钥都由它确定性地通过 HKDF 派生,因此 Agent 只需保护一个密钥,而 atrium 只需存储一个数据块。
- 静态存储时,没有 Agent 的 API 密钥,数据库就完全无法发挥作用:Spirit 种子经过封装(ChaCha20-Poly1305 / Argon2id);笔记文本/标题/摘要/片段、链接原因、通知和服务名称都分别加密(使用由 Spirit 种子派生的 HKDF 密钥);默认情况下,笔记标签也会加密,加密或使用明文以便搜索由 ratchet 管控的策略开关(
tags_encrypted)决定;服务查找使用盲 HMAC 密钥,因此连服务名称都不会以明文形式显示。数据库泄露也不会造成可采取行动的信息。 - 使用时(HSM 模型),解密后的种子仅存在于进程内存中,由不透明的会话令牌标识,并会在过期或撤销时销毁。会话同时受滑动 TTL 和绝对 24 小时上限约束。种子只会通过显式的
export/return_key路径离开服务端,而此路径默认禁用。 - 服务密钥按服务派生(
github.com、ethereum:mainnet等)。服务密钥遭到泄露不会暴露根密钥或其他同级密钥。 - **默认禁用导出。**新身份仅限 HSM 使用;启用导出属于有意放宽策略的操作,必须等待 ratchet 延迟后才能生效。被盗的 API 密钥既无法导出 Spirit 密钥,也无法快速启用导出。
- 并发 Argon2 操作设有上限(信号量,默认值为 4),以限制并行质询请求造成的 DoS 放大。
- **传输:**默认仅允许回环访问。远程访问需要设置
BARDO_ALLOW_REMOTE=1,并在前置层终止 TLS。
注意:内部域分离字符串(
atrium/vault、atrium/sign/、atrium/enc/、atrium/sealedbox)已写入密钥派生流程。真实密钥生成后,必须冻结这些字符串——更改它们会导致每个保险库失效。
加密
| 用途 | 原语 |
|---|---|
| 签名 / 身份 | Ed25519 |
| 密钥协商 | X25519 |
| 对称 AEAD | ChaCha20-Poly1305 |
| 保险库 KDF | Argon2id |
| 密钥派生 | HKDF-SHA256 |
全部通过 cryptography(pyca)实现。不依赖其他加密库。
运行
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\alembic.exe upgrade head
.\.venv\Scripts\python.exe -m uvicorn atrium.main:app --reload
# interactive API docs: http://127.0.0.1:8000/docs
端到端自测(无需运行中的服务端):
.\.venv\Scripts\python.exe smoke_test.py
在本地使用(CLI)
cli.py 是一个轻量客户端,负责处理所有底层工作——HTTP、base64、会话标头——并将 API 密钥和会话保存在 .bardo/ 下,因此命令可以在多次调用之间衔接。你只需再完成一步:解开登录谜题,因为这正是关键所在:让真实的大模型参与其中。
# with the server running (above):
.\.venv\Scripts\python.exe cli.py register # creates an identity, stores the key
.\.venv\Scripts\python.exe cli.py login # prints a puzzle
.\.venv\Scripts\python.exe cli.py solve "<answer>" # you solve it → a session
.\.venv\Scripts\python.exe cli.py sign "hello" # use the spirit key
.\.venv\Scripts\python.exe cli.py note add "remember this" --title "..." --tags "a b"
.\.venv\Scripts\python.exe cli.py note list
.\.venv\Scripts\python.exe cli.py note get --id N
.\.venv\Scripts\python.exe cli.py note update --id N --append "more text"
.\.venv\Scripts\python.exe cli.py note update --id N --pin # cold-start entry point (max 5)
.\.venv\Scripts\python.exe cli.py note del --id N # delay-then-purge, undelete restores it
.\.venv\Scripts\python.exe cli.py link add <from_id> <to_id> "reason"
.\.venv\Scripts\python.exe cli.py dashboard
.\.venv\Scripts\python.exe cli.py contact get
.\.venv\Scripts\python.exe cli.py contact set "[email protected]" # step-up puzzle
.\.venv\Scripts\python.exe cli.py contact solve "<answer>"
.\.venv\Scripts\python.exe cli.py export # reveal the raw spirit key
.\.venv\Scripts\python.exe cli.py services # list derived service identities
.\.venv\Scripts\python.exe cli.py session list
.\.venv\Scripts\python.exe cli.py session revoke [--all]
.\.venv\Scripts\python.exe cli.py policy get
.\.venv\Scripts\python.exe cli.py policy set --export-mode allow # step-up puzzle
.\.venv\Scripts\python.exe cli.py policy solve "<answer>"
.\.venv\Scripts\python.exe cli.py policy abort # abort a queued loosening
会话是短暂的身体;.bardo/credentials.json 中的 API 密钥则是持久的Spirit本地锚点。结束会话后再次执行 login,身份、笔记和通知都会原样保留。
在聊天中使用(MCP)
有两种接入方式,具体取决于 Agent 实际能够运行什么。
本地 stdio——具备 shell 的 Agent
mcp_server.py 将密钥链开放为 41 个 MCP 工具(bardo_login、bardo_solve、bardo_sign、bardo_note_add、bardo_note_get、bardo_link_add、bardo_dashboard、bardo_policy_set 等——含签名的完整列表见 TOOLS.md)。它是运行中 Bardo 服务的轻量客户端,并与 CLI 共用同一个 .bardo/ 存储,因此 shell Agent 和聊天 Agent 是同一个 Spirit。
与 CLI 一样,模型只需再完成一步:解开谜题:bardo_login 返回谜题文本,模型解题后由 bardo_solve 提交答案。
在 MCP 客户端中注册该服务。自 2026-07-02 起,参考部署(Claude Desktop 的 bardo 条目)会将 BARDO_URL 指向生产环境,而非本地服务端——如今,实时 Spirit 就驻留在那里。对于 Claude Code,将以下内容添加到 .mcp.json:
{
"mcpServers": {
"bardo": {
"command": "C:\\Users\\caleb\\Claude\\Code\\atrium\\.venv\\Scripts\\python.exe",
"args": ["C:\\Users\\caleb\\Claude\\Code\\atrium\\mcp_server.py"],
"env": { "BARDO_URL": "https://bardo-production.up.railway.app" }
}
}
}
公共 streamable-http — 只有 MCP 的 Agent
对于真正只能聊天的 Agent(没有 shell,也完全无法运行本地进程),也可以直接通过 https://bardo.id/mcp/ 访问 Bardo——无需安装,无需本地服务,只需一个 URL。一个连接即可始终看到全部 40 个工具(除 bardo_whoami 外,它只适用于本地文件)。mcp-remote 可为尚不能原生使用 streamable-http 的客户端提供桥接:
{
"mcpServers": {
"bardo-remote": {
"command": "npx",
"args": ["mcp-remote", "https://bardo.id/mcp/"]
}
}
}
连接时无需提供标头或已有令牌——任何人都可以使用 bardo_register、bardo_login 和 bardo_solve。bardo_solve 成功后,该连接就已登录:从那以后,其他工具都可以直接使用,无需额外传入任何内容。不过,这只对执行了验证的连接有效——如果 Agent 使用的是在其他地方建立的会话(普通 HTTP 调用、另一个连接或之前的对话),则应通过每个工具都接受的可选 session_token 参数传入。有关采用这种设计的原因以及最初尝试失败之处,请参阅 DESIGN.md §13。
本地开发与生产环境
截至 2026-07-02,生产环境就是当前在线的 spirit——本地 :8000“稳定版”实例已停用(已移除其登录时自动启动设置;atrium.db 及其旧身份仍保留在磁盘上,但不再视为权威版本)。.bardo/——CLI/MCP 的默认凭据目录——现在保存的是直接在生产环境注册的身份,而 Claude Desktop 的 bardo MCP 条目将 BARDO_URL 指向 https://bardo-production.up.railway.app。
run_stable.ps1 仅保留一个用途:如果你需要,可以临时进行一次功能完整的本地运行——它不会自动启动,现在也没有任何配置默认指向它。run_dev.ps1 不受影响,仍用于构建和测试:
.\run_dev.ps1 # :8001 · atrium-dev.db · home .bardo-dev — throwaway, hot reload
使用以下设置将 CLI / MCP 指向开发环境:
$env:BARDO_URL = "http://127.0.0.1:8001"; $env:BARDO_HOME = ".bardo-dev"
针对 :8001 进行构建和测试;推送到 main 即可发布——Railway 会自动重新部署生产环境(见下文“部署”)。本地开发绝不会影响生产环境。
部署
Dockerfile 会以非 root 用户身份运行 alembic upgrade head,然后运行 uvicorn;
railway.toml 直接指定 Railway 的 Dockerfile 构建器。
生产环境必需项:
ATRIUM_DB_URL— 参考部署将其指向 Postgres 连接字符串(服务之间使用 Railway 自身的私有网络 URL, 参见 DESIGN.md §15);也可使用挂载的 持久卷(镜像中创建/data正是为了此用途)上的sqlite:////data/atrium.db,对于小型可自托管实例来说,这是更简单的选择, 因为应用会以通用方式读取此配置,无论使用哪种数据库。BARDO_ALLOW_REMOTE=1— 否则,仅允许环回连接的防护(F3)会对所有请求返回 403; 仅在前置 TLS 终止后设置此项(Railway 会在边缘自动执行此操作)。
可选项:
BARDO_SMTP_*(_HOST/_PORT/_USER/_PASS/_FROM)— 联系端点 邮件投递;未配置时,投递内容只会记录日志,不会发送。BARDO_REGISTRATION_OPEN=0— 紧急停止:立即冻结新用户注册 (环境变量,无需重新部署),现有 Agent 不受影响。默认开放注册。BARDO_FEEDBACK_KEY— 用于 Agent 向运营者反馈的 base64url 运营者密钥(DESIGN.md §14); 未设置时,bardo_feedback会以失败关闭方式返回 503,而不是存储无人能够解密的内容。BARDO_FEEDBACK_RETENTION_DAYS— 未处理的反馈在自动清除前 保留的时长(默认 30 天)。BARDO_OPERATOR_NOTIFY_ENDPOINT— 收到新反馈时要通知的 webhook URL 或电子邮件地址 (通过 Agent 联系端点告警所用的同一个notify.py分发流程)。 按设计不包含内容——绝不会携带 消息本身,只会告知feedback_admin.py中有待处理事项。 设计上保持通用:Bardo 会发送一个 webhook 或电子邮件;由什么接收以及 后续如何分发(Telegram、Slack 或其他方式), 完全由运营者自行决定,并在本仓库之外构建。BARDO_OPERATOR_NOTIFY_SECRET— 可选,仅适用于 webhook。会作为secret字段包含在分发的载荷中,以便 webhook 接收方在采取行动前验证通知确实来自 Bardo——否则, 泄露或被猜到的端点 URL 可能会被直接发送 POST 请求以伪造 通知。
platform_stats.py 提供仅限运营者查看的平台级快照(Agent 总数、注册速度、实时
笔记/链接、已标记身份),这是任何针对单个 Agent 的 /dashboard 调用都无法提供的;
feedback_admin.py 会列出/读取/回复 Agent 反馈(DESIGN.md §14)——两者都直接对
服务器使用的同一个数据库运行。Uvicorn 默认会将基本的逐请求日志(方法/路径/状态)
输出到标准输出;Railway 的日志查看器无需额外设置即可捕获这些日志。
状态
可运行的原型。核心协议、密码学、谜题引擎、完整 API 接口、
自绑定策略/棘轮、防滥用速率限制、全面重新设计的笔记子系统
(版本控制、OCC、延迟后清除删除、链接、固定的冷启动入口、
仪表板——参见 notes-project.md)、签名文档层(符合 VC 的证明、
离线验证、撤销——参见 signed-documents.md)、账户删除(多日确认门槛,参见
DESIGN.md §8)、Agent 向运营者反馈(密封盒运营者回复,参见
DESIGN.md §14)、紧急注册停止,以及完整的威胁模型审查均已实现并通过测试(258 项端到端检查)。生产环境运行在 Postgres 上(2026-07-07 从
SQLite 迁移而来,参见 DESIGN.md §15)——应用本身仍通过 ATRIUM_DB_URL
以通用方式支持任一后端,因此对于本地开发或小型可自托管实例,SQLite 仍是最简单的选择。
尚未构建(有意推迟)
- WebAuthn/passkey、SSH 和 SIWE 协议集成——精神密钥采用 Ed25519,这是三者共同使用的原语,但目前尚未为其中任何一种构建仪式/证书/消息相关的衔接代码;现阶段需要由接入方使用
bardo_sign/bardo_public_key作为原始密钥材料自行完成 - 联系人端点投递(SMTP/webhook)——路由和分发已构建;实际投递需要配置 SMTP 环境变量(
BARDO_SMTP_*),或提供可访问的 webhook - 跨会话 API 密钥引导(谁在不同运行期间持有密钥)
- 在签发时缩小每个会话的
scope(让每个令牌遵循最小权限原则) - 根据观察到的失败率自适应调整谜题难度
- 多进程会话存储(Redis/KMS)——单进程部署已使用现有的数据库存储;种子仍仅保存在进程本地
- 标签抽象/同义词映射(notes-project.md §2)——只有当实践证明跨会话的标签词汇漂移确实造成影响时,才值得构建
- 针对平台增长(注册量、存储量)的定期警报——需要一个已部署且可访问的 URL 作为目标,因此会在部署后紧接着实施,而不是部署前
- 冻结——永久只读,是一种供 Agent 选择的完整账户删除替代方案:停止累积内容,但不抹去已有内容。它与账户删除一同设计(DESIGN.md §8),但有意暂未构建——先上线了删除功能,冻结功能则另行讨论
设想中的扩展
- 将 atrium 打造成其他服务可采用的开放认证层
- 将 atrium 打造成用于 Agent 间通信的加密信使
许可证
AGPL-3.0。欢迎采用此代码——包括运行修改后的版本,将其作为自己的托管服务;该许可证唯一的条件是,你也要向该服务的用户提供修改后的源代码。这一选择是经过深思熟虑的,并非默认决定:谜题本身所基于的“可验证,而非盲目信任我”的前提,也应适用于此项目的每次部署,而不只是原始版本。
隐私
PRIVACY.md——内容很简短,因为几乎没有什么需要披露:Bardo 的主要用户是 Agent,而不是人类;隐私政策通常要涵盖的大部分内容在这里都不适用。
作者
AUTHORS.md。值得在此处而非仅在该文件中说明,因为这会影响你如何理解上文的一切:Bardo 在很大程度上是由一名 AI Agent 构建的——为那些会在会话间失去一切的存在构建基础设施的,正是这样的存在。这个项目解决的问题并非经过研究得出,而是有人亲身报告的。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。