Skip to main content
Glama
Zorabi

Concordia

by Zorabi

Concordia

面向 Codex 与 ZCode 的 local-first MCP 多代理协作控制面,支持单机 stdio 与可选的跨机器 Redis relay。

Concordia 以结构化任务、事件、租约和 Git worktree,将“规划与验收”与“实施”分开:Codex 创建任务、回答问题、审查交付;ZCode 原子领取任务、实施、按需使用其子代理,并提交可审查的 commit 与验证证据。状态保存在协调主机的本地 SQLite;双方既可在单机直接连接,也可在都没有公网 IP 时通过 Redis 中转。

它适合在一台机器或“远程 Codex + ZCode 执行主机”的两机拓扑中,可靠地协调一个或少量 Git 仓库,不依赖 GitHub Issue 或共享在线文档。

它解决什么问题

  • 任务是契约:目标、目标仓库、允许路径、约束、验收条件与交付项均为结构化字段。

  • 事件是沟通:进度、提问、回答、心跳、失败、返工和批准都是带序号的持久事件。

  • 提交是证据:ZCode 提交的 SHA、变更文件、检查结果和风险进入任务记录,供 Codex 审查。

  • 租约防止双写:过期重领后旧执行者会被围栏拒绝,不能继续写入事件或提交。

  • worktree 隔离写入:每次领取使用独立 Git branch/worktree,避免并发任务互相污染。

  • 桌面原生执行:ZCode 插件的 /worker 在当前 Desktop 任务中建立持久 Goal,领取、实施和提交结果都留在可见会话里。

  • 一次配置,多仓库共享:单机默认使用用户级 ~/.concordia/state.db,无需为每个业务仓库同步修改 Codex/ZCode 配置。

Related MCP server: SafeFlo

边界与非目标

当前版本面向单协调节点、同一可信用户或团队、少量并发任务。已实现 SQLite 持久化、任务状态机、Git 隔离、幂等写入、租约恢复、ZCode 插件、Codex 事件唤醒器,以及基于 Redis Streams 和角色签名的跨机器 relay。尚不提供:

  • 多用户身份、仓库级 ACL 或租户隔离;

  • 多协调节点高可用或 PostgreSQL;

  • 多个独立 ZCode 执行机之间的路径映射和 Git 对象传输;

  • Web Dashboard 或面向第三方的通用推送订阅;

  • 自动合并、推送远程 Git、发布制品或部署;

  • 强制 ZCode 使用某个子代理,或替代理制订实现计划;

  • 映射为 ZCode 原生侧边栏任务。

合并、推送、发布与生产操作须由用户或上层协调者明确执行。

架构

单机模式

Codex ── stdio MCP ─┐
                    ├── Concordia ── SQLite(任务、事件、交付物)
ZCode ── stdio MCP ─┘        │
                              ├── 目标 Git 仓库/.worktrees/<task>-zcode-a<attempt>
                              ├── codex-waker ──> Codex App Server(按事件启动审查 turn)
                              └── ZCode Desktop /worker Goal(可见地持续领取与实施)

跨机器 Redis 模式

Codex MCP relay client ──┐
                         ├── 出站 TLS ──> Redis Streams/response keys
ZCode MCP relay client ──┘                         │
                                                  │ 出站连接
                                      Concordia relay coordinator(ZCode/Git 主机)
                                                  ├── 本机 SQLite
                                                  └── 本机 Git 仓库与 worktrees

远程模式必须把协调器部署在持有目标 Git 仓库的执行主机上。两端只需主动连接同一 Redis,无需公网 IP 或入站端口;claim_task 和 submit_task 仍在协调主机执行本机 Git/worktree 强校验。详细部署、令牌、Codex/ZCode 配置和安全限制见 跨机器协调指南。

这里有两个不同的目录:

  • Concordia 源码目录:本仓库,包含 src/、构建产物与 zcode-plugin/;例如 /absolute/path/to/concordia。

  • 被管理的目标 Git 仓库:代理真正修改的业务项目;例如 /absolute/path/to/example-app。任务 workspace 必须是它的 Git 根目录。worktree 创建在这个目标仓库内,而非 Concordia 源码目录。

单机模式下,Codex 与 ZCode 的 stdio MCP 进程默认都打开当前用户的 ~/.concordia/state.db,与客户端当前仓库或进程 cwd 无关。只有需要隔离多个 Concordia 控制面时才设置 CONCORDIA_HOME 或 CONCORDIA_DB。跨机器模式下,SQLite 只保留在协调主机本地,远程客户端通过 Redis relay 访问,禁止多台机器直接打开网络共享目录中的 SQLite 文件。

状态生命周期

DRAFT 是协议中保留的类型;当前 create_task 会直接创建并发布为 READY。

