Guide
Pipeline Composition
Pipelines chain multiple Boxes into a sequence where the output of one stage becomes the input of the next. Each stage boots a fresh micro-VM, so there are no state leaks between stages.
1. Why pipelines
Running everything in a single agent context means a long-lived VM accumulates side effects: temp files, environment mutations, leaked credentials in memory. Pipelines solve this by giving each stage a clean slate.
- Fresh VM per stage — no cross-contamination.
- Explicit data flow via
/workspace/input.json. - Independent timeouts and resource limits per stage.
2. Simple 2-stage pipeline
The quick_demo.rs example chains an analyst and a strategist:
use void_box::agent_box::VoidBox;
use void_box::pipeline::Pipeline;
use void_box::skill::Skill;
let reasoning = Skill::agent("claude-code");
let analyst = VoidBox::new("analyst")
.skill(reasoning.clone())
.prompt("List 3 bullish and 3 bearish signals for AAPL.")
.build()?;
let strategist = VoidBox::new("strategist")
.skill(reasoning.clone())
.prompt("Read /workspace/input.json and produce a BUY/SELL/HOLD verdict.")
.build()?;
let result = Pipeline::named("quick_demo", analyst)
.pipe(strategist)
.run().await?;
3. Fan-out (parallel stages)
Use .fan_out() to run multiple Boxes in parallel. All receive the same input from the previous stage.
let result = Pipeline::named("research", researcher)
.fan_out(vec![analyst, writer]) // parallel
.run().await?;
4. Pipeline results API
The PipelineResult returned by .run() gives you structured access to every stage:
println!("Success: {}", result.success());
println!("Cost: ${:.4}", result.total_cost_usd());
println!("Stages: {}", result.stages.len());
for stage in &result.stages {
println!(" {} — {} tokens",
stage.box_name,
stage.claude_result.input_tokens + stage.claude_result.output_tokens);
}
5. Next
Define pipelines declaratively with YAML Specs, or run agents with local LLMs via Ollama.
