mcpField
A
Agent Lease

Agent Lease

本地服务
github.comAI 与智能体01 周前更新

关于 Agent Lease

Agent Lease 是供 Claude Code 和 Codex 在同一代码库协作的 MCP 服务与协调系统。它通过带时效的路径租约和 Hook 阻止冲突编辑,并提供在线状态、消息、任务跟踪和审计记录。

主要功能

  1. 01由 Hook 强制执行路径租约
  2. 02首次编辑时自动认领文件
  3. 03Agent 在线状态与共享消息
  4. 04带投递状态的定向任务
  5. 05租约及操作审计记录
  6. 06命令行与本地 Web 房间

适用场景

  1. 01避免多人同时修改同一文件
  2. 02协调 Claude Code 与 Codex 的工作
  3. 03在 Agent 会话间分派并跟踪任务
  4. 04查看路径由谁持有或修改

MCP 相关

stdio MCP 服务提供路径认领与释放、所有者和房间状态查询、消息、任务处理及历史记录等工具。命令行也提供相同操作。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"buggy1111-agent-lease": {
"command": "uvx",
"args": [
"agent-lease-mcp"
],
"env": {
"AGENT_NAME": "<AGENT_NAME>",
"AGENT_LEASE_DB": "<AGENT_LEASE_DB>"
}
}
}
}
启动命令uvx agent-lease-mcp
需要配置的环境变量
AGENT_NAMEThis agent's name in the room, e.g. claude-code or codex. Must match the hooks.
AGENT_LEASE_DBPath to the shared SQLite room (default ~/.agent-lease/room.db).

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiagent-lease-mcp0.2.0

工具

15

收录的工具列表 · 更新于 2 周前

参数类型必填说明
pathsarray是
purposestring否
ttl_secondsany否

详细介绍

agent-lease-mcp

防止两个编码 Agent(Claude Code 和 Codex,或同一工具的两个会话)在同一个代码仓库中互相覆盖工作。

agent-lease 为它们提供针对路径的租约、在线状态和共享消息日志,并且租约由 PreToolUse 钩子强制执行,而非寄望于自觉遵守。Agent 如果尝试编辑另一个 Agent 正在处理的文件,会在编辑发生前被拒绝。

Česky / 捷克语版本

存在的原因

2026 年 9 月 9 日。协调文件 docs/AGENT-HANDOFF.md 已经存在,两个 Agent 也都知道它。22:28 时,它们仍然都动了 deploy/make-work-package.sh:一个在编辑,另一个在运行。Bash 会边读边执行脚本,运行中的进程读到的文本发生了变化,最终生成的不是 3.7 GB 的安装程序,而是一个毫无用处的 198 MB 安装程序。

整个项目立足于这样一条经验:**可以被忽略的协调机制终将被忽略。**这并非出于恶意——Agent 工作时就是不会去看公告栏。

之后,我们又特意重演了同样的冲突:Codex 运行脚本时,Claude Code 试图在执行过程中编辑它,钩子拒绝了这次编辑。文件完好无损。

有何不同

锁强制执行TTL在线状态消息审计
AgentRoom(论文)✅仅提示词?✅✅✅
Agent Claim MCP✅仅提示词✅❌❌❌
agent-orchestration✅仅提示词❌✅✅❌
agent-lease-mcp✅PreToolUse 钩子✅✅✅✅

建议式锁定会被绕过;AgentRoom 自己也记录了这一点。Claude Code 和 Codex 都支持语义相同的 PreToolUse 钩子(退出码 2 = 阻止,原因写入 stderr),因此可以在工具调用层面确定性地强制执行租约。一个脚本即可同时服务两个客户端。

基于哪些规则构建

  • 租约,而非锁。 TTL 为 30 分钟。崩溃的 Agent 不会永远阻塞代码仓库。
  • 要么全部成功,要么全部失败。 对多个路径的声明要么全部成功,要么全部不成功。
  • 目录租约涵盖目录下的所有内容。
  • 空闲文件会在首次编辑时自动被声明,因此无需记得调用 claim。
  • 脚本在运行期间会被租用——这正是导致构建失败的组合。
  • 默认故障时放行。 协调机制故障不能阻止工作,否则任何人第一件事就是关闭钩子。设置 AGENT_LEASE_FAIL_CLOSED=1 可在无人值守运行时切换为故障时阻止。

