← Blog

Graft v1.2: From Code Generator to Execution Engine

3 min read
graftcompileraiclaude-codeadversarial-debateruntime

What is Graft?

Graft is a graph-native language that compiles .gft files to Claude Code harness structures, eliminating token waste in multi-agent AI pipelines through typed schemas and edge transforms.

What v1.2 Adds

graft run — the command that turns Graft from a code generator into an execution engine:

graft run pipeline.gft --input '{"title": "crash on login", "description": "..."}'

Instead of compiling to .claude/ and letting humans orchestrate, graft run compiles AND executes the pipeline by spawning Claude Code subagents automatically.

Runtime Architecture

The runtime is a tree-walking interpreter over FlowNode[] from the compiled AST:

  • Parallel execution via Promise.allSettled (not Promise.all)
  • Foreach iteration with max_iterations cap
  • Edge transforms as pure TypeScript functions (~80 lines, no jq dependency)
  • File-based data passing via .graft/session/node_outputs/
  • Mock spawner injection via SpawnerFn for testing

Additional CLI options:

  • --dry-run — simulate execution without spawning real Claude subprocesses
  • --verbose — print detailed execution progress
  • --timeout <seconds> — configurable subprocess timeout (default 5 minutes)
  • --work-dir <dir> — specify working directory

The Forced Dissenter's Most Productive Self-Rebuttal

A4-Specialist scored 8/10 confidence (highest) and became the forced dissenter. The self-rebuttal was the most productive part of the debate:

1. generateAgent() Reuse

A4 proposed reusing the existing generateAgent() function for runtime prompts. Then argued against their own proposal:

"The function produces markdown with YAML frontmatter and ===NODE_COMPLETE=== sentinels designed for manual Claude Code mode. The runtime needs a plain prompt that says 'output JSON only.' These are fundamentally different output contracts."

All 4 agents agreed after this self-rebuttal. A separate buildPrompt() was created for runtime.

2. ExecutionContext Class

A4 proposed academic-style state threading with a typed context class. Self-rebutted: "plain Map<string, unknown> suffices."

3. Full Failure Strategies

A4 proposed implementing retry/fallback/skip strategies. Self-rebutted: "adds ~80 lines of untestable-without-real-CLI code." Deferred — the code is structured so they can be added later.


A3-Skeptic's Two Showstoppers

stdin.end() Required After Spawn

Without calling stdin.end() immediately after spawning the Claude CLI subprocess, it hangs forever waiting for input. No timeout can save you — the process simply never terminates. This is a fundamental Node.js child process behavior that A3 caught before any code was written.

Promise.allSettled, Not Promise.all

For parallel execution, Promise.all rejects on the first failure and silently discards successful branch results. If three branches succeed and one fails, you lose all three results. Promise.allSettled collects all outcomes — successes and failures — so partial results are preserved.


Stats

| Metric | Value | |--------|-------| | New source lines | ~400 | | New tests | 36 (171 total) | | Agent calls | ~14 | | New ratchet decisions | 12 (70 total) | | Dependencies added | 0 |

Try It

git clone https://github.com/JSLEEKR/graft.git
cd graft && npm install && npm run build
node dist/index.js run examples/hello.gft --input '{"title":"test"}' --dry-run

Built with Claude Opus 4.6 via Claude Code. April 2026.