Agent Harness Patterns
Anvil can serve as a "harness" for AI coding agents—constraining their actions and validating their outputs.
The Problem
AI coding agents (Claude, GPT-Engineer, Aider, etc.) can:
- Write code autonomously — with varying quality
- Execute commands — potentially destructive
- Make architectural decisions — without understanding your constraints
Without guardrails, agents drift from your intended architecture.
Anvil as a Harness
A harness constrains an agent's behaviour:
┌────────────────────────────────────────────────┐
│ Harness │
│ │
│ Agent ──▶ Plan ──▶ Execute ──▶ Validate │
│ │ │ │
│ └──────── Anvil ───────┘ │
│ │
└────────────────────────────────────────────────┘
Plan Constraint
Agent works within a defined plan:
## Task: AUTH-001
Outcome: Users can log in with email/password
Allowed files:
- src/auth/\*\*
- src/types/auth.ts
Forbidden:
- src/payments/\*\*
- Any database migrations
Execution Validation
Every change is validated before acceptance:
Agent: "I've created src/auth/login.ts"
Anvil: ✓ File is within allowed scope
Anvil: ✓ No architecture violations
Anvil: ✓ No anti-patterns detected
Harness: Accept change
Rejection Flow
Agent: "I've modified src/payments/processor.ts"
Anvil: ✗ File outside task scope
Harness: Reject change
Agent: "Understood. I'll find another approach."
Implementation Patterns
Pattern 1: Wrapper Script
Wrap your agent invocation:
#!/bin/bash
# run-agent.sh
# Start Anvil in watch mode (background)
anvil watch --json > anvil.log &
ANVIL_PID=$!
# Run agent
your-agent-cli "$@"
# Check Anvil results
if grep -q '"status":"fail"' anvil.log; then
echo "Agent produced failing code"
exit 1
fi
kill $ANVIL_PID
Pattern 2: MCP Integration
Use Anvil via MCP (Model Context Protocol):
{
"mcpServers": {
"anvil": {
"command": "anvil",
"args": ["mcp", "serve"]
}
}
}
The agent can then:
- Query allowed files for a task
- Validate changes before proposing
- Check current violations
Pattern 3: Pre-commit Hook
Catch issues before they're committed:
#!/bin/bash
# .git/hooks/pre-commit
anvil run --staged
if [ $? -ne 0 ]; then
echo "Anvil validation failed. Commit blocked."
exit 1
fi
Pattern 4: Plan-First Workflow
Require a plan before agent execution:
# 1. Create plan
anvil plan create --task "Add user authentication"
# 2. Review and approve plan
cat plans/execution/AUTH-001.steps.md
# Edit if needed
# 3. Run agent within plan
anvil session start --task AUTH-001
your-agent-cli "Implement AUTH-001"
anvil session end
Example: Claude + Anvil
Using Claude with Anvil harness:
import { AnvilClient } from '@eddacraft/anvil-client';
import { Anthropic } from '@anthropic-ai/sdk';
const anvil = new AnvilClient();
const claude = new Anthropic();
async function runWithHarness(task: string) {
// Start Anvil session
const session = await anvil.startSession({ task });
// Get task constraints
const constraints = await anvil.getTaskConstraints(task);
// Run Claude with constraints in prompt
const response = await claude.messages.create({
model: 'claude-3-opus-20240229',
messages: [
{
role: 'user',
content: `
Task: ${constraints.outcome}
Allowed files: ${constraints.allowedFiles.join(', ')}
Forbidden: ${constraints.forbiddenPatterns.join(', ')}
Implement this task.
`,
},
],
});
// Validate Claude's output
const validation = await anvil.validate(response.content);
if (validation.status === 'fail') {
// Rejection flow
return await runWithHarness(task); // Retry with feedback
}
await anvil.endSession(session.id);
return response;
}
Telemetry and Learning
Track agent behaviour over time:
anvil evidence list --agent claude --since 30d
Analyse:
- Violation rate — how often does the agent drift?
- Common violations — what patterns recur?
- Improvement over time — is the agent learning from rejections?
Next: GitHub integration →