TL;DR
- Agent harness: The orchestration layer that manages AI agents, tools, and workflows
- Content engineering: Structuring knowledge for AI consumption—prompts, documentation, and data
- Compound engineering: Each unit of work makes the next one easier through documented learnings
- Together: These patterns form the foundation of AI-native development
Agentic engineering patterns represent a new paradigm for building software. Instead of writing code directly, you engineer systems where AI agents are first-class citizens. The agent harness provides the orchestration, content engineering structures knowledge for AI consumption, and compound engineering ensures continuous improvement.
Related Articles
- From Vibe Coding to Agentic Engineering — The transition from AI-assisted to AI-native development
- Compound Engineering - The Next Paradigm Shift — How each unit of work compounds
- Context Engineering: Parenting for AI — Structuring context for better agent performance
- Antfarm Patterns: Orchestrating Specialized Agent Teams — Multi-agent workflows in practice
What Are Agentic Engineering Patterns?
Traditional software engineering patterns—Factory, Observer, Strategy—were designed for human-written code. Agentic engineering patterns are designed for systems where AI agents do the work.
The fundamental shift:
| Traditional Engineering | Agentic Engineering |
|---|---|
| Write code directly | Engineer agent workflows |
| Code is static | Agents learn and adapt |
| Patterns for humans | Patterns for AI consumption |
| Documentation is optional | Documentation is input |
| Technical debt accumulates | Knowledge compounds |
Agentic engineering patterns fall into three categories:
- Agent Harness Patterns — Orchestrating agents, tools, and workflows
- Content Engineering Patterns — Structuring knowledge for AI consumption
- Compound Engineering Patterns — Enabling continuous improvement
These patterns work together to create systems where AI agents are effective, reliable, and continuously improving.
Part 1: Agent Harness Patterns
The agent harness is the orchestration layer that manages AI agents, tools, and workflows. It’s the infrastructure that makes agentic systems possible.
The Agent Lifecycle Pattern
Every agent follows a predictable lifecycle:
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │Initialize│ → │Execute│ → │Observe│ → │Learn│ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ ↓ ↓ ↓ ↓ │
│ Load Run Capture Update
│ context tools state patterns │
│ & tools & prompt & results & prompts │
│ │
└─────────────────────────────────────────────────────────────────┘
Implementation:
interface AgentLifecycle {
initialize: (context: Context, tools: Tool[]) => Promise<AgentState>;
execute: (state: AgentState, input: Input) => Promise<Output>;
observe: (output: Output) => Promise<Observation>;
learn: (observation: Observation) => Promise<void>;
}
class AgentHarness implements AgentLifecycle {
async initialize(context: Context, tools: Tool[]) {
return {
context: await this.loadContext(context),
tools: this.registerTools(tools),
patterns: await this.loadPatterns(),
history: []
};
}
async execute(state: AgentState, input: Input) {
const prompt = this.buildPrompt(state, input);
const result = await this.llm.complete(prompt, { tools: state.tools });
return this.parseResult(result);
}
async observe(output: Output) {
return {
success: this.evaluateSuccess(output),
patterns: this.extractPatterns(output),
learnings: this.extractLearnings(output)
};
}
async learn(observation: Observation) {
await this.updatePatterns(observation.patterns);
await this.updateLearnings(observation.learnings);
await this.refinePrompts(observation);
}
}
The Tool Registration Pattern
Agents need tools to interact with the world. The tool registration pattern standardizes how tools are discovered, registered, and invoked.
interface Tool {
name: string;
description: string;
parameters: z.ZodSchema;
execute: (params: any) => Promise<any>;
}
class ToolRegistry {
private tools = new Map<string, Tool>();
register(tool: Tool) {
this.tools.set(tool.name, tool);
}
get(name: string): Tool | undefined {
return this.tools.get(name);
}
getAll(): Tool[] {
return Array.from(this.tools.values());
}
// Auto-generate tool descriptions for LLM
getToolDescriptions(): string {
return this.getAll()
.map(t => `- ${t.name}: ${t.description}`)
.join('\n');
}
}
// Usage
const registry = new ToolRegistry();
registry.register({
name: 'read-file',
description: 'Read the contents of a file at the given path',
parameters: z.object({ path: z.string() }),
execute: async ({ path }) => await fs.readFile(path, 'utf-8')
});
The Workflow Composition Pattern
Workflows compose agents into coordinated systems. This pattern enables complex tasks through simple, composable components.
type WorkflowStep = Agent | Workflow;
class Workflow {
constructor(
private name: string,
private steps: WorkflowStep[],
private config: WorkflowConfig
) {}
async execute(input: any): Promise<any> {
let result = input;
for (const step of this.steps) {
if (step instanceof Agent) {
result = await step.execute(result);
} else {
result = await step.execute(result);
}
// Checkpoints enable idempotency
if (this.config.checkpoints) {
await this.saveCheckpoint(step, result);
}
// Conditional routing
if (this.shouldBranch(result)) {
result = await this.executeBranch(result);
}
}
return result;
}
private shouldBranch(result: any): boolean {
return result.branch !== undefined;
}
private async executeBranch(result: any): Promise<any> {
const branch = this.config.branches[result.branch];
if (!branch) throw new Error(`Unknown branch: ${result.branch}`);
return branch.execute(result);
}
}
// Usage: Feature development workflow
const featureWorkflow = new Workflow('feature-development', [
researcherAgent,
architectAgent,
builderAgent,
reviewerAgent,
documenterAgent
], { checkpoints: true });
The State Management Pattern
Agents need observable state for debugging and learning. This pattern captures every decision and outcome.
interface AgentState {
context: Context;
tools: Tool[];
history: StateEntry[];
currentStep: string;
}
interface StateEntry {
timestamp: Date;
step: string;
input: any;
reasoning: string;
output: any;
metrics: Metrics;
}
class StateManager {
private history: StateEntry[] = [];
async record(entry: StateEntry) {
this.history.push(entry);
await this.persist(entry);
}
async getHistory(limit?: number): Promise<StateEntry[]> {
return limit ? this.history.slice(-limit) : this.history;
}
async getLearnings(): Promise<Learning[]> {
return this.history
.filter(e => e.learnings)
.flatMap(e => e.learnings);
}
// Export for analysis
async exportAnalysis(): Promise<WorkflowAnalysis> {
return {
totalSteps: this.history.length,
averageDuration: this.calculateAverageDuration(),
successRate: this.calculateSuccessRate(),
commonPatterns: this.extractCommonPatterns(),
bottlenecks: this.identifyBottlenecks()
};
}
}
Part 2: Content Engineering Patterns
Content engineering is the discipline of structuring knowledge for AI consumption. Unlike traditional documentation, content engineering treats knowledge as input data for AI systems.
The Schema-First Pattern
AI agents need structured, validated data. The schema-first pattern defines data models before content.
# schemas/pattern.yaml
type: object
properties:
name:
type: string
description: "Human-readable pattern name"
problem:
type: string
description: "What problem does this pattern solve?"
solution:
type: string
description: "How is the problem solved?"
code:
type: string
description: "Example implementation"
related:
type: array
items:
type: string
description: "Related patterns to explore"
tags:
type: array
items:
type: string
learned:
type: string
format: date
description: "When this pattern was documented"
The Context Hierarchy Pattern
Organize content by accessibility and relevance. Not all content belongs in every agent’s context.
Content Hierarchy:
├── Core Patterns (always included)
│ ├── Authentication patterns
│ ├── Error handling patterns
│ └── API design patterns
├── Domain Knowledge (included by relevance)
│ ├── Business logic patterns
│ ├── Data model conventions
│ └── Integration patterns
├── Historical Context (included on request)
│ ├── Architecture decisions
│ ├── Migration history
│ └── Past solutions
└── Ephemeral Context (per-session)
├── Current task context
├── Recent conversations
└── Session-specific learnings
Implementation:
class ContextBuilder {
async build(request: ContextRequest): Promise<Context> {
const context = {
core: await this.loadCorePatterns(),
domain: await this.loadDomainPatterns(request.domain),
historical: request.includeHistory
? await this.loadHistoricalContext(request.scope)
: [],
ephemeral: request.sessionContext
};
// Validate context size
if (await this.estimateTokens(context) > MAX_CONTEXT) {
return this.pruneContext(context, request.priorities);
}
return context;
}
}
The Prompt Template Pattern
Prompts are code. Template them for reuse and maintainability.
// templates/agent/system.hbs
You are a {{role}} agent with the following responsibilities:
{{responsibilities}}
## Available Tools
{{#each tools}}
- {{name}}: {{description}}
{{/each}}
## Patterns to Follow
{{#each patterns}}
### {{name}}
**Problem**: {{problem}}
**Solution**: {{solution}}
{{code}}
{{/each}}
## Instructions
{{instructions}}
Always:
1. Use available tools before generating solutions
2. Follow documented patterns
3. Explain your reasoning
4. Document new patterns you discover
// Usage
const systemPrompt = await renderTemplate('agent/system.hbs', {
role: 'builder',
responsibilities: [
'Generate TypeScript code from specifications',
'Follow established patterns',
'Write tests alongside code'
],
tools: toolRegistry.getAll(),
patterns: patternRegistry.getRelevantFor('builder'),
instructions: 'Always include type definitions and error handling'
});
The Learning Capture Pattern
Capture learnings systematically so agents get smarter over time.
# learnings/2026-04-29-auth-refresh.yaml
pattern: jwt-refresh-token-rotation
learned: 2026-04-29
problem: |
Refresh tokens were being reused, creating a security vulnerability.
An attacker could reuse a stolen refresh token multiple times.
solution: |
Implement refresh token rotation:
1. On refresh, issue a new refresh token
2. Invalidate the old token immediately
3. Store token family for detection of replay attacks
code: |
async function refreshToken(oldToken: string) {
const family = await getTokenFamily(oldToken);
const newToken = await generateToken(family);
await invalidateToken(oldToken);
return newToken;
}
agents_to_update:
- builder: "Always include rotation logic in auth implementations"
- reviewer: "Check for rotation pattern in auth code"
- tester: "Add tests for token reuse detection"
related:
- jwt-authentication
- token-storage-best-practices
- session-security
The Multi-Modal Content Pattern
AI agents can consume more than text. Structure content for multimodal understanding.
# Component: DataGrid
## Description
A performant data table with virtual scrolling.
## Textual Specification
[Detailed textual description...]
## Visual Reference


## Code Example
```typescript
<DataGrid
data={rows}
columns={columns}
virtualScroll
pageSize={50}
/>
Interaction Diagram
sequenceDiagram
User->>DataGrid: Scroll
DataGrid->>VirtualScroller: Request visible rows
VirtualScroller-->>DataGrid: Return rows
DataGrid->>Renderer: Paint rows
Accessibility Notes
- Keyboard navigation: Arrow keys, Page Up/Down
- Screen reader: ARIA labels on headers and cells
- Focus management: Maintains focus during updates
---
## Part 3: Compound Engineering Patterns
Compound engineering ensures each unit of work makes the next one easier through documented learnings and systematic improvement.
### The Learning Loop Pattern
The fundamental compound engineering pattern.
┌─────────────────────────────────────────────────────────────────┐ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ Plan │ → │ Work │ → │ Review │ → │Compound│ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ ↓ ↓ ↓ ↓ │ │ Research Code Multi-agent Document │ │ patterns generation review learnings │ │ ┌──────────────────────────────────────────┐ │ │ │ Learnings feed back │ │ │ │ into agents for next iteration │ │ │ └──────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
### The Pattern Evolution Pattern
Patterns evolve from discovery to standardization.
```yaml
# Pattern Lifecycle
discovery:
- Agent encounters a new problem
- Agent creates an ad-hoc solution
- Learning is captured
validation:
- Pattern is tested in multiple contexts
- Edge cases are documented
- Success metrics are established
standardization:
- Pattern is added to core library
- Agents are updated to use it
- Documentation is created
evolution:
- Pattern is refined based on usage
- New variations are documented
- Related patterns are linked
The Agent Improvement Pattern
Agents improve through structured feedback.
interface AgentImprovement {
agent: string;
version: number;
changes: AgentChange[];
validation: ValidationResult;
}
class AgentRegistry {
private agents = new Map<string, AgentVersion[]>();
async improve(agentName: string, learnings: Learning[]): Promise<void> {
const current = this.getLatest(agentName);
const improved = await this.applyLearnings(current, learnings);
// Validate improvement
const validation = await this.validateAgent(improved);
if (validation.passed) {
await this.registerVersion(agentName, improved);
await this.notifyDependents(agentName, improved);
} else {
await this.reportFailure(validation);
}
}
private async applyLearnings(agent: Agent, learnings: Learning[]): Promise<Agent> {
let improved = agent;
for (const learning of learnings) {
improved = await this.applyLearning(improved, learning);
}
return improved;
}
}
The Knowledge Graph Pattern
Connect related knowledge to enable discovery and compounding.
interface KnowledgeNode {
id: string;
type: 'pattern' | 'learning' | 'example' | 'warning';
content: any;
relationships: Relationship[];
}
interface Relationship {
type: 'related-to' | 'builds-on' | 'supersedes' | 'contradicts';
target: string;
strength: number;
}
class KnowledgeGraph {
private nodes = new Map<string, KnowledgeNode>();
private relationships = new Map<string, Relationship[]>();
async add(node: KnowledgeNode) {
this.nodes.set(node.id, node);
await this.index(node);
}
async findRelated(nodeId: string, types?: string[]): Promise<KnowledgeNode[]> {
const relationships = this.relationships.get(nodeId) || [];
const filtered = types
? relationships.filter(r => types.includes(r.type))
: relationships;
return filtered
.sort((a, b) => b.strength - a.strength)
.slice(0, 5)
.map(r => this.nodes.get(r.target))
.filter(Boolean) as KnowledgeNode[];
}
async discoverPath(from: string, to: string): Promise<Path[]> {
// Find shortest path through related knowledge
// Enables agents to discover relevant patterns they wouldn't find directly
}
}
Putting It All Together: A Complete System
The three patterns work together in a complete agentic engineering system.
class AgenticEngineeringSystem {
constructor(
private harness: AgentHarness,
private contentEngine: ContentEngine,
private compoundEngine: CompoundEngine
) {}
async buildFeature(request: FeatureRequest): Promise<FeatureResult> {
// 1. Content Engineering: Load relevant knowledge
const context = await this.contentEngine.buildContext({
domain: request.domain,
patterns: ['authentication', 'api-design'],
includeHistory: true
});
// 2. Agent Harness: Execute workflow
const workflow = this.harness.createWorkflow('feature-development', {
researcher: { context },
architect: { context },
builder: { context },
reviewer: { context }
});
const result = await workflow.execute(request);
// 3. Compound Engineering: Capture learnings
if (result.learnings.length > 0) {
await this.compoundEngine.documentLearnings(result.learnings);
await this.compoundEngine.updateAgents(result.learnings);
await this.contentEngine.updatePatterns(result.learnings);
}
return result;
}
}
Implementation Guide: Getting Started
Step 1: Set Up Your Agent Harness
Start with a simple tool registry and agent lifecycle.
# Initialize project
npm create agent-harness@latest my-agentic-system
cd my-agentic-system
# Configure tools
cp config/tools.example.yaml config/tools.yaml
Step 2: Structure Your Content
Create a content hierarchy for your domain.
# Create content structure
mkdir -p content/{core,domain,historical,ephemeral}
mkdir -p schemas
mkdir -p templates
Step 3: Implement Learning Capture
Add compound engineering from day one.
# Create learnings directory
mkdir -p learnings
# Configure learning capture
cp config/learnings.example.yaml config/learnings.yaml
Step 4: Build Your First Workflow
Compose agents into a workflow.
// workflows/feature-development.ts
export const featureWorkflow = new Workflow('feature-development', [
'researcher',
'architect',
'builder',
'reviewer',
'documenter'
]);
Common Pitfalls to Avoid
Pitfall 1: Skipping Content Engineering
The mistake: Treating documentation as optional, not as input.
The fix: Structure knowledge for AI consumption from the start. Every pattern, learning, and decision should be machine-readable.
Pitfall 2: Monolithic Agents
The mistake: Building one “super agent” that does everything.
The fix: Use specialized agents with clear responsibilities. Compose them into workflows.
Pitfall 3: No Observable State
The mistake: Agents work in black boxes.
The fix: Log every decision, outcome, and learning. Make state observable for debugging and improvement.
Pitfall 4: Breaking the Learning Loop
The mistake: Plan → Work → Review but skip Compound.
The fix: Make the learning loop explicit. Document learnings after every cycle.
Pitfall 5: No Schema for Knowledge
The mistake: Unstructured documentation that agents can’t reliably consume.
The fix: Schema-first content engineering. Validate all knowledge before ingestion.
Tools and Resources
Agent Harness Tools
- Claude Code — CLI with built-in agent orchestration
- Antfarm — Multi-agent workflow framework
- LangGraph — Agent workflow orchestration
Content Engineering Tools
- Frontmatter — Content management with schema validation
- Contentful — Headless CMS with structured content
- Notion API — Structured knowledge base
Compound Engineering Tools
- Compound Engineering Plugin — Claude Code plugin for learning loops
- Obsidian — Knowledge graph for pattern management
- Dendron — Hierarchical note-taking for knowledge organization
Key Takeaways
-
Three patterns, one system — Agent harness, content engineering, and compound engineering work together
-
Content is input, not documentation — Structure knowledge for AI consumption
-
Agents need orchestration — The agent harness manages lifecycle, tools, and workflows
-
Compounding requires explicit loops — Document learnings to make each cycle easier
-
State must be observable — Log decisions for debugging and improvement
-
Schema-first content — Validate knowledge before agents consume it
-
Compose over create — Build reusable agents and workflows
-
Start with learning capture — Add compound engineering from day one
The Future of Engineering
Agentic engineering patterns represent a fundamental shift in how we build software. We’re moving from writing code to engineering systems where AI agents are first-class citizens.
The agent harness provides the orchestration. Content engineering structures knowledge. Compound engineering ensures continuous improvement.
Together, they enable systems that:
- Learn from every interaction
- Compose capabilities like Lego bricks
- Improve continuously
- Scale without proportional human effort
The question isn’t whether to adopt agentic engineering—it’s how quickly you can master the patterns.
Further Reading
- From Vibe Coding to Agentic Engineering — The transition guide
- Compound Engineering - The Next Paradigm Shift — Deep dive on compounding
- Context Engineering: Parenting for AI — Structuring context
- Antfarm Patterns: Orchestrating Specialized Agent Teams — Multi-agent workflows
- Compound Engineering: How Every Codes With Agents — Dan Shipper’s original essay
- The Agent Harness: Orchestrating AI at Scale — Claude Code documentation