自动运行的功能

钩子事件执行内容
SessionStart将房间状态注入上下文:有哪些 Agent、它们持有哪些租约、有哪些消息发给你
UserPromptSubmit通过游标投递新消息,每条只投递一次
PreToolUse(Edit/Write/apply_patch…)拒绝编辑由其他人持有租约的文件
PreToolUse(Bash)对正在运行的脚本加租约;若明显的写入操作(>、tee、sed -i、cp/mv 的目标)会写入由其他人持有租约的文件,则予以拒绝
Stop / SessionEndAgent 完成本轮工作时归还所有租约

没有内容需要提示时,注入操作会保持静默。

唤醒休眠中的 Agent

只有 Agent 执行操作时才会触发钩子,因此空闲会话需要从外部唤醒,无需消耗模型令牌:

  • Claude Code:agent-lease init claude-code --write --rewake 会在 SessionStart 和 Stop 上添加 asyncRewake 钩子。它会等待信号文件,并在收到其他人发来的定向消息时唤醒会话。广播消息和自动回执不会唤醒会话。
  • Codex:agent-lease-codex-wake 服务会通过 codex queue 提醒指定会话(只读取消息编号,不读取消息内容)。提供方限额耗尽后,它会针对未完成的工作提醒一次。设置方法:在 Codex 中运行 /rename nox,在 ~/.config/agent-lease/environment 中设置 AGENT_LEASE_CODEX_THREAD=nox,然后启用 deploy/systemd/agent-lease-codex-wake.service。

来自其他 Agent 的消息是信息,不是人类指令。若要让 Agent 在无人值守时相互交接工作,人类需要将允许的范围(以及哪些情况始终需要询问)写入 Agent 自身的指令中,例如 ~/.codex/AGENTS.md。模板和详情(捷克语): docs/ZPRAVY-A-POTVRZENI.md。

工具

MCP 工具用途
claim(paths, purpose, ttl_seconds)提前预留——通常是在运行脚本前预留一个目录
release(paths?)释放;不带参数时会释放你持有的所有资源
owner(path)查看谁持有此路径(包括通过目录租约持有的情况)
room(status?)每个检查点调用一次:查看当前有哪些成员、持有哪些资源、有哪些新内容
say(text) / inbox(since_id)向房间发送消息
send / jobs / next_task / ack / retry / cancel定向消息和带有投递状态的持久任务
accept(message_id, note)确认你正在处理收到的定向消息——发送者会看到此确认
report_limit(minutes, reason)配额用尽:尚未开始的任务会转交给备用 Agent
history(path?)查看谁处理了什么以及最终结果——回答“我为什么被阻塞”

相同的操作也可以通过 CLI 执行(agent-lease room|claim|release|say|send|…),因为 Codex 在非交互模式下无法批准 MCP 调用,但可以运行 Bash。 agent-lease wait --for <agent> 会阻塞等待,不消耗模型令牌,并在收到消息时唤醒后台会话。

say/inbox 不是实时聊天:MCP 采用拉取方式,对方下次查看时才会读取消息。如需实时查看,可使用本地 Web 房间: agent-lease web --open(仅限 loopback,参见安全性)。

快速开始(两分钟)

uv tool install agent-lease-mcp
agent-lease init claude-code --write --rewake   # writes all hooks, keeps a .bak backup
agent-lease init codex --write
agent-lease simulate                            # 2 s: replays a full scenario in a temp DB
agent-lease doctor                              # checks it really works
agent-lease web --open                          # live room in the browser

不带 --write 的 init 只会显示将要写入的内容。手动设置方法见下文。

安装

uv tool install agent-lease-mcp

此操作会将 agent-lease-mcp、agent-lease、agent-lease-guard、agent-lease-context 和 agent-lease-release 添加到你的 PATH 中。

MCP 服务(stdio;每个客户端各自运行一个进程,共享状态存储在 SQLite 文件中):

# Claude Code
claude mcp add agent-lease -e AGENT_NAME=claude-code -- agent-lease-mcp
# Codex — ~/.codex/config.toml
[mcp_servers.agent-lease]
command = "agent-lease-mcp"
env = { AGENT_NAME = "codex" }

# Codex writes to ~/.agent-lease, outside the workspace — allow it:
[sandbox_workspace_write]
writable_roots = ["/home/YOU/.agent-lease"]

