# CVM: Turn Claude into a Systematic Processor
**Stop writing fragile AI scripts. Write programs that Claude executes one thought at a time.**
> **CVM is dual-licensed** under [AGPL-3.0-or-later](./LICENSE) for open source use and a [commercial license](./COMMERCIAL.md) for proprietary integration. See [COMMERCIAL.md](./COMMERCIAL.md) for details.
[](https://www.npmjs.com/package/cvm-server)
[](https://www.gnu.org/licenses/agpl-3.0)
[](./COMMERCIAL.md)
> [!IMPORTANT]
> **New: the CVM Plan Protocol (CVM-PP).** Write your work as a structured Markdown plan
> and CVM drives an AI agent through it, one task at a time β no hand-written CVM program
> needed. If a plan is in CVM-PP form, CVM knows how to run it.
> β [What it is & how it works](#the-cvm-plan-protocol-cvm-pp-let-an-agent-drive-itself-through-a-plan) Β· [Protocol specification](docs/PLAN_FORMAT.md)
**TRADITIONAL SCRIPT**
π Gray = Script Operations
```mermaid
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 ARCHITECTURE**
π’ Green = CVM Operations | π΅ Blue = Claude Actions | π‘ Yellow = Human Control
```mermaid
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
```
## See It In Action: From Fragile to Resilient
**Without CVM**, you manually chain calls. If it crashes, state is lost:
```typescript
// 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
```
**With CVM**, you write a simple program. The VM manages state:
```typescript
// 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;
}
```
The magic: CVM saves `step1` before moving to `step2`. You can stop, inspect, and resume anytime.
## Try It Now
Requires Node.js 22 or newer.
Save this as `counter.ts`:
```typescript
function main() {
var count = 0;
while (count < 5) {
var next = CC("Current number is " + count + ". What's the next number?");
count = +next;
}
return count;
}
```
Tell Claude: **"Run counter.ts with CVM"**
What happens:
1. CVM loads your program and starts execution
2. At each `CC()`, CVM pauses and waits
3. Claude pulls the next task: "Current number is 0. What's the next number?"
4. Claude submits "1"
5. CVM updates `count` and continues the loop
6. Repeat until done
## The Paradigm Shift: Claude as the CPU
```mermaid
graph LR
subgraph "CVM System"
PROGRAM["π Program
(Instructions)"]-->|"loaded into"| CVM["π₯οΈ CVM
(CPU + RAM)"]
CVM-->|"executes until CC()
then halts"| HALT["βΈοΈ Halted
(Awaiting input)"]
HALT-->|"getTask"| CLAUDE["π§ Claude
(Driver)"]
CLAUDE-->|"submitTask"| CVM
USER["π€ User
(Observer)"]-."can interact
with Claude".->CLAUDE
end
```
Traditional scripts treat Claude as a service. CVM treats Claude as the driver.
## Why CVM is a Game-Changer for Developers
**Unique Architecture Benefits:**
- **Inverted control flow**: Instead of your code calling AI APIs, the VM simply pauses and waits. Claude actively pulls tasks when ready
- **State preservation**: The VM maintains all state across interactions, preventing context loss in long-running tasks
- **Focused cognitive tasks**: Developers only need to handle specific decision points, not manage the entire flow
**Developer Experience:**
- **Simple API**: Just 6 straightforward functions (load, start, getTask, submitTask, status, etc.)
- **TypeScript native**: Write programs in familiar TypeScript syntax
- **Clean separation**: Deterministic logic in code, cognitive tasks delegated to AI
- **File persistence**: Automatic state management between calls
**Use Cases for Developers:**
- Complex multi-step workflows that need AI reasoning
- Data processing pipelines with intelligent decision points
- Interactive development tools that adapt based on context
- Testing scenarios that require creative input
- Code generation workflows with checkpoints
**What Makes It Special:**
The "GPS analogy" from Claude's docs is perfect - developers write the route, but don't have to worry about getting lost in complex flows. The VM guides execution step-by-step, making it ideal for tasks that would otherwise overwhelm AI context windows.
It's particularly elegant for developers who want to build AI-augmented tools without wrestling with prompt engineering and state management complexities.
## CC() is a PAUSE, Not a Call
`CC(prompt)` doesn't mean "call Claude." It means:
```mermaid
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
}
```
It's like `yield` in Python or `await` in JavaScript, but for cognitive tasks.
## Real-World Example
```typescript
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;
}
```
```mermaid
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:
499 summaries
preserved)]
STATE -.-> RESUME[Can resume
from file 500]
```
CVM turns this into a resilient workflow. If it fails on file 500 of 1000, the first 499 summaries are safely stored in CVM's state.
## Why Not Just Write a Python Script?
```mermaid
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
```
| Your Script | CVM |
| :--- | :--- |
| β **Stateless:** Each API call starts fresh | β
**Stateful:** All variables persist automatically |
| β **Fragile:** Crash = start over | β
**Resilient:** State survives, resume anytime |
| β **Opaque:** Can't see progress | β
**Observable:** Check status anytime |
| β **Rigid:** Can't intervene | β
**Flexible:** Paused by default at each CC() |
## How It Works Under the Hood
CVM is a passive MCP server. Claude actively drives execution:
```mermaid
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 is completely passive** - it never initiates anything. Claude drives everything.
### Built on MCP (Model Context Protocol)
The `getTask`/`submitTask` interaction shown above follows Claude's **Model Context Protocol (MCP)**. MCP is a specification for building stateful, resilient tools that Claude can operate. CVM acts as an MCP server, which is what allows Claude to actively drive the execution. You don't need to understand MCP to use CVM, but knowing it's built on this standard helps explain its unique, passive architecture.
## How CVM Works: The Interpreter
You might wonder: "How can a TypeScript `while` loop be paused mid-execution?" The answer is that CVM isn't running your code with Node.js or ts-node. Instead, CVM uses a custom interpreter that:
1. **Parses** your TypeScript-like code into an Abstract Syntax Tree (AST)
2. **Walks** this tree step-by-step, executing each instruction
3. **Pauses** when it encounters `CC()`, saving the complete execution state
4. **Resumes** from the exact same position when Claude submits a result
This is why CVM can pause anywhere - it's not running native JavaScript, but carefully interpreting your code instruction by instruction.
## Built with CVM Itself
CVM's own development is managed through CVM programs! This isn't just dogfooding - it's proof that CVM can handle complex, real-world development workflows:
**π§ Feature Evolution Programs**
- [RegExp Implementation](tasks/done/RegExp/regexp-evolution-program-v3.ts) - Added pattern matching with TDD
- [String & Array Methods](tasks/done/string-arrays/string-array-implementation-program.ts) - Implemented 15 methods systematically
- [Object Keys & For-loops](tasks/done/obj%20key%20and%20for%20c%20style/object-keys-for-switch-evolution-program.ts) - Enhanced language features
**ποΈ Architecture Refactoring**
- [CVM Evolution Executor](tasks/done/references%20usage/cvm-evolution-executor.ts) - Fixed critical architectural flaws
- [Test Coverage Analysis](tasks/done/references%20usage/test-coverage-executor.ts) - Systematic testing improvements
These programs guide Claude through hundreds of coordinated changes:
- Writing failing tests first (TDD)
- Implementing features step-by-step
- Running test suites between changes
- Committing progress systematically
- Updating documentation automatically
Each program breaks down complex tasks into cognitive checkpoints where Claude provides implementation, reviews code, fixes issues, and verifies correctness - all while CVM maintains perfect state across the entire workflow.
## The CVM Plan Protocol (CVM-PP): Let an Agent Drive Itself Through a Plan
You don't have to hand-write a CVM program for every task. CVM speaks the **CVM Plan
Protocol (CVM-PP)**: write the work as a structured Markdown **plan** (mission + an ordered
list of atomic blocks), and **if the plan is in CVM-PP form, CVM knows how to run it** β
an AI agent then **drives itself through it, one task at a time**.
CVM does *not* execute the work β it sequences it. It turns the plan into a stream of
checkpoints and hands the agent a single task at a time (write this failing test β
implement it β verify each criterion β commit), holding all the loop / retry / resume /
progress state itself. The agent does the actual work and reports back; CVM advances.
This is the same guide-rope idea as `CC()`, applied to a whole development plan, so an
agent can follow a long plan without keeping it all in its context.
```mermaid
flowchart LR
PLAN["π Markdown plan
(mission + blocks)"] -->|parsePlan| UPLAN["π§© uplan.json
(validated + compiled)"]
UPLAN -->|planexecutor| SEQ["π One task at a time
RED β GREEN β VERIFY β COMMIT"]
SEQ -->|CC checkpoint| AGENT["π§ AI agent
does the work, reports back"]
AGENT -->|done| SEQ
```
**Two pieces:**
- **`parsePlan`** β validates the plan against the grammar and compiles it to
`.cvm/uplan.json`. On any violation it fails with precise `line N: message` errors.
- **`planexecutor`** β walks the blocks, emitting one phase task at a time to the agent
and advancing as each is reported done. Completed blocks are checkpointed to
`.cvm/uplan-progress.json`, so an interrupted run **resumes** where it left off.
Plans come in two flavours: **`tddab`** (test-driven blocks, `RED β GREEN β VERIFY β
CROSS-CHECK β COMMIT`) and **`step`** (action blocks, `EXECUTE β VERIFY β COMMIT`), and
can span a single file or an index file plus multiple sub-files.
**CVM-PP is a documented, stable contract.** If an AI (or any tool) produces a plan that
conforms to the protocol, it is immediately drivable β no conversion needed. The full
specification (grammar, validation rules, examples, authoring checklist) lives in
**[docs/PLAN_FORMAT.md](docs/PLAN_FORMAT.md)** and is intended as an interop target for
external plan generators.
## Universal Skills: Use CVM Standalone with Any AI Agent
CVM ships three **universal skills** β self-contained Markdown guides that let any AI
agent author, review, and run CVM-PP plans **without the maintainer's bespoke agent
setup**. Each references [docs/PLAN_FORMAT.md](docs/PLAN_FORMAT.md) as the single source
of truth for the format.
- **[skills/cvm-plan-create/SKILL.md](skills/cvm-plan-create/SKILL.md)** β author a valid
CVM-PP plan (mission + atomic blocks), then validate it with `parsePlan`.
- **[skills/cvm-plan-review/SKILL.md](skills/cvm-plan-review/SKILL.md)** β review a plan
before execution: machine validation via `parsePlan`, then a semantic quality pass.
- **[skills/cvm-plan-execute/SKILL.md](skills/cvm-plan-execute/SKILL.md)** β drive a
validated plan end to end through the `parsePlan β start β getTask/submitTask` loop.
### Installation (Claude Code)
Copy each skill directory into your project's `.claude/skills/` folder:
```bash
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/
```
Or symlink them, so they track this repo's updates:
```bash
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
```
The skills are plain Markdown with YAML frontmatter β **agent-agnostic**. Other agent
frameworks can ingest the same `SKILL.md` files directly; nothing about them is specific
to Claude Code beyond the install path above.
## Language Features & Limitations
Since CVM uses a custom interpreter, it supports a TypeScript-like subset designed for reliability and safety.
### β
Supported Features
| Feature | Example |
| :--- | :--- |
| Variables | `var name = "CVM"; var version = 1;` |
| Basic Types | Strings, Numbers, Booleans, `null`, `undefined` |
| Arrays | `[1, 2, 3]`, `items.push(4)`, `items[0]` |
| Objects | `{name: "Claude", age: 2}`, `obj.name` |
| Loops | `while (i < 5)`, `for (const item of array)` |
| Conditionals | `if (x > 10) { ... } else { ... }` |
| Operators | `+`, `-`, `*`, `/`, `===`, `!==`, `&&`, `||` |
### β Not Supported
- `import` / `require` statements
- `async` / `await` (use `CC()` instead)
- Classes and `new` keyword
- `try...catch` blocks (see error handling below)
- Arrow functions `() => {}`
- Spread operator `...`
- Destructuring `const {a, b} = obj`
- Template literals `` `Hello ${name}` ``
### π¦ Built-in Functions
| Function | Description |
| :--- | :--- |
| `CC(prompt: string): string` | Pauses execution for Claude to process a task |
| `console.log(...args)` | Outputs to CVM console |
| `fs.listFiles(path, options?)` | Lists files in directory (sandboxed) |
| `JSON.stringify(obj)` | Converts object to JSON string |
| `JSON.parse(str)` | Parses JSON string to object |
## Security & Sandboxing
CVM runs your code in a secure, isolated environment:
- **No Network Access**: Scripts cannot make HTTP requests or access the internet
- **Filesystem Restrictions**: `fs.listFiles()` is limited to the CVM working directory
- **No System Access**: Cannot execute shell commands or access environment variables
- **Memory Limits**: Scripts are bounded by reasonable memory constraints
- **Execution Timeouts**: Long-running operations are automatically terminated
For additional security, we recommend running CVM in a Docker container when processing sensitive data.
## Practical Usage
### Error Handling Without try...catch
Since CVM doesn't support `try...catch`, you must validate Claude's responses defensively:
```typescript
// β 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;
}
```
### Checking Execution Status
You can inspect any running execution using the `status` tool:
```typescript
// 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": [...]
// }
// }
```
This allows you to monitor long-running tasks and verify progress without interrupting execution.
## Quick Reference
**MCP Tools Claude Uses**:
- `load(programId, source)` - Load a program
- `start(programId, executionId)` - Start execution
- `getTask(executionId)` - Pull next task
- `submitTask(executionId, result)` - Submit result
- `status(executionId)` - Check state anytime
- `parsePlan(filePath)` - Validate a CVM-PP plan and compile it to `.cvm/uplan.json` (see [The CVM Plan Protocol](#the-cvm-plan-protocol-cvm-pp-let-an-agent-drive-itself-through-a-plan))
**What CVM Maintains**:
- All variables and their values
- Current execution position
- Loop counters and conditions
- Complete program state between pauses
## Installation
Add to Claude's MCP settings:
```json
{
"mcpServers": {
"cvm": {
"command": "npx",
"args": ["cvm-server@latest"]
}
}
}
```
## Use Cases
Perfect for any workflow where Claude needs to process many items systematically:
- Document analysis pipelines
- Data extraction from multiple sources
- Report generation with multiple inputs
- Code refactoring across many files
- Any task requiring loops with AI processing
[β Full API Documentation](docs/API.md)
[β CVM Plan Protocol (CVM-PP) Specification](docs/PLAN_FORMAT.md)
## The Key Insight
CVM doesn't make Claude smarter. It makes Claude systematic.
Without CVM: Brilliant but chaotic
With CVM: Brilliant with perfect memory and a checklist
---
## License
CVM is **dual-licensed**:
- **[AGPL-3.0-or-later](./LICENSE)** β free for open source, personal, research, and internal use that complies with the AGPL network clause (section 13).
- **[Commercial license](./COMMERCIAL.md)** β required for proprietary integration, closed-source redistribution, or any use incompatible with AGPL-3.0.
If you are a company that wants to integrate CVM into a commercial product, ship it inside a closed-source tool, or expose it as part of a hosted service without releasing your own code under AGPL, see [COMMERCIAL.md](./COMMERCIAL.md).
> **Note on previous versions:** All releases up to and including version `0.16.0-next.8` were licensed under Apache-2.0 and remain available under those terms. Starting from version `1.0.0`, CVM is dual-licensed as described above.
---
Copyright (C) 2025-2026 Ladislav Sopko.