mcpField
C
cpm-planner

cpm-planner

本地服务
github.com/praxecAI 与智能体03 天前更新

关于 cpm-planner

cpm-planner 是一个 MCP 服务,使用关键路径法根据任务图安排 Agent 工作。它识别进度约束,将文件集合互不重叠的就绪交付项分配给并行工作者,并支持计划变体、风险分析、挣值跟踪和可选的 AI 审查。

主要功能

  1. 01计算关键路径和进度浮时
  2. 02分配文件集合不重叠的并行任务组
  3. 03保存并比较代码化计划变体
  4. 04执行资源平衡和蒙特卡洛风险分析
  5. 05按基线跟踪挣值
  6. 06审查计划改进建议

适用场景

  1. 01安排 Agent 工作并识别瓶颈任务
  2. 02为并行工作者分配任务以避免文件冲突
  3. 03比较计划变体并评估进度风险
  4. 04跟踪项目进度、成本和计划表现

MCP 相关

它通过 stdio 向 MCP 客户端提供计划、调度、状态和挣值工具。客户端可将其注册为命令,用于协调 Agent 工作。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"praxec-cpm-planner": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/praxec/cpm-planner:0.5.0"
]
}
}
}
启动命令docker run -i --rm ghcr.io/praxec/cpm-planner:0.5.0

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

安装包
ocighcr.io/praxec/cpm-planner:0.5.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

cpm-planner

CI Release License: Apache-2.0

cpm-planner 是一款用于 Agent 工作的关键路径法(CPM)规划器,以 MCP 服务的形式提供。提交任务图后,它会计算计划:最早和最晚开始时间与完成时间、时差、关键路径,以及决定完工时间的瓶颈任务。随后,它会分配考虑锁定状态的就绪任务组,这些任务组中的交付项文件集彼此不重叠,因此多个工作者可以并行执行而不会发生冲突。计划可以作为代码形式的文件保存在代码库中,并支持分支变体和对比;只读工具可以检查计划、根据资源容量进行资源平衡并运行蒙特卡洛风险分析;挣值工具可以根据冻结的基线跟踪 PV、EV、AC、SPI 和 CPI;可选的 AI 评审还可以提出经过验证的计划改进。任何 MCP 客户端(Claude Code、Cursor、VS Code、Codex、自定义编排器或 praxec 工作流)都可以通过 stdio 驱动它。它是一个独立工具,不依赖 praxec。

目录

安装

预构建二进制文件(推荐)

已为 Linux、macOS 和 Windows 的 x86_64 与 ARM64 平台发布预构建包。

安装程序会识别你的操作系统和 CPU,并下载匹配的归档文件。它们会 在安装前验证归档文件的 SHA-256 是否与发布版本的 checksums.sha256 一致, 然后在用户本地目录中原子替换二进制文件。如果校验和不匹配,安装程序会以非零状态退出, 不会安装任何内容。再次运行安装程序会原地升级。

# Linux / macOS  ->  ~/.local/bin/cpm-planner
curl -fsSL https://github.com/praxec/cpm-planner/releases/latest/download/install.sh | sh

# Windows (PowerShell)  ->  %LOCALAPPDATA%\Programs\cpm-planner\cpm-planner.exe
irm https://github.com/praxec/cpm-planner/releases/latest/download/install.ps1 | iex

安装程序会打印安装路径的绝对路径。向 GUI 客户端注册服务时,请使用该路径。

安装程序详情:检查脚本、PATH、升级和直接下载

如果你想先查看脚本再运行,请先下载并检查,然后再运行 (<version> 的说明请参阅固定版本):

# Linux / macOS
curl -fsSLO https://github.com/praxec/cpm-planner/releases/latest/download/install.sh
less install.sh
sh install.sh --version <version>
# Windows
irm https://github.com/praxec/cpm-planner/releases/latest/download/install.ps1 -OutFile install.ps1
Get-Content install.ps1
.\install.ps1 -Version <version>

PATH。 如果安装目录不在你的 PATH 中,安装程序会打印要添加的确切行。 传入 --add-to-path(Windows 上为 -AddToPath),即可让安装程序代为添加; 此操作仅限用户级,且绝不会使用 sudo。

在 Linux 和 macOS 上,只有当对应行尚未存在时,安装程序才会将其追加到:

  • zsh 对应的 ~/.zshrc;
  • bash 对应的 ~/.bash_profile(如果存在),否则为 ~/.bashrc;
  • 其他 shell 对应的 ~/.profile。

对于 fish,安装程序会打印 fish_add_path <dir>,供你运行,而不会写入文件。

下载。 安装程序只接受 https:// 下载 URL。

