bama
BAMA: Build Any Mac App. Agent skills to research, clone, design, build, optimize, and test native macOS apps with Swift and SwiftUI.
翻译准备中
Run Claude as a step-by-step agent using structured plans or programs
翻译准备中
AI 摘要 · README
技能TypeScript · HTMLGitHub @LadislavSopko自行安装运营者未确认
试用过了吗? 点一下就好,无需登录。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
安装型项目无需部署域名也可验证。个人仓库可通过 GitHub 登录验证,组织仓库可使用上方的仓库验证文件。
正在加载完整 README。 以下为已保存的摘录。
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 for open source use and a commercial license for proprietary integration. See COMMERCIAL.md for details.
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 · Protocol specification查看完整 README ↗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 for open source use and a commercial license for proprietary integration. See COMMERCIAL.md for details.
[!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 · Protocol specification
TRADITIONAL SCRIPT
🔘 Gray = Script Operations
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
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
Without CVM, you manually chain calls. If it crashes, state is lost:
// 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:
// 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.
Requires Node.js 22 or newer.
Save this as 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;
}
Tell Claude: "Run counter.ts with CVM"
What happens:
CC(), CVM pauses and waitscount and continues the loopgraph 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
Traditional scripts treat Claude as a service. CVM treats Claude as the driver.
Unique Architecture Benefits:
Developer Experience:
Use Cases for Developers:
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(prompt) doesn't mean "call Claude." It means:
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.
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 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.
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() |
CVM is a passive MCP server. Claude actively drives execution:
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.
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.
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:
CC(), saving the complete execution stateThis is why CVM can pause anywhere - it's not running native JavaScript, but carefully interpreting your code instruction by instruction.
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
🏗️ Architecture Refactoring
These programs guide Claude through hundreds of coordinated changes:
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.
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.
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
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 and is intended as an interop target for external plan generators.
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 as the single source of truth for the format.
parsePlan.parsePlan, then a semantic quality pass.parsePlan → start → getTask/submitTask loop.Copy each skill directory into your project's .claude/skills/ folder:
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:
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.
Since CVM uses a custom interpreter, it supports a TypeScript-like subset designed for reliability and safety.
| 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 | +, -, *, /, ===, !==, &&, ` |
import / require statementsasync / await (use CC() instead)new keywordtry...catch blocks (see error handling below)() => {}...const {a, b} = obj`Hello ${name}`| 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 |
CVM runs your code in a secure, isolated environment:
fs.listFiles() is limited to the CVM working directoryFor additional security, we recommend running CVM in a Docker container when processing sensitive data.
Since CVM doesn't support try...catch, you must validate Claude's responses defensively:
// ❌ 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;
}
You can inspect any running execution using the status tool:
// 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.
MCP Tools Claude Uses:
load(programId, source) - Load a programstart(programId, executionId) - Start executiongetTask(executionId) - Pull next tasksubmitTask(executionId, result) - Submit resultstatus(executionId) - Check state anytimeparsePlan(filePath) - Validate a CVM-PP plan and compile it to .cvm/uplan.json (see The CVM Plan Protocol)What CVM Maintains:
Add to Claude's MCP settings:
{
"mcpServers": {
"cvm": {
"command": "npx",
"args": ["cvm-server@latest"]
}
}
}
Perfect for any workflow where Claude needs to process many items systematically:
→ Full API Documentation → CVM Plan Protocol (CVM-PP) Specification
CVM doesn't make Claude smarter. It makes Claude systematic.
Without CVM: Brilliant but chaotic With CVM: Brilliant with perfect memory and a checklist
CVM is dual-licensed:
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.
Note on previous versions: All releases up to and including version
0.16.0-next.8were licensed under Apache-2.0 and remain available under those terms. Starting from version1.0.0, CVM is dual-licensed as described above.
Copyright (C) 2025-2026 Ladislav Sopko.