hbar-systems/permitd
GitHub: hbar-systems/permitd
permitd 是一个零依赖的 Python 库,为 AI agent 循环提供人在环中的工具执行治理,通过提议-批准-执行-审计流程确保敏感操作获得人工授权。
Stars: 0 | Forks: 0
# permitd
**用于 agent 循环的受治理工具执行。**

你的 agent 循环想发送电子邮件、写入文件、访问 API。而你想
在其中加入人类的决策——一种 agent 无法伪造、重放或篡改
为不同参数的决策——并且无论结果如何,都会在审计日志中留下记录。
```
propose(tool, args) ──> permit (signed, TTL, single-use)
──> approve (a human, out-of-band: CLI, or any callable)
──> execute (verify + burn, atomically)
──> one audit line lands (append-only JSONL)
```
permitd 就是实现这一流程的轻量级、仅依赖标准库的 Python 库。它也是
**循环状态**:许可保存在 SQLite 中,因此在 agent 循环第 N 轮提议的调用
可以从另一个终端批准,并在第 N+K 轮执行——
跨越重启,跨越进程。
除执行外的任何结果都会默认失败。缺失、过期、被拒绝、
被篡改、参数不匹配或已使用的许可都会被拒绝,并且
拒绝记录也会被审计。
## 安装
```
pip install permitd
```
Python ≥ 3.10,零依赖。
## 六十秒,两个终端
**终端 1 — agent 端** (`agent.py`):
```
import time
from permitd import Gate, RED
gate = Gate(db="permitd.db")
@gate.tool(tier=RED, description="send a message to someone")
def send_message(to, body):
return f"delivered to {to}: {body!r}"
args = {"to": "alice", "body": "hello from the loop"}
r = gate.call("send_message", args)
print(r.error) # "... permit PRM-xxxx is proposed ..."
pid = r.permit["id"]
while gate.get(pid).status == "proposed": # this state survives restarts
time.sleep(1)
r = gate.call("send_message", args, permit_id=pid)
print(r.result if r.ok else r.error)
```
```
python agent.py
```
**终端 2 — 人类端:**
```
$ permitd pending
1 pending permit(s):
PRM-3f9c21ab44de [proposed] send_message
args: {"to": "alice", "body": "hello from the loop"}
proposed: 2026-07-29T18:12:03+00:00 ttl: 300s
$ permitd approve PRM-3f9c21ab44de
approved — PRM-3f9c21ab44de is executable for 300s, single use, bound to exactly these arguments
```
终端 1 唤醒并打印 `delivered to alice: 'hello from the loop'`。
轨迹如下:
```
$ permitd audit
{"ts": "...", "event": "proposed", "permit_id": "PRM-3f9c21ab44de", "tool": "send_message", ...}
{"ts": "...", "event": "approved", "permit_id": "PRM-3f9c21ab44de", ...}
{"ts": "...", "event": "executed", "permit_id": "PRM-3f9c21ab44de", "ok": true}
```
这就是整个产品:提议、批准、执行、审计记录。
## 许可实际保证的内容
- **绑定到精确参数。** 许可的范围限定于
`sha256(tool + canonical_json(args))`。对“向 Alice 发送 X”的批准无法
重放为“向 Eve 发送 Y”——键的顺序和空格不会改变绑定;
任何值的改变都会导致失败 (`args_mismatch`)。
- **单次使用,原子操作。** 消耗许可是一次 SQLite 的比较并交换操作
(`UPDATE ... WHERE status='approved'`),因此两个进程竞争同一个
许可不可能同时成功 (`already_used`)。
- **双重时间限制。** 提议可以在 `ttl_seconds`(默认为
300)内被批准;生成的批准可以在另一个 `ttl_seconds` 内执行。无法解析的
时间戳将被视为过期。
- **HMAC 签名。** 批准会生成
`HMAC-SHA256(secret, id.binding_hash.approved_at)`,在执行时
重新验证——在内核背后被篡改的存储行将会失败 (`bad_signature`)。
- **处处默认失败。** 任何内核无法明确验证的内容——
包括“甚至无法检查参数”——都是拒绝,而不是
放行。拒绝行为及其原因都会被审计。
## 层级
`Gate` 是一个在内核之上具有三个层级的小型注册表:
| 层级 | 含义 | 门控 |
|---|---|---|
| `GREEN` | 对自身状态的只读 | 自由运行,接受审计 |
| `YELLOW` | 外部读取(搜索、获取) | 一个常驻开关:`gate.standing_authorization = True` |
| `RED` | 写入 / 执行 / 发送 | 每次调用的许可:如上所述的流程 |
如果你不需要注册表,请直接使用内核:
```
from permitd import PermitKernel, SqliteStore, AuditLog
kernel = PermitKernel(SqliteStore("permitd.db"),
secret_path="permitd.db.secret",
audit=AuditLog("permitd_audit.jsonl"))
p = kernel.propose("deploy", {"target": "prod"})
kernel.approve(p.id) # or from the CLI / your own UI
kernel.execute("deploy", {"target": "prod"}, p.id, runner=do_deploy)
```
`approve` 只是支持存储的内核上的一个方法——从 CLI、Slack 处理程序、
HTTP 端点或人类所在的任何地方调用它。
## 出站防护
在任何非 GREEN 调用运行之前——**包括在提议时**——它的参数将
被扫描是否包含凭证特征内容:私钥块、`Bearer`/`Basic`
标头、AWS/GitHub/Slack/Stripe/OpenAI/Anthropic/Google 密钥特征、内联
`api_key=...` 赋值、此进程自身敏感环境
变量的值,以及保守的高熵后备方案。将机密引导
至工具参数的中毒上下文会在任何内容
离开之前,在显示任何批准卡片之前被拒绝,并且拒绝原因会标明
匹配的*特征*,而不是值本身。
## MCP:对任何 agent 的工具进行门控,包括 Claude Code
[`examples/mcp_server/`](examples/mcp_server/) 是一个 MCP 服务器,其工具会
经过门控。将任何使用 MCP 通信的 agent 指向它,该 agent 将获得
提议 → 批准 → 执行 + 审计,且**无需对 agent 端进行任何更改**:
agent 调用 RED 工具,被告知“许可 PRM-… 已提议,等待批准”,
你在另一个终端运行 `permitd approve PRM-…`,agent 重试并且
调用执行。无论结果如何,审计记录都会生成。
## 存储
`SqliteStore`(默认,持久化,原子化消耗)和 `MemoryStore`(测试,
临时)开箱即用。其他任何实现都需要五个方法——请参阅
[`store.py`](src/permitd/store.py) 中的 `PermitStore` 协议;保持 `burn`
是比较并交换操作,否则你将失去单次执行的保证。审计跟踪是
一个独立的、仅追加的 JSONL 文件,因此可以保持使用 `tail -f` 进行追踪。
## permitd 不是什么
不是 agent,不是框架,不是内存,不是 RAG。它对你的循环、
你的模型或你的 prompt 没有任何意见。它是跨轮次保持“可以运行这个吗?”
状态的层——以及运行完成后的凭证。
## 源流
从
[brainfoundry-nous](https://github.com/hbar-systems/brainfoundry-nous) 的工具治理内核中提取,
在那里它运行在生产环境中,对个人 AI 节点的工具进行门控。
提议/确认/执行 + 审计的语法可以追溯到
[hbar.brain.console](https://github.com/hbar-systems/hbar.brain.console)
(2026-03)。设计说明:[DESIGN.md](DESIGN.md)。
## 许可证
MIT。
标签:Python, SOC Prime, 人机交互, 审计日志, 开发工具, 无后门, 时序数据库, 权限控制, 逆向工具