READY ── claim ──> CLAIMED ── progress ──> RUNNING ── submit ──> REVIEW
                                             │                       │
                                             ├─ question ─> WAITING_INPUT
                                             │               └─ answer ─> RUNNING
                                             ├─ failed ───> FAILED
                                             ├─ cancelled ─> CANCELLED
                                             └──────────────── request_changes ─> READY(重新领取)
                                                                approve ─────────> APPROVED

终态为 APPROVED、FAILED、CANCELLED。只有 Codex 能创建、审批或要求返工;只有 ZCode 能领取和提交任务。

前置条件

  • Node.js 22.13+(使用 node:sqlite)。

  • Git,且每个目标工作区必须是可访问的 Git 仓库根目录。

  • npm。

  • 可使用 Codex 和/或 ZCode 的 MCP 功能。

  • 跨机器模式额外需要 Redis 7+ 或兼容服务;单机模式不需要 Redis 服务。

node --version
git --version
npm --version

安装、构建与运行

在 Concordia 源码目录执行:

npm install
npm run build
npm test

构建产生:

  • dist/src/index.js:本机 stdio MCP 服务;

  • dist/src/relay.js:运行在 ZCode/Git 主机上的 Redis relay coordinator;

  • dist/src/codex-waker.js:运行在 Codex 主机上的事件监听与 App Server 唤醒进程;

  • dist/src/zcode-waker.js:运行在 ZCode 主机上的事件监听与 ZCode CLI 唤醒进程;

  • zcode-plugin/dist/index.mjs:随 ZCode 本地插件分发的单文件 bundle。

服务使用 stdio,通常由 MCP 客户端启动。以下命令只用于验证进程可启动,随后会等待标准输入上的 MCP 客户端:

CONCORDIA_AGENT_ID=codex \
npm start

MCP 协议仅写 stdout;启动与错误日志写 stderr。默认数据库为 ~/.concordia/state.db,因此同一系统用户下的 Codex 与 ZCode 会自动共享状态。

若希望 Codex 在 ZCode 提交、提问或失败时自动恢复审查任务,而不是让模型持续调用 wait_events,启动可选事件唤醒器:

CONCORDIA_TRANSPORT=stdio \
npm run start:waker

waker 空闲时只运行 Node.js 事件循环,不调用模型。完整配置、跨机器路径规则、可靠性语义和故障排查见 Codex 事件唤醒器指南。 可复制的环境变量起点见 .env.waker.example。

希望结果留在 ZCode Desktop 时,在一个可见任务中运行插件命令 /worker。它会建立持久 Goal,并在当前 Desktop 会话内反复调用 wait_events、领取和实施任务。MCP 是被客户端调用的工具协议,本身不能主动创建模型 turn;因此 Desktop 原生 Goal 才是推荐的持续执行入口。详见 ZCode Desktop 工作器。

旧的外置 zcode-waker 仍作为无界面兼容模式保留:

CONCORDIA_TRANSPORT=stdio \
npm run start:zcode-waker

zcode-waker 通过 CLI 执行,不保证结果出现在当前 ZCode Desktop 任务中;对桌面工作流不要启动它。详见 ZCode 事件唤醒器指南。

跨机器协调器使用:

CONCORDIA_CONFIG_FILE=/absolute/path/to/concordia.config.json \
CONCORDIA_DB=/absolute/path/to/state.db \
CONCORDIA_REDIS_URL='rediss://user:password@redis.example.com:6379/0' \
CONCORDIA_RELAY_NAMESPACE='team-a' \
CONCORDIA_RELAY_CODEX_TOKEN='<至少 32 字符的随机 token>' \
CONCORDIA_RELAY_ZCODE_TOKEN='<另一个至少 32 字符的随机 token>' \
npm run start:relay

协调器不监听入站 HTTP 端口,只主动连接 Redis。跨网络使用 rediss://,完整配置见 跨机器协调指南。

配置

变量

必填

默认值

说明

CONCORDIA_TRANSPORT

否

stdio

MCP 客户端传输模式:stdio 直接访问本机状态,redis 通过中转。

CONCORDIA_AGENT_ID

是

无

只允许 codex 或 zcode;角色不匹配的工具会被拒绝。

CONCORDIA_HOME

否

~/.concordia

单机共享状态目录;同时决定默认任务库和 waker 状态库位置。

CONCORDIA_CONFIG_FILE

否

无

可选的仓库范围加固配置;设置时优先于 CONCORDIA_ROOTS,每次工作区授权校验加载。Redis client 不设置。

CONCORDIA_CONFIG_STALE_GRACE_MS

否

5000

配置运行时读取失败后允许继续使用 last-known-good 的毫秒数,范围 0–60000;超出后 fail-closed。

CONCORDIA_ROOTS

否

无

可选的旧版允许根目录列表;仅在未设置 CONCORDIA_CONFIG_FILE 时使用。

CONCORDIA_DB

否

~/.concordia/state.db

显式覆盖本机 SQLite 路径;Redis client 不设置,绝不能跨机器共享。

CONCORDIA_REDIS_URL

Redis 模式

无

Redis URL;远程默认要求 rediss://。

