Harness
Harness orchestration. AForge runs by default with nothing to install; Claude Code, Codex, Gemini CLI, and OpenCode are one field away.
Harness orchestration dispatches complex work to a coding agent with full tool access and structured results. Unlike app.ai() which makes a single LLM call, app.harness() runs a multi-turn harness that can navigate codebases, run tests, and produce verified output with cost controls.
By default it runs AForge, AgentField's native harness — installed alongside the af binary, so there is nothing extra to install; export OPENROUTER_API_KEY and go. Set provider and the same call runs Claude Code, Codex, Gemini CLI, or OpenCode instead.
from pydantic import BaseModel
from agentfield import Agent
class MigrationPlan(BaseModel):
sql_statements: list[str] # ordered DDL/DML
rollback_steps: list[str] # how to undo each change
risk_assessment: str # safety analysis
# Structured output from a harness -- reads files, writes SQL, validates.
# No provider, no model: runs on AForge, AgentField's native default harness.
result = await app.harness(
f"Analyze the database schema and generate a migration plan: {description}",
schema=MigrationPlan, # validated typed output, not free text
max_turns=30, # bound the run — AForge honours turns, not USD caps
)
# Full observability — cost, turns, duration, session replay
print(f"${result.cost_usd:.3f}") # $0.042
print(f"{result.num_turns} turns") # 8 turns
print(f"{result.duration_ms}ms") # 12400ms
# Swap workers per-call — Claude Code, Codex, Gemini CLI, OpenCode
result = await app.harness(
"Generate a test suite for the payment module.",
provider="codex", # OpenAI Codex for this task
model="o4-mini",
max_turns=40,
)
# Different providers for different strengths
refactor = await app.harness(
"Refactor auth to use JWT. Run tests after.",
provider="gemini", # Gemini CLI for broad refactors
model="gemini-2.5-pro",
max_turns=25,
)
# Robust error handling — typed failure modes, not just true/false
if result.is_error:
match result.failure_type:
case "timeout": log.warning(f"Timed out after {result.duration_ms}ms")
case "crash": log.error(f"Agent crashed: {result.error_message}")
case "schema": log.warning("Output didn't match schema after retries")
case "api_error": log.error("Transient API error")
else:
plan = result.parsed # MigrationPlan, fully validatedagent.reasoner('planDbMigration', async (ctx) => {
// Coding agent reads schema, writes SQL, returns structured output.
// No provider, no model: runs on AForge, AgentField's native default harness.
const result = await agent.harness(
`Analyze the DB schema and generate a migration plan: ${ctx.input.description}`,
{
schema: MigrationPlanSchema, // validated output, not free text
maxTurns: 30, // bound the run — AForge honours turns, not USD caps
}
);
// Full observability on every call
console.log(`Cost: $${result.costUsd?.toFixed(3)}`);
console.log(`Turns: ${result.numTurns}`);
console.log(`Duration: ${result.durationMs}ms`);
// Swap workers per-call — Codex for test generation
const tests = await agent.harness(
'Generate a comprehensive test suite for the payment module.',
{ provider: 'codex', model: 'o4-mini', maxTurns: 40 }
);
// Error handling
if (result.isError) {
console.error(`Harness failed: ${result.errorMessage}`);
}
return { plan: result.parsed, cost: result.costUsd };
});// Coding agent reads files, writes SQL, returns validated struct.
// Options carries no Provider or Model: runs on AForge, the native default harness.
var plan MigrationPlan
schema, _ := harness.StructToJSONSchema(plan)
result, _ := app.Harness(ctx,
"Analyze the database schema and generate a migration plan: add user roles",
schema, &plan, // structured output
harness.Options{MaxTurns: 30}, // bound the run — AForge honours turns
)
// Full observability
fmt.Printf("Turns: %d | Duration: %dms\n",
result.NumTurns, result.DurationMS)
// Swap workers per-call
testResult, _ := app.Harness(ctx,
"Generate a test suite for the payment module.",
nil, nil, // no schema
harness.Options{
Provider: "claude-code", // override the worker for this task
MaxTurns: 40,
},
)
// Typed failure handling
if result.IsError {
switch result.FailureType {
case harness.FailureTimeout: log.Printf("Timed out after %dms", result.DurationMS)
case harness.FailureCrash: log.Printf("Agent crashed: %s", result.ErrorMessage)
case harness.FailureSchema: log.Printf("Schema validation failed after retries")
}
}What just happened
The harness example did not just call a model. It launched a tool-using harness, enforced turn limits, and returned structured output with execution metrics. That is the main distinction this page needs to make visible immediately.
{
"provider": "aforge",
"num_turns": 8,
"duration_ms": 12400,
"parsed_output": "validated_against_schema"
}