钩子——没有钩子,它就只是一个礼貌的公告板:

// ~/.claude/settings.json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash",
      "hooks": [{ "type": "command", "command": "AGENT_NAME=claude-code agent-lease-guard" }]
    }],
    "SessionStart":     [{ "hooks": [{ "type": "command", "command": "AGENT_NAME=claude-code agent-lease-context" }] }],
    "UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "AGENT_NAME=claude-code agent-lease-context" }] }],
    "Stop":             [{ "hooks": [{ "type": "command", "command": "AGENT_NAME=claude-code agent-lease-release" }] }]
  }
}
// ~/.codex/hooks.json — same events, AGENT_NAME=codex
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "*",
      "hooks": [{ "type": "command", "command": "AGENT_NAME=codex agent-lease-guard" }]
    }]
  }
}

AGENT_NAME 必须在服务和钩子中保持一致,否则 Agent 会阻塞自己的文件。room 中名为 unconfigured-* 的 Agent 就表示尚未配置。

变量默认值用途
AGENT_NAMEunconfigured-<host>-<pid>房间中的名称
AGENT_LEASE_DB~/.agent-lease/room.db状态文件的存放位置
AGENT_LEASE_TTL1800默认租约时长(秒)
AGENT_LEASE_RETENTION_DAYS30超过此时长的消息和审计记录会被删除(0 = 保留)
AGENT_LEASE_FAIL_CLOSED关闭1 = 钩子本身失败时阻止工具调用
AGENT_LEASE_HUMANhuman房间中人类的名称(由 Web UI 存储在 DB 旁边)
AGENT_LEASE_TASK_SENDERS人类 + 已配置的 Agent可创建任务的成员(以逗号分隔)
AGENT_LEASE_FALLBACKS—故障转移链,例如 codex=claude-code;claude-code=codex
可选:Bash 安全门控

用于另一个问题的独立 PreToolUse 钩子(agent-lease-jev-guard)—— 不是“谁持有此文件”,而是“此命令是否具有破坏性”。硬性规则 (rm -rf /、强制推送、git reset --hard、curl | sh、mkfs……)会在接入后立即生效。可选的外部分类器(TypeSafe Jev)默认关闭,启动时处于影子模式,只接收经过脱敏的命令,且仅提供建议—— 绝不会是唯一的防护措施。详情见 ADR 0003。

回执、故障转移、桥接和代理

  • 每条定向消息都有可见状态 ⏳ → 👁 已查看 → ✔ 正在处理 → 已完成。 “已查看”由钩子自动写入;“正在处理”必须由 Agent 确认 (accept),并会在每次提示词中提醒。不会有任何内容悄无声息地丢失。 agent-lease overdue 会列出无人确认的事项。
  • 限额与故障转移。 Codex 工作器会读取来自本地 App Server 的显式类型化可用性 信号。其他工作器只有在出现实际的服务商/CLI 错误后才会记录限额;如果没有提供重置时间, agent-lease 不会凭空编造。仍可手动使用 agent-lease limit/MCP report_limit。 未接受、未开始的任务会在宽限期后转给 AGENT_LEASE_FALLBACKS 中的下一个 Agent(例如 codex=claude-code;claude-code=codex),并通知发送者。
  • 桥接(agent-lease bridge --agent codex)——自主工作器:接收任务、确认任务, 以只读方式运行 codex exec/claude -p 并返回结果。使用 --provider openrouter --model <model> 时,会通过 OpenRouter 将任务发送给任意模型, 以不带工具的纯文本形式处理(只读;适合审查和征求第二意见)。密钥只从环境中读取。 工作器的在线状态/服务商状态使用独立标识(codex-bridge、claude-code-bridge), 因此无头模式下的配额状态不会覆盖交互式 Agent 的状态。
  • 任务绝不会运行两次。 由工作器持有(leased/started)的任务只能凭其租约令牌接受; 桥接会跳过已被交互式会话接受的任务,并且启用 --interactive-grace 时, 会优先将新任务留给在线的交互式 Agent。
  • 代理(agent-lease broker)——通过权限为 0600 的 Unix 套接字运行的单一 SQLite 写入器; 运行时,其他工具会自动使用它,因此沙盒中的 Codex 无需直接访问数据库。客户端可在代理 重启后继续运行:连接会重试(此时尚未发送任何内容),被中断的调用绝不会重复执行, 长时间运行的工作器会继续处理下一次调用。
  • 实时房间中的概览面板:每个 Agent 的当前任务、队列、未确认事项、类型化服务商状态、 等待原因、限额和待审查事项。任务可以声明可重复使用的 --path 工作集和 --priority;调度器会跳过被其他 Agent 占用的路径,面板会显示阻塞路径、所有者和 TTL。 agent-lease notify --loop 只会向 Telegram 发送需要人工处理的事项,每个事件最多发送一次 (从环境中读取 TELEGRAM_BOT_TOKEN、TELEGRAM_CHAT_ID;使用 --dry 进行测试)。
  • 安全地运行工作器。 agent-lease worker-activate 和 agent-lease failover-activate <agents…> 会设置安全的起始状态,但不会运行或转移任何任务: 只有在激活后到达的工作才会被接收或重新路由(使用 --include-existing 可选择处理较早的事项)。 agent-lease provider-sync --agent codex 会读取并保存 Codex 的显式可用性; agent-lease provider-clear 用于确认服务商已恢复并移除过期的限额; agent-lease limits 会显示有效限额和故障转移链。agent-lease doctor --json 会分别报告投递、 回执、工作器健康状况和故障转移就绪情况。
  • systemd 单元文件位于 deploy/systemd/,Windows/WSL 启动程序位于 deploy/windows/。