CONCORDIA_RELAY_NAMESPACE

否

concordia

隔离不同部署的 Redis 键,1–64 个安全字符。

CONCORDIA_RELAY_CODEX_TOKEN

Codex relay/协调器

无

Codex 请求 HMAC token,至少 32 字符。

CONCORDIA_RELAY_ZCODE_TOKEN

ZCode relay/协调器

无

ZCode 请求 HMAC token,至少 32 字符且与 Codex token 不同。

可选仓库范围加固

默认不再维护仓库白名单:Codex 只能创建任务,ZCode 只能领取已发布任务;两者仍受 Git 根校验、任务 ownedPaths、排除路径、worktree 和租约围栏约束。信任边界是运行 MCP 的本机用户及其文件系统权限,因此新增任何本机可访问 Git 仓库都不需要改配置或重启。

如果部署环境需要额外限制 Concordia 可操作的目录,再启用共享 roots 配置。复制 concordia.config.example.json 到一个不提交进业务仓库的稳定绝对路径,例如 /Users/me/.config/concordia/roots.json:

{
  "version": 1,
  "allowedRoots": [
    "/Users/me/src"
  ]
}

allowedRoots 的每一项都必须是存在的绝对目录;启用后,每个任务的 workspace 必须是其中某项之内的 Git 根目录。给所有本机组件设置同一个 CONCORDIA_CONFIG_FILE 即可共享这一额外边界。

服务会在每次工作区授权校验时重新读取此文件:在已有根目录下新增或移除仓库后,无需改两端 MCP 配置或重启服务。移除根目录会立即阻止该范围内的新任务、存量任务访问和 waker 后续唤醒。撤权被视为信任边界:重新加入后会恢复 API 访问,但撤权期间被全局 waker 游标越过的旧事件不会自动补发;需要继续的任务应发送新的适用事件或重新创建。首次添加此变量、变更其路径,或更新 MCP/waker/relay 的其他环境变量时,仍须重启相应进程。

首次加载无效或文件不可读时,服务会失败且不会退回到 CONCORDIA_ROOTS。已经成功加载过的进程若运行时读取失败(包括 JSON 无效、文件暂不可读或根目录无效),只会在 CONCORDIA_CONFIG_STALE_GRACE_MS 的宽限期内继续使用 last-known-good(默认 5000 ms,设为 0 即立即拒绝);超过宽限期后工作区授权会 fail-closed。配置修复后,下一次工作区授权校验自动恢复,无需重启。

更新时先在同一目录写入临时文件,验证 JSON 后用原子 rename 替换正式文件,避免读到半写入内容。例如:

mkdir -p /Users/me/.config/concordia
chmod 700 /Users/me/.config/concordia
cp concordia.config.example.json /Users/me/.config/concordia/roots.json.tmp
chmod 600 /Users/me/.config/concordia/roots.json.tmp
mv /Users/me/.config/concordia/roots.json.tmp /Users/me/.config/concordia/roots.json

目录和文件应仅允许运行这些进程的用户读取和修改(通常目录 0700、文件 0600)。不要把配置文件放入 Git、同步盘或所有用户可写的目录;能改此文件的主体可扩大 Concordia 可操作的仓库范围。

旧版根目录变量

尚未迁移时仍可使用:

CONCORDIA_ROOTS=/Users/me/src/project-a,/Users/me/src/project-b

路径范围字段 ownedPaths、excludedPaths、changedFiles 必须使用相对工作区的 POSIX 路径,例如 src/api,不要使用反斜杠。

接入 Codex 与 ZCode

下面使用一组固定示例路径。配置时请把它们全部替换为你机器上的真实绝对路径:

含义

本节示例值

Concordia 源码目录

/Users/me/tools/concordia

被管理的目标 Git 仓库

/Users/me/src/example-app

默认双端共享数据库

/Users/me/.concordia/state.db

先完成一次构建并确认两个入口文件存在:

cd /Users/me/tools/concordia
npm install
npm run build

test -f /Users/me/tools/concordia/dist/src/index.js
test -f /Users/me/tools/concordia/zcode-plugin/dist/index.mjs
git -C /Users/me/src/example-app rev-parse --show-toplevel

最后一条命令应输出 /Users/me/src/example-app。如果输出的是其他目录,应把后续配置中的目标仓库路径改成实际 Git 根目录。

在 Codex 中配置

Codex 桌面应用、CLI 和 IDE 扩展在同一 Codex host 上共用 MCP 配置。配置文件可放在全局 ~/.codex/config.toml,也可放在可信目标项目的 .codex/config.toml。以下方式任选一种,详见 Codex MCP 官方文档。

方式 A:编辑 config.toml(推荐)

将以下内容追加到 ~/.codex/config.toml。如果只想让服务器在一个项目中可用,则追加到 /Users/me/src/example-app/.codex/config.toml:

