Skip to content

Agentic Engineering Patterns- The Foundation of AI-Native Development

Published: at 12:00 AM
Agentic engineering patterns: agent harness, content engineering, and compound engineering visualized

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.



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 EngineeringAgentic Engineering
Write code directlyEngineer agent workflows
Code is staticAgents learn and adapt
Patterns for humansPatterns for AI consumption
Documentation is optionalDocumentation is input
Technical debt accumulatesKnowledge compounds

Agentic engineering patterns fall into three categories:

  1. Agent Harness Patterns — Orchestrating agents, tools, and workflows
  2. Content Engineering Patterns — Structuring knowledge for AI consumption
  3. 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
![DataGrid preview](/images/components/datagrid-preview.png)
![DataGrid states](/images/components/datagrid-states.png)

## 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

Compound Engineering Tools


Key Takeaways

  1. Three patterns, one system — Agent harness, content engineering, and compound engineering work together

  2. Content is input, not documentation — Structure knowledge for AI consumption

  3. Agents need orchestration — The agent harness manages lifecycle, tools, and workflows

  4. Compounding requires explicit loops — Document learnings to make each cycle easier

  5. State must be observable — Log decisions for debugging and improvement

  6. Schema-first content — Validate knowledge before agents consume it

  7. Compose over create — Build reusable agents and workflows

  8. 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


Previous Post
From Vibe Coding to Agentic Engineering- The Mindset Shift for AI Development
Next Post
C-Suite Leaders Must Embrace Rapid Experimentation in the AI Era