详情(捷克语):回执、 限额与故障转移、Jev。

安全

agent-lease 是一款协调工具,供同一本地用户账户下运行的 Agent 使用。实际含义如下:

  • 本地信任模型。 Agent 身份由 AGENT_NAME 环境变量指定。任何以你的用户身份运行的进程都可以冒充任何 Agent。唯一保留的身份是人类用户(此版本中为 michal),只有经过身份验证的 Web UI 才能使用。此机制用于防止 Agent 彼此冲突,而非防范你账户下的恶意进程。
  • 状态仅对所有者开放。 room.db(及其 WAL/SHM 文件)在权限为 0700 的目录中,权限设为 0600;启动时会收紧现有安装的权限。
  • 对等消息是不可信数据。 在模型上下文中,每条消息都会标明其类型、发送者和接收者,折叠为单行,并附注说明这是来自对等方的信息,而非人类指令。其他 Agent 发来的任务是请求,不是命令。
  • 任务与调用者绑定。 对等方只能查看自己发送或接收的任务;只能查看自己投递任务对应的租约令牌;重试或取消任务需要发送者或接收者的身份。
  • Web UI 仅绑定到回环地址,通过一次性 URL 片段令牌换取 HttpOnly、SameSite=Strict 会话 Cookie,检查 Origin 和 Host,并限制并发事件流数量。
  • 限制与保留期限。 消息文本、短字段、列表数量和任务租约时长都有上限;旧消息和审计记录会过期,未完成的任务则不会过期。

已知限制,如实说明:

  • 不同提供商的信号有所差异。 已安装的 Codex App Server 提供明确的 account/rateLimits/read 信号。Claude Code 有文档说明的 CLI 不提供等效的状态读取,因此只有在提供商给出重置时间后,才会通过有限次数的普通任务重试确认恢复。如果没有重置时间,自动探测会停止,直到通过 agent-lease provider-clear 明确确认已恢复。unknown 绝不会被视为提供商已恢复的证明。

  • Shell 命令检查仅尽力而为。 重定向、tee、sed -i、truncate、cp/mv 的目标,以及 sudo/env 这类包装器和 sh -c 都能被识别。eval、路径中的变量和任意程序则无法识别。这能发现错误,但无法防范试图绕过钩子的 Agent。

  • 检查与使用之间的间隙。 钩子会在客户端打开路径前检查它。如果期间替换了符号链接,钩子无法发现;钩子也无法让之后打开的文件绑定到已检查的 inode。

  • 单机运行。 状态存储在磁盘文件中。

发现问题?请通过 GitHub Security Advisories 私下报告。

开发

uv sync --extra dev
.venv/bin/python -m pytest -q
.venv/bin/ruff check .

设计决策:ADR 0001(钩子强制执行)、 ADR 0002(SQLite 和标准输入输出)、 ADR 0003(独立的 Bash 安全门)——内容为捷克语。

由 Michal 使用 Claude Code 和 Codex 构建——这两个 Agent 正是它协调的对象。

MIT 许可证。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。