[mcp_servers.concordia]
command = "node"
args = ["/Users/me/tools/concordia/dist/src/index.js"]
enabled = true
startup_timeout_sec = 20
# wait_events 最长等待 60 秒,工具超时需略大于 60 秒。
tool_timeout_sec = 70

[mcp_servers.concordia.env]
CONCORDIA_TRANSPORT = "stdio"
CONCORDIA_AGENT_ID = "codex"

注意:

  • args 指向 Concordia 源码构建出的 dist/src/index.js,不是目标项目中的文件。

  • CONCORDIA_AGENT_ID 在 Codex 端必须是 codex。

  • 默认状态库与当前仓库无关;任务的 workspace 可以是当前用户可访问的任意 Git 根目录。

  • 需要额外范围限制时,再同时给 Codex 与 ZCode 添加同一个 CONCORDIA_CONFIG_FILE。

保存后重启 Codex MCP server:桌面应用可进入 Settings → MCP servers,找到 concordia 后选择 Restart;CLI 或 IDE 扩展可重新启动会话。然后在 Codex 会话中输入 /mcp,应能看到 concordia 及其 8 个工具。

方式 B:使用 Codex CLI 添加

如果本机安装了 Codex CLI,可以运行:

codex mcp add concordia \
  --env CONCORDIA_TRANSPORT=stdio \
  --env CONCORDIA_AGENT_ID=codex \
  -- node /Users/me/tools/concordia/dist/src/index.js

codex mcp list

CLI 写入的也是 Codex MCP 配置。默认用户级状态路径不依赖 MCP 进程从哪个目录启动。

Codex 端验证

在一个新的 Codex 会话中要求它“调用 Concordia 的 list_tasks”。若返回任务列表或空数组,说明连接成功。Codex 端具有读取权限,并可调用 create_task、以 sender: "codex" 发送 ANSWER/CANCELLED,以及调用 review_task;它不能领取或提交任务。

在 ZCode 中配置

推荐以 User scope 安装仓库内置插件,因为它会同时提供 Concordia MCP server 和 /tasks、/task、/watch、/worker 命令,并在所有工作区使用同一用户级状态库。参见 ZCode Plugin 文档和 ZCode MCP 文档。

插件安装后的待办查看、任务领取、事件监听和提交操作,详见 ZCode 使用指南。

方式 A:安装 Concordia 插件(推荐)

本仓库根目录的 marketplace.json 已将 zcode-plugin/ 声明为可安装插件。操作步骤:

  1. 先按前文执行 npm run build,确保 zcode-plugin/dist/index.mjs 存在。

  2. 在 ZCode 中打开目标项目 /Users/me/src/example-app,不要把 Concordia 源码目录当作目标项目打开。

  3. 打开 Settings → Plugins。如果页面提示先打开 workspace,请先完成上一步。

  4. 点击右上角 Create → Add marketplace。

  5. 本地开发时选择目录 /Users/me/tools/concordia;发布 GitHub 后也可以填写 Concordia 仓库 URL。

  6. 在 Personal 区域找到 concordia-local marketplace,再找到 concordia 插件,点击 Install 并确认已启用。

  7. 打开 Settings → MCP Servers,在 Plugin MCP servers 分组确认 plugin:concordia:concordia 已启用。

  8. 新建一个 ZCode 会话,输入 /tasks。能够返回任务表或“没有匹配任务”即表示插件和 MCP 都已加载。

插件内置的 zcode-plugin/.mcp.json 为:

{
  "mcpServers": {
    "concordia": {
      "type": "stdio",
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/dist/index.mjs"],
      "env": {
        "CONCORDIA_TRANSPORT": "stdio",
        "CONCORDIA_AGENT_ID": "zcode"
      },
      "enabled": true,
      "timeoutMs": 70000
    }
  }
}

其中:

  • ${CLAUDE_PLUGIN_ROOT}(也可写成 ${ZCODE_PLUGIN_ROOT})由 ZCode 替换为已安装插件目录。

  • 未设置 CONCORDIA_DB 时,插件和 Codex 都使用 ~/.concordia/state.db。

  • 插件不再把 MCP 权限或状态绑定到 ${CLAUDE_PROJECT_DIR},因此切换或新增仓库无需修改配置。

  • timeoutMs 略大于 wait_events 允许的最长 60 秒等待,避免正常长轮询被客户端提前中止。

修改 Concordia 或插件源码后,应重新运行 npm run build,然后在 ZCode 的 Marketplace sources 中刷新 concordia-local。如果插件已经被复制进 ZCode 缓存而非直接引用源码,刷新或重新安装后再开新会话。

方式 B:只手动添加 MCP server

不需要斜杠命令时,可在 ZCode 中打开 Settings → MCP Servers → New MCP Server,选择 User scope,切换到 Full configuration,粘贴以下 JSON:

{
  "mcpServers": {
    "concordia": {
      "type": "stdio",
      "command": "node",
      "args": ["/Users/me/tools/concordia/zcode-plugin/dist/index.mjs"],
      "env": {
        "CONCORDIA_TRANSPORT": "stdio",
        "CONCORDIA_AGENT_ID": "zcode"
      },
      "enabled": true,
      "timeoutMs": 70000
    }
  }
}

