关于 Cvm: Stateful Programable Task Engine
CVM 是一个以 TypeScript 语法编写程序的 MCP 服务,由 Claude 逐步驱动执行。程序在每个 CC() 处暂停并保存状态,适合需要长流程且希望中断后恢复的任务。
主要功能
- 01CC() 暂停执行并等待 Claude 提交结果
- 02执行状态在多次交互之间持久保存
- 03支持暂停、检查与恢复执行
- 04基于解释器逐条执行 TypeScript 类语法
- 05提供 CVM-PP 计划协议,可按计划逐项驱动 Agent
适用场景
- 01多文件逐个处理并汇总结果的流程
- 02中途失败后从断点恢复的长任务
- 03按 Markdown 计划分步执行的开发工作
MCP 相关
CVM 以被动 MCP 服务的形式运行,由 Claude 通过 getTask 和 submitTask 等工具拉取任务并提交结果。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
15收录的工具列表 · 更新于 3 周前
此工具无需参数。
详细介绍
CVM:将 Claude 变为系统化处理器
别再编写脆弱的 AI 脚本。编写由 Claude 一次执行一个思考步骤的程序。
CVM 采用双重许可:开源使用遵循 AGPL-3.0-or-later,专有集成则使用商业许可。详情请参阅 COMMERCIAL.md。
重要
新功能:CVM 计划协议(CVM-PP)。 将工作编写为结构化 Markdown 计划, CVM 就会引导 AI Agent 一次完成一个任务——无需手写 CVM 程序。 如果计划采用 CVM-PP 格式,CVM 就知道如何运行它。 → 协议介绍与工作原理 · 协议规范
传统脚本
🔘 灰色 = 脚本操作
flowchart TD
Start([Start]) --> Loop{More files?}
Loop -->|Yes| Call[Call Claude API with process file prompt]
Call --> Response[Get Response]
Response --> Lost[❌ Context Lost]
Lost --> Loop
Loop -->|No| End([End])
Response -.->|Crash| Restart[Start Over From Beginning]
classDef script fill:#e0e0e0,stroke:#666,color:#000
class Start,Loop,Call,Response,Lost,End,Restart script
CVM 架构
🟢 绿色 = CVM 操作 | 🔵 蓝色 = Claude 操作 | 🟡 黄色 = 人工控制
flowchart TD
Start([Start]) --> Loop{More files?}
Loop -->|Yes| CC[CC: analyze file]
CC --> Pause((⏸️ PAUSE))
Pause --> Wait[Wait for Claude]
Wait --> GetTask[Claude: getTask]
GetTask --> Process[Claude analyze file]
Process --> Submit[Claude: submitTask]
Submit --> Save[✓ State saved]
Save --> Loop
Loop -->|No| End([End])
Pause -.->|Can inspect| Status[Check Progress]
Submit -.->|Crash| Resume[Resume from here, just going to start]
classDef cvm fill:#d4ffd4,stroke:#090,color:#000
classDef claude fill:#d4d4ff,stroke:#00d,color:#000
classDef human fill:#ffffd4,stroke:#990,color:#000
class Start,Loop,CC,Pause,Wait,Save,End cvm
class GetTask,Process,Submit claude
class Status,Resume human
实际演示:从脆弱到可靠
不使用 CVM 时,你需要手动串联调用。一旦崩溃,状态就会丢失:
// Fragile, stateless, and hard to inspect
const result1 = await claude.call("Step 1: Analyze this");
const result2 = await claude.call("Step 2: Based on '" + result1 + "', do this");
// If this fails, you have to start over from scratch
使用 CVM 时,你只需编写一个简单程序。虚拟机负责管理状态:
// Resilient, stateful, and observable
function main() {
const step1 = CC("Step 1: Analyze this");
const step2 = CC("Step 2: Based on '" + step1 + "', do this");
return step2;
}
神奇之处在于:CVM 会在进入 step2 前保存 step1。你可以随时停止、检查并恢复执行。
立即试用
需要 Node.js 22 或更高版本。
将以下内容保存为 counter.ts:
function main() {
var count = 0;
while (count < 5) {
var next = CC("Current number is " + count + ". What's the next number?");
count = +next;
}
return count;
}
告诉 Claude:“使用 CVM 运行 counter.ts”
接下来会发生什么:
- CVM 加载你的程序并开始执行
- 每遇到一次
CC(),CVM 都会暂停并等待 - Claude 获取下一个任务:“当前数字是 0。下一个数字是多少?”
- Claude 提交“1”
- CVM 更新
count并继续循环 - 重复上述过程,直到完成
范式转变:作为 CPU 的 Claude
graph LR
subgraph "CVM System"
PROGRAM["📜 Program<br/>(Instructions)"]-->|"loaded into"| CVM["🖥️ CVM<br/>(CPU + RAM)"]
CVM-->|"executes until CC()<br/>then halts"| HALT["⏸️ Halted<br/>(Awaiting input)"]
HALT-->|"getTask"| CLAUDE["🧠 Claude<br/>(Driver)"]
CLAUDE-->|"submitTask"| CVM
USER["👤 User<br/>(Observer)"]-."can interact<br/>with Claude".->CLAUDE
end
传统脚本把 Claude 当作服务。CVM 则把 Claude 当作驱动器。
为什么 CVM 能为开发者带来巨大改变
独特的架构优势:
- 反转控制流:你的代码不再调用 AI API,虚拟机只需暂停并等待。Claude 准备好后会主动获取任务
- 状态保留:虚拟机在交互过程中维护所有状态,防止长时间运行的任务丢失上下文
- 专注于认知任务:开发者只需处理特定决策点,无需管理整个流程
开发者体验:
- 简单的 API:只有 6 个直观的函数(load、start、getTask、submitTask、status 等)
- 原生支持 TypeScript:使用熟悉的 TypeScript 语法编写程序
- 职责清晰分离:代码负责确定性逻辑,AI 负责认知任务
- 文件持久化:调用之间自动管理状态
开发者适用场景:
- 需要 AI 推理的复杂多步骤工作流
- 包含智能决策点的数据处理管道
- 能根据上下文进行调整的交互式开发工具
- 需要创造性输入的测试场景
- 带检查点的代码生成工作流
特别之处: Claude 文档中的“GPS 类比”非常贴切——开发者编写路线,却不必担心在复杂流程中迷路。虚拟机会逐步引导执行,因此非常适合那些可能会让 AI 上下文窗口不堪重负的任务。
对于想要构建 AI 增强型工具,又不想费力处理提示词工程和状态管理复杂问题的开发者来说,这种方式尤其优雅。
CC() 是暂停点,而不是调用
CC(prompt) 并不表示“调用 Claude”,而是表示:
stateDiagram-v2
[*] --> Package: CC(analyze this)
Package --> PAUSE: Create task
PAUSE --> WAIT: Execution stops here
WAIT --> PULL: Claude calls getTask
PULL --> PROCESS: Claude processes
PROCESS --> RESUME: Claude submits result
RESUME --> [*]: Continue with result
state Package {
[*] --> p1: Package prompt
p1 --> p2: Into task object
}
state PAUSE {
[*] --> pause: ⏸️ Program paused
pause --> save: State saved
}
state WAIT {
[*] --> waiting: 🔄 Waiting for Claude
}
这就像 Python 中的 yield 或 JavaScript 中的 await,只不过用于认知任务。
实际示例
function main() {
var files = fs.listFiles("./docs");
var summaries = []; // State lives safely in CVM
for (const file of files) {
// PAUSE: Ask Claude to summarize this file
var content = CC("Read and summarize: " + file);
summaries.push({ filename: file, summary: content });
// CVM automatically resumes here with content
}
// PAUSE: Ask Claude to create final report
var report = CC("Create report from: " + JSON.stringify(summaries));
return report;
}
flowchart TD
START([Start]) --> LIST[fs.listFiles]
LIST --> INIT[summaries = empty array]
INIT --> LOOP{For each file}
LOOP -->|Has files| CC1[CC: Read and summarize file]
CC1 --> PAUSE1[⏸️ CVM Pauses]
PAUSE1 --> CLAUDE1[Claude pulls task]
CLAUDE1 --> SUMMARY[Claude returns summary]
SUMMARY --> SAVE[Push to summaries array]
SAVE --> LOOP
LOOP -->|No more files| CC2[CC: Create final report]
CC2 --> PAUSE2[⏸️ CVM Pauses]
PAUSE2 --> CLAUDE2[Claude creates report]
CLAUDE2 --> RETURN[Return report]
RETURN --> END([End])
CRASH{{If crash at file 500}} -.-> STATE[(CVM State:<br/>499 summaries<br/>preserved)]
STATE -.-> RESUME[Can resume<br/>from file 500]
CVM 会将其转变为可靠的工作流。如果处理 1000 个文件时在第 500 个文件处失败,前 499 个文件的摘要已安全保存在 CVM 的状态中。
为什么不直接写 Python 脚本?
graph LR
subgraph YourScript["Your Script"]
S1[❌ Stateless]
S2[❌ Fragile]
S3[❌ Opaque]
S4[❌ Rigid]
S1 --> API1[API Call 1]
API1 --> S2
S2 --> API2[API Call 2]
API2 --> S3
S3 --> CRASH[💥 Crash = Start Over]
end
subgraph CVMArch["CVM"]
C1[✅ Stateful]
C2[✅ Resilient]
C3[✅ Observable]
C4[✅ Flexible]
C1 --> TASK1[Task 1]
TASK1 --> STATE1[(State Preserved)]
STATE1 --> TASK2[Task 2]
TASK2 --> STATE2[(State Updated)]
STATE2 --> PAUSE[⏸️ Can Pause/Resume]
end
| 你的脚本 | CVM |
|---|---|
| ❌ 无状态: 每次 API 调用都会从头开始 | ✅ 有状态: 所有变量都会自动保留 |
| ❌ 脆弱: 崩溃 = 重新开始 | ✅ 可靠: 状态会保留,可随时恢复 |
| ❌ 不透明: 无法查看进度 | ✅ 可观察: 可随时检查状态 |
| ❌ 僵化: 无法介入 | ✅ 灵活: 默认在每个 CC() 处暂停 |
底层工作原理
CVM 是一个被动的 MCP 服务。Claude 会主动驱动执行:
sequenceDiagram
participant Claude
participant CVM
participant State as CVM State
Claude->>CVM: load("counter", "...program code...")
CVM->>State: Store program
Claude->>CVM: start("counter", "exec-123")
CVM->>State: Initialize count = 0
loop While count < 5
Claude->>CVM: getTask("exec-123")
CVM-->>Claude: "Current number is 0. What's the next number?"
Claude->>Claude: Process task
Claude->>CVM: submitTask("exec-123", "1")
CVM->>State: count = 1
Note over CVM: Continue loop execution
end
Claude->>CVM: getTask("exec-123")
CVM-->>Claude: "Execution completed with result: 5"
CVM 完全被动——它绝不会主动发起任何操作。一切都由 Claude 驱动。
基于 MCP(模型上下文协议)构建
上方展示的 getTask/submitTask 交互遵循 Claude 的模型上下文协议(MCP)。MCP 是一项用于构建有状态、可靠工具的规范,Claude 可以操作这些工具。CVM 作为 MCP 服务运行,因此 Claude 能够主动驱动执行。使用 CVM 不需要了解 MCP,但知道它基于这一标准构建,有助于理解其独特的被动架构。
CVM 的工作原理:解释器
你可能会想:“TypeScript 的 while 循环怎么能在执行过程中暂停?”答案是,CVM 并不是用 Node.js 或 ts-node 运行你的代码,而是使用自定义解释器来:
- 解析 类 TypeScript 代码,并将其转换为抽象语法树(AST)
- 遍历 这棵树,逐步执行每条指令
- 遇到
CC()时暂停,并保存完整的执行状态 - Claude 提交结果后,从完全相同的位置恢复
这就是 CVM 可以在任意位置暂停的原因——它运行的不是原生 JavaScript,而是逐条谨慎地解释并执行你的代码。
CVM 本身也用 CVM 构建
CVM 自身的开发通过 CVM 程序来管理!这不只是自用验证——这证明了 CVM 能够处理复杂的真实开发工作流:
🔧 功能演进程序
- RegExp 实现 - 使用 TDD 添加模式匹配
- String 与 Array 方法 - 系统地实现 15 种方法
- Object Keys 与 For 循环 - 增强语言特性
🏗️ 架构重构
这些程序引导 Claude 完成数百项协调一致的更改:
- 先编写失败的测试(TDD)
- 一步步实现功能
- 在更改之间运行测试套件
- 系统地提交进度
- 自动更新文档
每个程序都会将复杂任务拆分为多个认知检查点,由 Claude 提供实现、审查代码、修复问题并验证正确性,同时由 CVM 在整个工作流中完美保留状态。
CVM 计划协议(CVM-PP):让 Agent 自主执行计划
你不必为每项任务手写 CVM 程序。CVM 支持 CVM 计划协议(CVM-PP):将工作写成结构化的 Markdown 计划(任务目标 + 有序的原子步骤列表),只要计划符合 CVM-PP 格式,CVM 就知道如何运行它——随后,AI Agent 会一次执行一项任务,自主推进计划。
CVM 不会执行工作——它负责安排执行顺序。它会将计划转换为一系列检查点,并一次向 Agent 分配一项任务(编写失败测试 → 实现功能 → 验证每项标准 → 提交),同时自行维护整个循环、重试、恢复和进度状态。Agent 负责实际工作并汇报结果;CVM 则继续推进。这与 CC() 的导绳理念相同,只不过应用于整个开发计划,让 Agent 无需将整个计划都保留在上下文中,也能按步骤完成长计划。
flowchart LR
PLAN["📄 Markdown plan<br/>(mission + blocks)"] -->|parsePlan| UPLAN["🧩 uplan.json<br/>(validated + compiled)"]
UPLAN -->|planexecutor| SEQ["🔁 One task at a time<br/>RED → GREEN → VERIFY → COMMIT"]
SEQ -->|CC checkpoint| AGENT["🧠 AI agent<br/>does the work, reports back"]
AGENT -->|done| SEQ
包含两部分:
parsePlan— 根据语法验证计划,并将其编译为.cvm/uplan.json。遇到任何不符合项时,都会以精确的line N: message错误信息失败。planexecutor— 遍历各个步骤,每次向 Agent 发送一个阶段任务,并在收到完成报告后继续推进。已完成的步骤会保存为检查点,写入.cvm/uplan-progress.json,这样运行中断后就能从上次进度恢复。
计划分为两种类型:tddab(测试驱动步骤,RED → GREEN → VERIFY → CROSS-CHECK → COMMIT)和 step(操作步骤,EXECUTE → VERIFY → COMMIT);计划既可以写在单个文件中,也可以由索引文件和多个子文件组成。
CVM-PP 是有文档说明且稳定的协议。 只要 AI(或任何工具)生成的计划符合该协议,就可以立即驱动执行,无需转换。完整规范(语法、验证规则、示例和编写检查清单)见 docs/PLAN_FORMAT.md,旨在作为外部计划生成器的互操作标准。
通用 Skills:将 CVM 与任何 AI Agent 搭配使用
CVM 提供三个通用技能——独立的 Markdown 指南,让任何 AI Agent 无需维护者定制的 Agent 配置,就能编写、审查和执行 CVM-PP 计划。每个技能都将 docs/PLAN_FORMAT.md 作为格式的唯一事实来源。
- skills/cvm-plan-create/SKILL.md — 编写有效的 CVM-PP 计划(任务目标 + 原子步骤),然后使用
parsePlan验证。 - skills/cvm-plan-review/SKILL.md — 在执行前审查计划:先通过
parsePlan进行机器验证,再进行语义质量审查。 - skills/cvm-plan-execute/SKILL.md — 通过
parsePlan → start → getTask/submitTask循环,从头到尾执行已验证的计划。
安装(Claude Code)
将每个技能目录复制到项目的 .claude/skills/ 文件夹中:
mkdir -p .claude/skills
cp -r skills/cvm-plan-create .claude/skills/
cp -r skills/cvm-plan-review .claude/skills/
cp -r skills/cvm-plan-execute .claude/skills/
也可以创建符号链接,以便同步跟踪此仓库的更新:
mkdir -p .claude/skills
ln -s "$(pwd)/skills/cvm-plan-create" .claude/skills/cvm-plan-create
ln -s "$(pwd)/skills/cvm-plan-review" .claude/skills/cvm-plan-review
ln -s "$(pwd)/skills/cvm-plan-execute" .claude/skills/cvm-plan-execute
这些技能是带有 YAML frontmatter 的纯 Markdown 文件——与 Agent 无关。其他 Agent 框架也可以直接读取相同的 SKILL.md 文件;除了上文所述的安装路径外,它们没有任何部分专为 Claude Code 设计。
语言特性与限制
CVM 使用自定义解释器,因此支持一个类似 TypeScript、旨在确保可靠性和安全性的子集。
✅ 支持的特性
| 特性 | 示例 |
|---|---|
| 变量 | var name = "CVM"; var version = 1; |
| 基本类型 | 字符串、数字、布尔值、null、undefined |
| 数组 | [1, 2, 3]、items.push(4)、items[0] |
| 对象 | {name: "Claude", age: 2}、obj.name |
| 循环 | while (i < 5)、for (const item of array) |
| 条件语句 | if (x > 10) { ... } else { ... } |
| 运算符 | +、-、*、/、===、!==、&&、` |
❌ 不支持
import/require语句async/await(请改用CC())- 类和
new关键字 try...catch代码块(请参阅下文的错误处理)- 箭头函数
() => {} - 展开运算符
... - 解构
const {a, b} = obj - 模板字面量
`Hello ${name}`
📦 内置函数
| 函数 | 描述 |
|---|---|
CC(prompt: string): string | 暂停执行,让 Claude 处理任务 |
console.log(...args) | 将内容输出到 CVM 控制台 |
fs.listFiles(path, options?) | 列出目录中的文件(受沙盒限制) |
JSON.stringify(obj) | 将对象转换为 JSON 字符串 |
JSON.parse(str) | 将 JSON 字符串解析为对象 |
安全与沙盒
CVM 在安全、隔离的环境中运行代码:
- 无法访问网络:脚本无法发出 HTTP 请求或访问互联网
- 文件系统限制:
fs.listFiles()仅限于 CVM 工作目录 - 无法访问系统:无法执行 shell 命令或访问环境变量
- 内存限制:脚本受到合理的内存限制
- 执行超时:长时间运行的操作会自动终止
为进一步增强安全性,我们建议在 Docker 容器中运行 CVM,以处理敏感数据。
实用用法
不使用 try...catch 处理错误
由于 CVM 不支持 try...catch,你必须谨慎验证 Claude 的响应:
// ❌ Fragile - assumes Claude returns a number
function fragileCounter() {
var count = 0;
while (count < 5) {
var next = CC("Current number is " + count + ". What's next?");
count = +next; // Fails if Claude returns "four" instead of "4"
}
}
// ✅ Robust - validates the response
function robustCounter() {
var count = 0;
while (count < 5) {
var result = CC("Current number is " + count + ". What's next?");
var nextNum = parseInt(result, 10);
if (isNaN(nextNum)) {
console.log("Invalid response: '" + result + "'. Retrying...");
// Loop continues without incrementing, effectively retrying
} else {
count = nextNum;
}
}
return count;
}
检查执行状态
你可以使用 status 工具查看任何正在运行的执行:
// Claude can check status at any time:
const status = await cvm.status("exec-123");
console.log(status);
// {
// "executionId": "exec-123",
// "status": "PAUSED",
// "currentTask": "Analyzing file 247 of 1000",
// "state": {
// "filesProcessed": 246,
// "summaries": [...]
// }
// }
这样,你可以监控长时间运行的任务并确认进度,而不会中断执行。
快速参考
Claude 使用的 MCP 工具:
load(programId, source)- 加载程序start(programId, executionId)- 启动执行getTask(executionId)- 获取下一个任务submitTask(executionId, result)- 提交结果status(executionId)- 随时检查状态parsePlan(filePath)- 验证 CVM-PP 计划并将其编译为.cvm/uplan.json(请参阅《CVM 计划协议》)
CVM 会维护:
- 所有变量及其值
- 当前执行位置
- 循环计数器和条件
- 暂停期间的完整程序状态
安装
添加到 Claude 的 MCP 设置中:
{
"mcpServers": {
"cvm": {
"command": "npx",
"args": ["cvm-server@latest"]
}
}
}
使用场景
适用于任何需要 Claude 系统化处理大量项目的工作流:
- 文档分析流水线
- 从多个来源提取数据
- 基于多个输入生成报告
- 跨多个文件重构代码
- 任何需要循环并由 AI 处理的任务
→ 完整 API 文档 → CVM 计划协议(CVM-PP)规范
关键见解
CVM 不会让 Claude 变得更聪明,而是让 Claude 做事更有条理。
不使用 CVM:能力出众,但容易混乱
使用 CVM:能力出众,且拥有完美记忆和检查清单
许可证
CVM 采用双重许可:
- AGPL-3.0-or-later — 可免费用于开源、个人、研究和内部用途,但须遵守 AGPL 网络条款(第 13 节)。
- 商业许可证 — 用于专有集成、闭源再分发,或任何与 AGPL-3.0 不兼容的用途时,必须获取此许可证。
如果你的公司希望将 CVM 集成到商业产品中、将其包含在闭源工具中,或将其作为托管服务的一部分提供而不以 AGPL 许可发布自己的代码,请参阅 COMMERCIAL.md。
**关于早期版本的说明:**所有不晚于
0.16.0-next.8的版本均采用 Apache-2.0 许可,并继续按照这些条款提供。从1.0.0版本开始,CVM 采用上述双重许可。
Copyright (C) 2025-2026 Ladislav Sopko.
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。