mcpField
C
Cvm: Stateful Programable Task Engine

Cvm: Stateful Programable Task Engine

本地服务
github.com/LadislavSopko生产力222 周前更新

关于 Cvm: Stateful Programable Task Engine

CVM 是一个以 TypeScript 语法编写程序的 MCP 服务,由 Claude 逐步驱动执行。程序在每个 CC() 处暂停并保存状态,适合需要长流程且希望中断后恢复的任务。

主要功能

  1. 01CC() 暂停执行并等待 Claude 提交结果
  2. 02执行状态在多次交互之间持久保存
  3. 03支持暂停、检查与恢复执行
  4. 04基于解释器逐条执行 TypeScript 类语法
  5. 05提供 CVM-PP 计划协议,可按计划逐项驱动 Agent

适用场景

  1. 01多文件逐个处理并汇总结果的流程
  2. 02中途失败后从断点恢复的长任务
  3. 03按 Markdown 计划分步执行的开发工作

MCP 相关

CVM 以被动 MCP 服务的形式运行,由 Claude 通过 getTask 和 submitTask 等工具拉取任务并提交结果。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"cvm": {
"command": "npx",
"args": [
"-y",
"cvm-server"
],
"env": {
"CVM_STORAGE_TYPE": "<CVM_STORAGE_TYPE>",
"CVM_DATA_DIR": "<CVM_DATA_DIR>"
}
}
}
}
启动命令npx -y cvm-server
需要配置的环境变量
CVM_STORAGE_TYPE
CVM_DATA_DIR

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

安装包
npmcvm-server

工具

15

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

此工具无需参数。

详细介绍

CVM:将 Claude 变为系统化处理器

别再编写脆弱的 AI 脚本。编写由 Claude 一次执行一个思考步骤的程序。

CVM 采用双重许可:开源使用遵循 AGPL-3.0-or-later,专有集成则使用商业许可。详情请参阅 COMMERCIAL.md。

npm version License: AGPL v3 Commercial License Available

重要

新功能: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”

接下来会发生什么:

  1. CVM 加载你的程序并开始执行
  2. 每遇到一次 CC(),CVM 都会暂停并等待
  3. Claude 获取下一个任务:“当前数字是 0。下一个数字是多少?”
  4. Claude 提交“1”
  5. CVM 更新 count 并继续循环
  6. 重复上述过程,直到完成

范式转变:作为 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 运行你的代码,而是使用自定义解释器来:

  1. 解析 类 TypeScript 代码,并将其转换为抽象语法树(AST)
  2. 遍历 这棵树,逐步执行每条指令
  3. 遇到 CC() 时暂停,并保存完整的执行状态
  4. Claude 提交结果后,从完全相同的位置恢复

这就是 CVM 可以在任意位置暂停的原因——它运行的不是原生 JavaScript,而是逐条谨慎地解释并执行你的代码。

CVM 本身也用 CVM 构建

CVM 自身的开发通过 CVM 程序来管理!这不只是自用验证——这证明了 CVM 能够处理复杂的真实开发工作流:

🔧 功能演进程序

🏗️ 架构重构

这些程序引导 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 作为格式的唯一事实来源。

安装(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.

评论

支持 Markdown

第一次接触 MCP?

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

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