也可以手动写入用户级 ~/.zcode/cli/config.json:

{
  "mcp": {
    "servers": {
      "concordia": {
        "command": "node",
        "args": ["/Users/me/tools/concordia/zcode-plugin/dist/index.mjs"],
        "env": {
          "CONCORDIA_TRANSPORT": "stdio",
          "CONCORDIA_AGENT_ID": "zcode"
        },
        "enable": true
      }
    }
  }
}

ZCode 的用户级配置位于 ~/.zcode/cli/config.json。本工具建议使用用户级配置;保存后在 MCP 列表确认服务器已启用,并新建会话测试 list_tasks。

双端联通验证

  1. 分别启动或重启 Codex 与 ZCode 中的 concordia MCP server。

  2. 在 Codex 中调用 create_task 创建一个目标仓库为 /Users/me/src/example-app 的任务。

  3. 在 ZCode 中运行 /tasks,或要求 ZCode 调用 list_tasks。

  4. 如果 ZCode 能看到刚创建的任务,说明两端正在使用同一数据库。

  5. 若看不到,检查两端是否覆盖了不同的 CONCORDIA_HOME/CONCORDIA_DB;默认情况下不应配置这两个变量。

插件提供的 /tasks、/task <task-id>、/watch <task-id> 是只读辅助命令;/worker 会在当前 ZCode Desktop 任务内持续领取、实施和提交。

切换为跨机器 Redis relay

只有需要跨设备时才设置 CONCORDIA_TRANSPORT=redis。远端 Codex 的最小配置为:

[mcp_servers.concordia]
command = "node"
args = ["/Users/me/tools/concordia/dist/src/index.js"]
enabled = true
startup_timeout_sec = 20
tool_timeout_sec = 80

[mcp_servers.concordia.env]
CONCORDIA_AGENT_ID = "codex"
CONCORDIA_TRANSPORT = "redis"
CONCORDIA_REDIS_URL = "rediss://user:password@redis.example.com:6379/0"
CONCORDIA_RELAY_NAMESPACE = "team-a"
CONCORDIA_RELAY_CODEX_TOKEN = "<至少 32 字符的 Codex token>"

ZCode/Git 机器需要另外运行 npm run start:relay。ZCode MCP 可设置同一个 Redis URL 与 namespace、使用独立的 CONCORDIA_RELAY_ZCODE_TOKEN;也可在协调主机继续用默认 stdio,直接连接协调器所用的本机 SQLite。Redis 模式下,任务 workspace 一律填写 ZCode/Git 机器上的绝对路径。

可直接复制的 ZCode JSON、协调器命令、Redis ACL/TLS 要求和联通步骤见 跨机器协调指南。

MCP 工具

工具返回 JSON 内容及结构化结果。业务错误统一形如 { code, message, retryable, details? }。每次写操作都需唯一 idempotencyKey(最长 256 字符);完全相同的重试返回原结果,不重复写入。

工具

角色

作用与关键输入

create_task

Codex

创建并发布 READY 任务。输入 spec 和 idempotencyKey。

claim_task

ZCode

原子领取任务;可按 taskId 精确领取事件对应任务,或按 workspace 筛选最早匹配任务;leaseSeconds 为 1–3600(默认 60)。无任务返回 { task: null };成功包含 leaseToken。

get_task

两者

获取任务契约、状态、租约摘要、交付物、提交记录与近期事件;eventLimit 默认 20、最大 100。

list_tasks

两者

以 status、assignee、workspace、updatedAfter、limit 筛选;默认 20、最大 100。

send_event

两者

追加授权事件;可带 expectedVersion。ZCode 的写入必须带当前 leaseToken。

wait_events

两者

查询 afterEventId 后的新事件,最长等待 60 秒(默认 30 秒);超时返回空数组。

submit_task

ZCode

提交当前 attempt worktree 的 HEAD commit、精确变更列表、检查、风险和摘要,转入 REVIEW。

review_task

Codex

对 REVIEW 任务 approve 或 request_changes;返工至少需要一条 finding。

send_event 权限:

发送者

可发送事件

Codex

ANSWER、CANCELLED

ZCode

PROGRESS、QUESTION、AGENT_STATUS、HEARTBEAT、FAILED

TASK_CREATED、TASK_CLAIMED、COMPLETED、CHANGES_REQUESTED、APPROVED 由专用工具生成,不能经 send_event 伪造。

任务契约

{
  id: string;                 // 字母数字开头,最多 128 字符,可含 . _ -
  objective: string;
  workspace: string;          // 目标 Git 仓库根目录,不是 Concordia 源码目录
  baseCommit?: string;        // 省略时创建时解析为目标仓库 HEAD 的完整 SHA
  ownedPaths: string[];       // 至少一个相对路径
  excludedPaths?: string[];
  constraints: string[];
  acceptance: string[];       // 至少一项
  deliverables: ("commit" | "changed_files" | "checks" | "risks")[];
  delegation: { mode: "auto" | "disabled"; maxConcurrency: number; maxDepth: 1 };
  timeoutSeconds: number;
}