升级。 升级后,请重启 MCP 客户端,使其启动新的二进制文件。在 Windows 上,旧的 exe 会被重命名为 cpm-planner.exe.old,并在下次运行时删除。

直接下载。 你也可以自行下载归档文件,并使用 checksums.sha256 对其进行校验;同时也发布了机器可读的 release-manifest.json。所有资源均可在 https://github.com/praxec/cpm-planner/releases/latest 获取。

平台资源
Linux x86_64cpm-planner-x86_64-unknown-linux-gnu.tar.gz
Linux ARM64cpm-planner-aarch64-unknown-linux-gnu.tar.gz
macOS x86_64cpm-planner-x86_64-apple-darwin.tar.gz
macOS Apple Siliconcpm-planner-aarch64-apple-darwin.tar.gz
Windows x86_64cpm-planner-x86_64-pc-windows-msvc.zip
Windows ARM64cpm-planner-aarch64-pc-windows-msvc.zip
固定版本

在本 README 的命令中,<version> 是诸如 v0.2.0 的发布标签。请从发布页面中选择一个版本。

# Linux / macOS
curl -fsSL https://github.com/praxec/cpm-planner/releases/latest/download/install.sh | sh -s -- --version <version>

# Windows (PowerShell): the piped form cannot take parameters, so use the environment variable...
$env:PRAXEC_VERSION = '<version>'; irm https://github.com/praxec/cpm-planner/releases/latest/download/install.ps1 | iex
# ...or a script block
& ([scriptblock]::Create((irm https://github.com/praxec/cpm-planner/releases/latest/download/install.ps1))) -Version <version>
npm

使用 Node 18 或更高版本,从 npm 安装 cpm-planner 命令:

npm install -g @matthew-cochran/cpm
cpm-planner --version

此软件包是一个轻量级启动器。它会下载适用于你平台的发布二进制文件、验证校验和并缓存该文件;此操作会在安装期间进行,若 npm 跳过安装脚本,则会在首次运行时进行。软件包版本与发布版本一致,因此 npm install -g @matthew-cochran/[email protected] 可以固定到指定版本。若要运行而不安装,请使用 npx -y @matthew-cochran/cpm。详情和环境变量请参阅 npm/README.md。

从源代码构建

使用 Cargo 构建并安装带标签的发布版本(需要 Rust 1.99 或更高版本):

cargo install --git https://github.com/praxec/cpm-planner --tag <version> --locked

在下一次执行 cargo publish 之前,crates.io 上的列表会落后于 GitHub 发布版本,因此 cargo install cpm-planner 目前无法安装最新版本。请按上述方式从标签安装。

Docker
docker pull ghcr.io/praxec/cpm-planner
docker run -i --rm -v cpm-planner-data:/data ghcr.io/praxec/cpm-planner

-i 会保持 stdin 打开,以供 stdio 传输使用。

此镜像设置了 CPM_PLANNER_DB=/data/cpm-planner.db,并将 /data 声明为由非特权 app 用户拥有的卷,因此命名卷可以在多次运行间保留计划状态。对于绑定挂载(-v "$PWD:/data"),请以你自己的身份运行,确保目录可写:--user "$(id -u):$(id -g)"。仅在需要覆盖路径时传入 -e CPM_PLANNER_DB=...。

要将此镜像注册到客户端,请将 docker 放入 command,其余内容放入 args。例如,在 Claude Code 中:

claude mcp add cpm-planner --scope user -- docker run -i --rm -v cpm-planner-data:/data ghcr.io/praxec/cpm-planner
验证安装
cpm-planner --version

它会输出 cpm-planner <version>。若要在不使用客户端的情况下检查 MCP 端,请运行仓库中的冒烟测试脚本。该脚本会执行 MCP initialize 和 tools/list 握手;如果缺少 plan.submit、plan.status 或 plan.get,则会失败:

node scripts/mcp-smoke.mjs /absolute/path/to/cpm-planner

快速入门:将计划作为代码

将计划(PlanGraph)写入 .cpm-planner/plans/<name>/<variant>.json:

  1. plan.lint {path: ".cpm-planner/plans/checkout/main.json"} — 静态检查,不写入状态。
  2. plan.sync {path: ".cpm-planner/plans/checkout/main.json"} — 注册该变体并返回其 plan_id。
  3. plan.status {plan_id} — 查看进度安排、关键路径、就绪集和锁。

plan.sync 会根据内容哈希追踪文件;如果被追踪的文件与存储的头部图不一致,plan.status 会报告 definition_drift。

快速入门:挣值管理

冻结基线、记录进度,然后读取报告(earning_rule: "weighted" 时,earned_pct 按比例挣值;fifty_fifty 会在可交付成果开始进行或报告了任何 earned_pct 后计入 50%;默认的 zero_hundred 则在完成时计入全部挣值):

  1. plan.baseline {plan_id} — 冻结 CPM 进度安排和预算,作为基线 1。
  2. plan.mark_status {plan_id, deliverable_id, caller_id, status: {"status": "in_progress"}, earned_pct: 50, actual_effort_hours: 4} — 报告进度和实际成本。
  3. plan.ev {plan_id} — 查看 PV、EV、AC、SV、CV、SPI、CPI、EAC 和警报。
  4. plan.snapshot {plan_id, format: "markdown"} — 追加读数并导出 Markdown 表格。

分母为零的比率会显示为 null,并在 undefined 中说明;警报(SPI_BELOW_0_9、CPI_BELOW_0_9)会比较最近两次存储的读数。

与 AI Agent 配合使用

任何 MCP 客户端都可以通过 stdio 运行 cpm-planner:将 cpm-planner 二进制文件注册为命令,或者在 Node 18 或更高版本中使用 npx -y @matthew-cochran/cpm。 对于图形界面客户端,请使用安装程序输出的绝对路径。

使用 cpm-planner skills install --target <tool> --user(或 --project <dir>)安装 Agent 技能(/cpm-plan 等),其中 <tool> 可以是 claude、codex、cursor、copilot、gemini、all 或 agents-md(仅限项目)。

docs/AGENT-INSTALL.md 提供各客户端的安装步骤(Claude Code、Claude Desktop、Codex、Cursor、VS Code、Gemini CLI 等)、env 代码块、验证和故障排除。llms.txt 为大模型编制了文档索引。

MCP 工具

工具功能
plan.submit提交任务图;返回计划 ID(基于任务图和调用方实现幂等)。前置项可以是交付项 ID 字符串,也可以是对象 {id, consumes?, kind?: artifact|interface, lag_hours?};两种形式都可以通过 plan.get 原样读回。交付项可以设置 milestone: true(验收点;除非指定估算值或工期,否则时长为零;在 plan.status 的 milestones 中报告)。可选的 earning_rule(zero_hundred,默认值:仅在完成时计入 100%;fifty_fifty:一旦开始或报告任何 earned_pct,即计入 50%;weighted:按报告的 earned_pct 计入)用于设定已挣价值如何计入部分进度,也是计划标识的一部分。交付项的可选 duration_hours(日历时间)会取代工作量,作为其排定时长;前置项的 lag_hours 会延迟依赖项的开始时间;工作量仍是成本计算依据。可选的 estimate {optimistic, likely, pessimistic}(0 <= optimistic <= likely <= pessimistic)是三点工作量估算。排定时长优先级:duration_hours > estimated_effort_hours > estimate.likely > 里程碑的 0 > 估算器默认值;仅当未设置 duration_hours 和 estimated_effort_hours 时,Monte Carlo 才会对估算值进行抽样。限制:最多 5000 个交付项,且每个小时数值(工作量、工期、滞后时间、估算值)必须为有限数值且介于 0 到 1000000 之间(否则返回 INVALID_GRAPH)。指定 name(可选的 project/variant;variant 默认为 main)后,会注册为具名变体,而非未命名计划。
plan.acquire_cohort原子性地获取最多 N 个就绪交付项,且它们的文件集互不重叠(owned_files 条目可以是 {path, mode: "append"};同一路径上的追加声明可以共同租用,并显示在 shared_paths 中;仅当多个交付项由前置项排序,或所有声明均为追加时,同一个文件才可由多个交付项所有);可选的 ttl_seconds 设置租约 TTL(限制为服务端最大值);可选的 ids 和 filter.metadata 用于指定交付项;metadata.kind = "manual" 的交付项永远不会被租用;响应会在 blocked 中列出未租用的候选项(以及 blocked_count、needs_operator)。
plan.heartbeat刷新持有的锁的 TTL;可选的 ttl_seconds 设置新的 TTL(限制为服务端最大值)。
plan.mark_status将交付项标记为已完成/失败;同时释放其锁。未持有锁时,只有前置项全部完成才能标记为已完成(否则返回 PREREQUISITES_INCOMPLETE),且每次无锁标记都会记录审计信息。无锁的 in_progress(所有者工作或手动工作)会在服务重启后保留,且不可租用;可通过无锁的 ready(或任何其他状态)标记将其交还。可选的已挣价值进度:earned_pct(整数,0 到 100,仅用于 in_progress;与 complete 一起提交时会被接受并忽略)、actual_effort_hours(截至目前的总工作量,必须为有限数值且介于 0 到 1000000 之间;会取代租用时长作为实际成本)以及 evidence(最多 2048 个字符,会追加到交付项的证据列表中;列表最多保留 100 条);违规时返回 INVALID_ACTUALS,包括 earned_pct 为负数、小数或大于 100。plan.select 会复制其携带的每个已完成交付项的实际数据(租用时长会累加;被携带交付项报告的百分比和小时数优先;保留最新的 100 条证据)。每次租约结束(完成、失败、强制释放、过期、接受覆盖、强制修订/选择/归档)都会将其时长计入交付项的租用时长;过期租约按其到期时间计算。
plan.status只读的计划及其锁快照。critical_path 始终从 __start__ 延伸到 __finish__(这两个合成端点的工作量为零;它们的 schedule 行带有 synthetic: true,且 __start__/__finish__ 是保留交付项 ID,提交时会被 INVALID_GRAPH 拒绝)。强制修订若使租约失效,会报告 superseded_revision;前置项完成后可重新获取该交付项,但旧持有者无法将其标记为已完成。当所有交付项都已完成时,plan_complete 为 true;此时 plan.completed 审计事件仅触发一次。milestones 为每个满足 milestone: true(或旧版 metadata.milestone == true)的交付项提供一行数据:id、critical_path(从 __start__ 到该交付项的最长链)、hours(其最早完成时间)和 complete。对于具名变体,还会报告 name、variant、selected、archived 和 active_plan(该变体归档时,项目唯一活动分支的名称;未命名计划的 archived 和 active_plan 为 null),以及 definition_drift:对于缺少项目根目录的变体、没有受跟踪计划文件的变体,或文件缺失、不可读或大于 8 MiB 时,值为 null(未知);否则,若文件字节与上次同步或导出的哈希一致,或文件图与当前头部图相同(重新格式化不算漂移),值为 false;若文件图与当前头部图不同(或无法解析),值为 true。因此,对文件关联变体执行内联 plan.revise/plan.sync 后,在文件重新导出或同步之前,结果会报告 true。
plan.get按 plan_id、plan 分支名称或 active: true 选取计划,并返回存储的计划图(读回已提交的内容)。
plan.force_release运维人员的紧急释放工具:无论锁的持有者/TTL 如何都可释放锁;reset_counters: true 还会清除过期/失败计数。无锁的 in_progress 没有锁,因此 plan.force_release 不会更改其状态;可通过无锁的 plan.mark_status 将其交还。
plan.accept经理/所有者验收:无需持有租约即可完成交付项(记录审计信息及证据)。
plan.lint提交前执行静态检查:循环(包含循环路径)、冗余边、缺少理由的边、未指向契约的接口边、未为任何里程碑提供输入的交付项,以及文件无序重叠(#20)。
plan.schedule根据资源容量(默认使用 metadata.owner)对任务图进行资源调配:工期、各交付项的开始/结束时间、各资源的负载、驱动链(依赖等待与具名资源等待),以及项目缓冲和输入缓冲(#19)。交付项可通过 metadata.resources: {"agent":1,"builder":1} 原子性地占用多个资源池;每个被占用的资源池都必须有足够容量。duration_hours 配合 metadata.wall_clock_only: true 可建模会阻塞依赖项、但不消耗容量的 CI/观测时间。project_buffer_pct 范围为 0 到 100(默认值为 25)。
plan.simulate对任务图、已存储计划或计划文件执行只读假设分析(不会持久化任何内容):包括 lint、关键路径、排期、里程碑、可选的资源排期(schedule,输入项与 plan.schedule 相同,且遵循相同的 INVALID_CAPACITIES: 规则)、Monte Carlo(monte_carlo:iterations 为 1 到 50000,默认值为 2000;seed 默认值为 0xC0FFEE;iterations × (deliverables + prerequisite edges) 不得超过 200000000),以及评分卡(#23)。
plan.release.compile将有版本控制且有界的工作流/晋级元数据编译为通过 lint 的普通计划:包括受保护的 PR、并行检查/汇合、所有者等待/审批/合并、生产者重试回执、保留的制品、原生固定成本集成轮次/证据复用,以及集中验收。报告批处理与逐变更门禁的成本效益分析及支配性警告;离线运行,绝不执行或验收工作(发布工作流)。
plan.release.diff将保留的生成 graph 与当前 workflow 元数据进行比较;在修订或建立基线前报告策略/估算漂移以及新增、移除或更改的 ID(发布工作流)。对应的 CLI 命令:cpm-planner release compile、release lint 和 release diff。
plan.sync根据计划文件(路径格式为 .cpm-planner/plans/<name>/<variant>.json)或内联 graph,注册或更新具名计划分支的一个变体(需要 name;variant 默认为 main)。文件通过禁止跟随符号链接的受限路径读取,并按内容哈希跟踪,以检测漂移;project 默认为自动发现的项目根目录;使用 path 时,给出的任何 name/variant/project 都必须与文件路径一致(否则返回 INVALID_PATH: name/variant/project must match the plan file path);force 会释放已移除交付项的活动锁。
plan.list列出 project 的所有计划分支(默认值:自动发现的项目根目录),按名称排序,变体也按名称排序;除非指定 include_archived,否则不包括已归档的分支和变体。active: true 仅返回项目的活动分支,且不能与 include_archived 同时使用。
plan.export将 plan_id 的头部图写入其自身的变体文件或受限 path,并返回相对于根目录的路径。如果目标是另一个变体受跟踪的计划文件,或是该变体自身存在尚未同步的本地修改的文件,则拒绝操作(返回 INVALID_PATH),除非设置 force: true。写入的文件不会同步,除非导出到该变体自身受跟踪的文件;此时会记录其哈希(之后漂移为 false)。
plan.revise就地替换计划图,并沿用现有进度(未更改的交付项保留状态/计数器;更改或重新开放的交付项会重新派生)。交付项可以通过 metadata.consumes_revision_from 声明一个直接前置项;若更改该屏障或任何前置项,除非指定 force,否则会拒绝其活动租约;指定 force 时会报告诊断信息 superseded_revision,并保留其先前的证据/小时数。返回新版本及差异;force 会释放已移除交付项的活动锁。
plan.fork复制具名变体的头部图,应用按顺序排列的 edits,并将结果注册为同一分支下的新草稿变体(未选中)。若目标分支已归档,会在写入任何文件之前返回 ARCHIVE_REFUSED;可从活动分支中已归档的变体分叉。若文件写入后注册失败,会删除该文件。
plan.select将具名变体设为其分支选中的(唯一可执行)变体,并沿用进度;force 会释放先前选中变体上的锁。
plan.archive归档(archived 默认为 true)或取消归档整个分支或其中一个 variant。已归档的变体仍可读取,但拒绝同步、选择和执行(返回 ARCHIVE_REFUSED)。
plan.compare根据评分卡比较已存储的计划(plan_ids:2 到 16 个不同 ID;或在 project 中指定 plan 分支名称(默认值为自动发现的根目录),比较所有未归档变体,最多 16 个):包括 Pareto 前沿、加权排名和推荐计划;得分相同的计划排名相同,tied_with_recommended 列出与推荐计划并列的变体。权重必须为有限数值且 >= 0。使用 monte_carlo 时,所有变体的 iterations × (deliverables + prerequisite edges) 总和不得超过 200000000(否则返回 INVALID_GRAPH)。只读;评分在异步运行时之外执行。
plan.baseline将计划当前的 CPM 排期(每个交付项的最早开始/完成时间)和预算(工作量依据 × metadata.cost_rate,默认值为 1)冻结为下一个编号的已挣价值基线。可选的 start(RFC 3339,默认为当前时间)和 calendar {hours_per_day (0 < h ≤ 24, default 8), workdays (default mon–fri), utc_offset_minutes (default 0)}(省略时:首个基线按墙上时钟小时计算;重新建立基线时沿用上一基线的日历)。第一个基线的编号为 1;重新建立基线需要非空白的 reason(最多 2048 个字符,否则返回 INVALID_GRAPH),并保留实际数据和快照。基线、实际数据和快照归属于同一变体:新选中的变体会使用自身的基线 1,无需提供理由。执行侧操作:仅适用于选中且未归档的变体(否则返回 VARIANT_NOT_SELECTED / ARCHIVE_REFUSED)。记录为 plan.ev.baselined 审计事件。
plan.ev根据最新基线生成截至 as_of 的已挣价值报告(as_of 为 RFC 3339 格式,默认为当前时间)。as_of 是 PV 状态日期;EV 和 AC 反映截至调用执行时记录的进度和实际数据。返回 BAC、PV、EV、AC、SV、CV、SPI、CPI、EAC、ETC、VAC、TCPI、逐交付项数据、已消耗的关键路径浮时、SPI_BELOW_0_9 / CPI_BELOW_0_9 警报(根据当前基线中截至 as_of 的最新两个已存储、非回填快照判断指标是否低于 0.9;当前读数不计入这两个快照),以及 excluded_unbaselined(基线建立后新增的交付项)。AC 汇总计划所有已记录的小时数,包括已移除和未纳入基线的交付项(按基线行的成本率计算;若无成本率则按 1 计算),因此即使重新建立基线,支出也不会消失。若 plan.revise 移除了已纳入基线的交付项,则会保留其被移除时已挣得的百分比(已完成时为 100,否则按其已挣价值规则计算),并将行状态报告为 removed。重新添加该交付项时,其已挣百分比会重置,但小时数仍会持续累加。分母为零的比率会返回 null,并在 undefined 中说明原因;输出永远不会包含 NaN 或无穷大。可对任何变体(包括已归档变体)执行只读操作;已归档变体会报告 archived: true,且当项目恰好有一个活动分支时会报告其 active_plan;在 plan.baseline 之前返回 NOT_BASELINED。
plan.snapshot计算 plan.ev 报告并将其追加为快照(as_of 是 PV 状态日期;EV 和 AC 反映调用执行时记录的进度)。若快照的 as_of 早于 taken_at 超过一小时,则标记为 backfilled: true:不会触发警报,后续警报也会跳过该快照。返回其 summary(其中 undefined 会说明每个空比率的原因;警报仅考虑截至该快照自身位置的读数:该快照,以及当前基线中按 as_of 排序、位于其之前的最新非回填快照,因此回填快照不会从更新的读数触发警报)、snapshot_count 和包含最新 100 个快照的 export(按 as_of 排序,同一日期按拍摄时间排序,最旧的在前,因此回填的 as_of 会按日期顺序排列;若回填快照比这 100 个更早,则仍会存储并计数,但不会列出):可以是摘要列表(format: "json",默认值),也可以是包含日期、PV、EV、AC、SPI、CPI、EAC 列的 Markdown 表格(format: "markdown",未定义的比率显示为 n/a)。执行侧规则与 plan.baseline 相同;在建立基线之前返回 NOT_BASELINED。
plan.review对任务图、已存储计划或计划文件进行可选的 AI 审查(只读;graph、plan_id、path 三者中必须且只能指定一个;可选的 capacities / resource_key / project_buffer_pct 用于平衡工期;max_questions 范围为 1 到 64,默认值为 64)。始终执行 lint;若 lint 报错,则返回 status: "invalid_graph",且不会调用评审器。否则会批量调用一次 Jev,询问可能存在的错误依赖和缺失依赖、拆分及接口拆分候选项、以及崩溃选项,并返回建议性的 findings 和 proposals:plan.fork 编辑列表;每个列表都通过 simulate 验证(lint 通过且缩短工期),并按 hours_saved / max(cost, 1) 排名。若没有密钥或 LLM 设置不可用,则 status 为 review_unavailable,并附带 reason 和 lint 结果。参阅计划审查(可选)。
plan.status、plan.get、plan.ev、plan.snapshot、plan.baseline、
plan.acquire_cohort、plan.heartbeat、plan.mark_status、plan.accept 和
plan.force_release 通过以下三种方式之一定位计划:plan_id、plan(计划行名称,解析为其选定变体),或 active: true(项目中唯一未归档,且其选定变体未归档、未完成的计划行)。plan 和 active 还接受可选的 project(默认值:发现的项目根目录);将 project 与 plan_id 一起使用会导致参数无效。没有活动计划行时返回 NO_ACTIVE_PLAN;有多个活动计划行时返回 AMBIGUOUS_ACTIVE_PLAN 并列出这些计划行;未知计划行或没有选定变体的计划行返回 PLAN_NOT_FOUND。
周期性任务和 Agent 应使用 active(或 plan)查找计划,而不要固定使用 plan_id,这样它们才能跟随工作转到下一计划行。active 仅匹配未完成的计划行;其他计划行上线时,它可能会变更(或变得不明确):先解析一次(plan.status 和 plan.acquire_cohort 会返回 plan_id),然后在心跳、状态标记以及该计划最终的 plan.status/plan.ev 中继续使用此 plan_id。已归档变体的固定 ID 仍可通过 plan.status/plan.ev 读取;这两个工具会报告 archived: true,并通过 active_plan 指明当前进行的工作所在位置,而快照、基线和执行会因 ARCHIVE_REFUSED 而被拒绝。

plan.lint、plan.simulate 和 plan.review 必须且只能使用内联 graph、已存储的 plan_id 或计划文件 path 三者之一;plan.schedule 接受 graph 或 plan_id; plan.schedule 和 plan.simulate 会拒绝 plan.submit 所拒绝的内容,而 plan.lint 会将其报告为问题。对于相同平台和工具链,给定种子时 Monte Carlo 输出可复现;由于浮点数学函数可能存在差异,不保证不同目标平台或编译器版本之间的结果逐位完全相同。

计划即代码工作流

将计划编写为文件,保存到 .cpm-planner/plans/<name>/<variant>.json,使用 plan.lint {path} 检查,通过 plan.sync {path} 注册,然后执行返回的 plan_id。一个具名计划行可以有多个变体,但只能有一个选定变体:plan.fork 根据结构化编辑创建草案,plan.compare 对变体评分,plan.select 则指定一个可执行变体。请将定义保存在已跟踪的文件中,切勿保留未跟踪的临时图。

计划审查(可选)

plan.review 会通过 OpenRouter 向 Jev(typesafe/jev-1.13)——TypeSafe 的校准判断模型——询问一个通过 lint 检查的计划:每次审查最多批量提出 64 个问题。设置 OPENROUTER_API_KEY(或 CPM_OPENROUTER_KEY_FILE)后才会启用;若未设置密钥,工具仍会响应,并返回 review_unavailable 和 lint 报告。无效的 LLM 设置不会导致服务停止:它会在启动时记录日志,而 plan.review 会返回 review_unavailable,并说明具体设置项。

  • 概率仅供参考。 请将审查结果视为第二意见。提案会通过机械方式验证(编辑后的计划必须通过 lint 检查,并模拟出更短的总工期);使用 plan.fork {edits} 应用一项提案,然后运行 plan.compare。

  • 成本。 每次实际调用评审模型的 plan.review 请求,都会产生一笔 OpenRouter 费用;Jev 在 OpenRouter 上的输入费用约为每百万个 token 0.042 美元。每份报告都会在服务提供方提供 usage 时附上该信息。每台服务最多同时运行 2 次调用评审模型的审查;更多请求会等待空位(在调用模型前就结束的审查,例如缺少密钥或存在 lint 错误的审查,无需等待)。

  • 隐私。 以下是该单次请求中发送到 OpenRouter 的全部内容:

    • 固定的任务句子、计划总工期和关键路径(ID);
    • 问题:每个问题都会包含其类型、问题中提及的交付物 ID,以及引用这些 ID 的问题句子;根据问题类型,句子还会包含前置项的 consumes 文本、交付物的计划工时、计划的计划工时中位数,以及触发缺失依赖问题的启发式信号(描述提及了另一交付物、文件位于相同或嵌套目录中、共享 metadata.owner);
    • 对于问题提及的每项交付物:其 ID、计划工时、浮动工时、critical 和 milestone 标记、所拥有的文件路径(完整发送,不截断)、前置项(ID、consumes、类型),以及 description、artifact 和 owner 元数据。description、artifact、owner 和 consumes 均截断至 500 个字符。

    图中的其他内容(其他交付物、其他元数据键、估算)均不会发送。请勿审查其内容可能不适合分享给 OpenRouter 的计划。

  • 审计。 密钥不会被记录或返回,错误放置的 LLM 变量值也不会。每次 plan.review 调用都会记录一条 plan.review 审计事件,无论结果如何(包括缺少计划、路径错误或审查失败);唯一不记录审计的情况是因参数无效(invalid_params)而拒绝调用。事件仅包含以下字段:

    • status:ok、review_unavailable、invalid_graph 或 error(审查失败:PLAN_NOT_FOUND、INVALID_PATH、INVALID_CAPACITIES 等);
    • code:error 时为错误前缀,否则为 null;
    • failure_class:若 review_unavailable 是由评审模型调用失败所致,则为其类别(unauthorized、rate_limited、timeout、upstream、decode、transport、invalid_request);否则为 null(包括缺少密钥和 LLM 设置不可用的情况);
    • plan_id:被审查的已存储计划;若使用内联 graph 或 path,则为 null;
    • question_count:发送的问题数量(未调用评审模型时为 0);
    • jev_called:是否调用了评审模型;
    • prompt_hash:规范化请求的 sha256;未调用评审模型时为 null;
    • model:服务提供方报告的模型;若调用失败,则为已配置的模型;未调用评审模型时为 null;
    • endpoint:评审模型端点的主机名;未配置评审模型、lint 检查发现错误或审查以 error 结束时为 null。

    提示词本身绝不会被记录。

作为库使用

CPM 内核也是一个纯 Rust 库,可独立于 MCP 使用:

use cpm_planner::{CpmAlgorithm, Task, TaskKind};

let mut tasks = vec![
    Task::new("design", "Design", TaskKind::Custom { description: "design".into() }, 4.0),
    Task::new("build", "Build", TaskKind::Custom { description: "build".into() }, 8.0)
        .depends_on("design"),
    Task::new("test", "Test", TaskKind::Custom { description: "test".into() }, 2.0)
        .depends_on("build"),
];

let result = CpmAlgorithm::calculate(&mut tasks);
println!("critical path: {:?}", result.critical_path); // ["design", "build", "test"]
// also: result.bottlenecks, result.optimal_duration_parallel,
// and per-task .float (slack) / .is_critical on each Task.

crate 级文档(运行 cargo doc --open,或在当前版本发布到 docs.rs 后查阅)中包含一个可运行的示例,演示如何通过提交、租用和完成来驱动规划器。

llm::jev::JevJudge(plan.review 裁判)拥有自己的 HTTP 客户端和连接池。池化连接由打开它的 tokio 运行时驱动,因此请在同一个运行时中使用裁判及其克隆,并为其他运行时创建新的裁判。

Praxec

cpm-planner 完全独立:它使用纯 MCP 通信,不依赖任何特定客户端的代码。Praxec 工具包将其作为 MCP 工具使用。要将其接入 praxec 工作流,请声明一个 MCP 连接(仅使用协议,不共享代码):

connections:
  planner:
    kind: mcp
    command: cpm-planner

最简单的启动方式是使用一条命令完成设置,同时启动它以及使用它的工作流工具包:

curl -fsSL https://raw.githubusercontent.com/praxec/packs/main/setup.sh | bash

请参阅工具包注册表,了解此工具的提供方坐标(容器镜像或发布版二进制文件),以及依赖它的工具包。

环境变量

在客户端的 env 块中设置这些变量(或使用 -e/--env 标志,或 docker run -e)。这些变量均为可选。

变量默认值含义
CPM_PLANNER_DB所有操作系统上均为 ~/.local/share/praxec/cpm-planner.db(~ 表示 HOME,否则为 USERPROFILE:Windows 上为 %USERPROFILE%\.local\share\praxec\cpm-planner.db);Docker 镜像中为 /data/cpm-planner.db用于保存可跨进程持久化规划器状态的 SQLite 路径;:memory: 表示临时状态。
CPM_PLANNER_STATE_MODE未设置未设置时,按常规方式打开持久化状态。如果现有数据库为空,或其旁置收据检测到已知计划缺失,启动将拒绝对其进行修改。只有在查看服务器报告的带时间戳备份路径后,才可设置为 recover;initialize 则明确接受现有的空位置。每条 MCP 结果都会通过 durable_state 报告解析后的位置、结果和任何备份路径。
CPM_PROJECT_ROOTcwd 中包含 .cpm-planner/ 或 .git 的最近祖先目录计划即代码文件(.cpm-planner/plans/<name>/<variant>.json)的仓库根目录。需要根目录的工具在未找到时会报告 INVALID_PATH: no project root (set CPM_PROJECT_ROOT or run inside a repo)。
CPM_MAX_TTL_SECS28800(8 小时)服务端对 plan.acquire_cohort 和 plan.heartbeat 的 ttl_seconds 上限;超过上限的请求值会被截断。必须是 1..=2592000 范围内的整数(最多 30 天),否则启动将中止。
OPENROUTER_API_KEY未设置plan.review 使用的 OpenRouter 密钥。未设置或为空时:plan.review 会报告 review_unavailable(“no OpenRouter key configured”)。绝不记录或返回该密钥。
CPM_OPENROUTER_KEY_FILE未设置存放 OpenRouter 密钥的文件(读取内容会去除首尾空白;最多 4096 字节),仅在未设置 OPENROUTER_API_KEY 时使用。在 unix 上,如果文件对所有用户可读(o+r)或为空,则会忽略该文件并发出警告(请对其运行 chmod 600)。
CPM_JEV_MODELtypesafe/jev-1.13plan.review 使用的 Jev 模型 ID:最多 128 个字符,且只能包含 A-Z a-z 0-9 . _ : / -,不得包含密钥;其他任何值都会被记录(仅记录变量名,不记录变量值),并使 plan.review 不可用。
CPM_JEV_ENDPOINThttps://openrouter.ai/api/v1/systemoneJev 端点 URL:必须使用 https://;仅当主机为环回地址时才允许使用 http://,且不得包含凭据。
CPM_LLM_TIMEOUT_SECS30每次大模型调用的超时上限,以秒为单位,必须是 1..=300 范围内的整数。
CPM_LLM_MODELdeepseek/deepseek-v4.1-flash生成式(聊天)模型 ID:最多 128 个字符,且只能包含 A-Z a-z 0-9 . _ : / -。调用前会拒绝前沿厂商的模型,并返回包含模型名称的类型化错误:anthropic/、openai/(openai/gpt-oss* 除外)、google/、x-ai/、xai/。

租约默认有效期为 5 分钟。对于长时间运行的工作,请在获取租约或发送心跳时传入 ttl_seconds(≤ 服务端上限),并至少每隔 ttl/3 发送一次心跳。

文档

贡献

欢迎贡献。有关工具链、门禁和分支模型,请参阅 CONTRIBUTING.md。 所有参与者均同意遵守行为准则。

许可证

Apache-2.0。

评论

支持 Markdown

第一次接触 MCP?

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

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