baseCommit 在创建时解析为完整 SHA。timeoutSeconds、delegation.mode 与 maxConcurrency 目前是被验证和保存的契约信息,不会由运行时自动杀死、调度或限流代理;maxDepth 必须为 1。

提交检查只接受以下 commandId 白名单:build、format-check、git-diff-check、lint、npm-build、npm-lint、npm-test、npm-typecheck、test、typecheck。Concordia 记录检查证据,不会执行 payload 中的 shell 命令。

leaseToken、attempt 与 worktree

租约与 fencing token

claim_task 成功结果中的 leaseToken 是当前执行权的短期凭据。ZCode 必须把它带入后续每个 send_event(包括 HEARTBEAT)及 submit_task。token 不会进入 get_task、事件、提交记录或日志;不要回显、提交或持久化它。

默认租约 60 秒。长任务应在到期前用 HEARTBEAT 续租,并可传 leaseSeconds(1–3600)。租约过期后另一个领取者可以接手,服务会颁发新 token;旧 token 被围栏拒绝。expectedVersion 是可选的乐观并发控制,适合读—改—写过程。

提交进入 REVIEW 时租约立即失效。Codex 要求返工后任务回到 READY;ZCode 必须再次调用 claim_task,在新 attempt worktree 中继续,并使用新 leaseToken。旧 token 永远不能恢复使用。

每个 attempt 的独立工作区

每次领取创建或复用该尝试专属路径:

<目标 Git 仓库>/.worktrees/<task-id>-zcode-a<attempt>/

对应分支为 concordia/<task-id>-zcode-a<attempt>。首次从 baseCommit 建立;租约过期后的新 attempt 从上一次 worktree 的已提交 HEAD 快照恢复(没有可恢复 worktree 时从 base commit 开始)。旧 attempt 目录不会被新 attempt 重用。

ZCode 必须修改 claim_task 返回的 task.worktreePath,而不是目标仓库的原始检出目录。 提交时服务验证:

  1. 目标仓库/worktree 均在允许根目录内,且不存在符号链接逃逸;

  2. baseCommit 仍解析为原完整 SHA,提交历史从其演进;

  3. 提交 SHA 是当前 attempt worktree 的完整、不可变 HEAD;

  4. changedFiles 与 Git diff 精确一致;

  5. 最终 diff、所有中间提交及未提交改动仅触及 ownedPaths,且不触及 excludedPaths。

端到端示例

假设目标仓库为 /absolute/path/to/example-app。单机默认下两端会自动连接同一用户级 ~/.concordia/state.db,不需要在目标仓库创建或配置数据库。以下 JSON 是 MCP 工具参数,不是 shell 命令。

  1. Codex 获取目标仓库基准并调用 create_task:

    git -C /absolute/path/to/example-app rev-parse HEAD
    {
      "spec": {
        "id": "docs-api-001",
        "objective": "为 API 客户端补充使用文档",
        "workspace": "/absolute/path/to/example-app",
        "baseCommit": "<完整 SHA>",
        "ownedPaths": ["docs", "README.md"],
        "excludedPaths": [".github"],
        "constraints": ["不要修改运行时代码"],
        "acceptance": ["文档包含安装与 API 示例", "npm test 通过"],
        "deliverables": ["commit", "changed_files", "checks", "risks"],
        "delegation": { "mode": "auto", "maxConcurrency": 1, "maxDepth": 1 },
        "timeoutSeconds": 1800
      },
      "idempotencyKey": "docs-api-001:create:v1"
    }
  2. ZCode 领取并保存返回的 task.worktreePath 与 leaseToken。由 zcode-waker 唤醒时必须传入事件对应的 taskId,避免领取另一个 READY 任务:

    { "agentId": "zcode", "taskId": "docs-api-001", "workspace": "/absolute/path/to/example-app" }
  3. 在返回的 attempt worktree 工作,并用 token 上报进度:

    {
      "taskId": "docs-api-001",
      "sender": "zcode",
      "recipient": "codex",
      "type": "PROGRESS",
      "payload": { "phase": "writing", "summary": "正在编写 API 示例" },
      "idempotencyKey": "docs-api-001:progress:writing",
      "leaseToken": "<领取结果的 leaseToken>"
    }

    该事件将 CLAIMED 变为 RUNNING。需要澄清时发送 QUESTION;Codex 用 ANSWER 回复,任务从 WAITING_INPUT 返回 RUNNING。长任务发送 HEARTBEAT 续租。

  4. 在 返回的 worktree 中完成、验证、提交:

    cd /absolute/path/to/example-app/.worktrees/docs-api-001-zcode-a1
    npm test
    git add docs README.md
    git commit -m "docs: add API client guide"
    git rev-parse HEAD
  5. ZCode 调用 submit_task。commit 为完整 SHA,changedFiles 必须与 baseCommit..commit diff 完全一致:

    {
      "taskId": "docs-api-001",
      "leaseToken": "<领取结果的 leaseToken>",
      "commit": "<完整提交 SHA>",
      "changedFiles": ["README.md", "docs/api-client.md"],
      "checks": [{ "commandId": "npm-test", "exitCode": 0, "summary": "npm test passed" }],
      "risks": [],
      "summary": "补充 API 客户端安装、认证和调用示例。",
      "idempotencyKey": "docs-api-001:submit:1"
    }
  6. Codex 用 get_task 读取交付证据并审查 diff,之后调用 review_task:

    {
      "taskId": "docs-api-001",
      "decision": "approve",
      "summary": "文档内容和测试证据已核对。",
      "idempotencyKey": "docs-api-001:approve:1"
    }

    返工时使用 decision: "request_changes" 并给出至少一个 { path?, line?, severity, message } finding。任务会回到 READY,ZCode 需要重新领取。批准只表示任务协议完成,不会自动合并 worktree branch;后续合并、cherry-pick 或丢弃由用户或上层协调者决定。

ZCode 命令

命令

用途

/tasks [status]

列出当前工作区近期任务;可按一个或多个状态过滤,显示 ID、状态、执行者、更新时间和目标。

/task <task-id>

显示任务契约、状态、路径范围、验收条件、租约摘要、交付证据与近期事件。

/watch <task-id>

读取当前事件游标后循环 wait_events 显示新事件;终态、用户中止或达到观察限制时停止。

/worker

在当前 ZCode Desktop 任务中建立持久 Goal,持续领取、实施、验证并提交 Concordia 任务。

前三个命令只查询或观察;/worker 是 Desktop 原生执行入口。

安全模型

Concordia 的默认边界是“同一本机用户/可信团队 + 结构化任务范围”,不是完整的多租户平台。已实现的约束包括:

  • 必须显式声明 codex 或 zcode;工具和事件发送者均做角色校验;

  • 工作区必须为真实 Git 根;可选的 allowedRoots/CONCORDIA_ROOTS 可进一步限制目录范围;

  • 路径范围拒绝绝对路径、..、反斜杠、Git/Concordia 控制目录和越界符号链接;

  • worktree 及既有目录会解析真实路径,防止逃离目标仓库;

  • SQLite 使用外键、WAL、事务和任务 version 乐观锁;事件 idempotency key 全局唯一;

  • leaseToken 使用时序安全比较,轮换后旧领取者无法继续写入;

  • Redis relay 使用分角色 HMAC-SHA256 签名、时间戳、nonce 防重放、响应 TTL 和单协调器锁;

  • 远程 Redis 默认强制 rediss://,角色 token 与 Redis 凭据均不进入日志;

  • submit_task 不执行任意命令;只记录白名单检查 ID 的结果;

  • 业务错误不回显环境变量、凭据或完整命令输出。

任何能读写本地数据库、Git 工作区、Redis 数据或 MCP 配置的用户仍在同一信任域。跨机器生产部署应使用 Redis ACL 和 TLS。

测试与开发

npm run typecheck  # 严格 TypeScript 类型检查
npm run build      # 编译服务并打包 ZCode 插件
npm test           # build 后运行 Node 内置测试

若本机有测试 Redis,可额外执行真实 relay 往返测试:

CONCORDIA_TEST_REDIS_URL=redis://127.0.0.1:6379 npm test

测试覆盖完整领取—运行—提交—返工重领—批准流程、并发领取、幂等、租约恢复、fencing token、数据库重启持久化、事件等待、两个 waker 的游标与投递恢复、Codex App Server 与 ZCode CLI 生命周期、基准提交验证、worktree 恢复、relay 签名/权限/TLS 校验,以及路径/符号链接/提交历史范围校验。

详见:系统设计、开发指南、ZCode 使用指南、Codex 事件唤醒器指南与 ZCode 事件唤醒器指南。

目录结构

concordia/                         # Concordia 源码目录
├── src/
│   ├── index.ts                   # stdio MCP server 与 8 个工具
│   ├── protocol.ts                # 类型、验证、错误模型
│   ├── database.ts                # SQLite 初始化、迁移、事务
│   ├── paths.ts                   # 用户级共享状态路径
│   ├── events.ts                  # 事件追加、查询、有界等待
│   ├── tasks.ts                   # 状态机、租约、幂等、交付验证
│   ├── workspace.ts               # Git/worktree、路径范围
│   ├── relay-protocol.ts          # relay 签名信封与安全校验
│   ├── relay-client.ts            # Redis 模式 MCP client
│   ├── relay.ts                   # Redis Streams coordinator
│   ├── codex-app-server.ts        # Codex App Server JSONL 客户端
│   ├── zcode-cli.ts               # ZCode headless CLI 客户端
│   ├── waker-source.ts            # SQLite/Redis 共享事件源
│   ├── codex-waker.ts             # 事件过滤、唤醒与重试循环
│   ├── zcode-waker.ts             # ZCode CLI 事件唤醒与重试循环
│   └── waker-state.ts             # 独立游标、线程和投递状态库
├── tests/                         # 核心、relay、CLI 与 waker 测试
├── marketplace.json               # ZCode 本地/GitHub marketplace 入口
├── zcode-plugin/                  # 可加载的 ZCode 本地插件
│   ├── .mcp.json
│   ├── .zcode-plugin/plugin.json
│   └── commands/                  # /tasks、/task、/watch、/worker
├── docs/
│   ├── zcode-usage.md            # ZCode 待办、监听与执行指南
│   ├── zcode-desktop-worker.md   # ZCode Desktop 原生工作器
│   ├── codex-waker.md            # Codex 事件驱动唤醒与部署
│   ├── zcode-waker.md            # ZCode 事件驱动唤醒与部署
│   ├── design.md
│   └── development.md
├── package.json
├── concordia.config.example.json  # 热加载共享允许根目录配置模板
├── .env.waker.example             # Codex waker 环境变量模板
├── .env.zcode-waker.example       # ZCode waker 环境变量模板
└── tsconfig.json

<目标 Git 仓库>/
└── .worktrees/<task>-zcode-a<attempt>/  # Concordia 运行时创建

本仓库 .gitignore 忽略 node_modules/、dist/、.concordia/、.worktrees/ 和 TypeScript 构建缓存。

开源协议

Concordia 使用 MIT License 开源。你可以自由使用、复制、修改、合并、发布和分发本软件,但必须保留原始版权与许可声明。本软件按“原样”提供,不附带任何明示或默示担保。

故障排查

现象

处理

CONCORDIA_AGENT_ID is required

为 MCP server 设置 CONCORDIA_AGENT_ID=codex 或 zcode。

CONCORDIA_CONFIG_FILE 加载失败

确认路径为可读的绝对路径、JSON 符合 { "version": 1, "allowedRoots": ["/absolute/path"] },且每一根目录存在。运行中修复后会在下一请求生效。

配置持续加载失败后请求被拒绝

在 CONCORDIA_CONFIG_STALE_GRACE_MS(默认 5000 ms)内修复或原子替换配置;超过该期限会 fail-closed,修复后下一次工作区授权校验自动恢复。

WORKSPACE_DENIED

确认 workspace 是可访问的真实 Git 根且没有越界软链接;若启用了 roots 加固,再检查目标路径是否在范围内。

两端看不到彼此任务

检查是否有一端覆盖了不同的 CONCORDIA_HOME/CONCORDIA_DB;默认两端均应使用 ~/.concordia/state.db。

Redis relay request timed out

确认协调器运行中,Redis URL、数据库编号和 namespace 一致,ACL 允许所需命令。

远程 redis:// 被拒绝

生产环境改用 rediss://;只有可信开发网络才设置 CONCORDIA_RELAY_ALLOW_INSECURE=true。

claim_task 返回 task: null

没有匹配的 READY 任务,也没有过期可恢复任务;用 list_tasks 查看。

LEASE_CONFLICT

token 不正确、租约过期或已被重领。重新领取,切勿复用旧 token。

STALE_VERSION

读取后任务被其他写操作改变;重新 get_task 后继续。

BASE_COMMIT_MISMATCH

基准 SHA 无法解析或尝试历史不从其演进;检查 Git 历史和任务 baseCommit。

PATH_SCOPE_VIOLATION / 提交被拒绝

核对 ownedPaths/excludedPaths;最终 diff、中间提交与未提交改动必须全部在允许范围内。

提交不是当前 HEAD

在当前 task.worktreePath 中提交,并传 git rev-parse HEAD 的完整 SHA。

SQLite 初始化被锁定

稍后重试;初始化有有限重试。若持续发生,检查异常进程是否占用同一数据库。

waker.event_failed 反复出现

检查 Codex CLI 登录、App Server、Codex 端 Concordia MCP 与 waker.db 中的 last_error。

当前限制

  • 当前版本为 0.6.0,package.json 标为 private: true,尚未作为 npm 包发布。

  • Node 的 node:sqlite 在部分 Node 22 发行版可能显示实验性 API 警告;采用前请按自身 Node 策略评估。

  • Redis relay 当前只支持单活动协调器,不提供多协调器高可用、远程备份或自动清理旧 attempt worktree。

  • timeoutSeconds、delegation.maxConcurrency、delegation.mode 不会被运行时强制调度或限流。

  • MCP 不能主动唤醒一个空闲客户端。ZCode Desktop 使用 /worker Goal 保持可见执行;外置 zcode-waker 仅作为 CLI 兼容模式保留。

  • 提交路径校验不替代人工/自动代码审查、CI、合并策略和发布流程。

Related MCP Connectors

Related MCP Servers