agentic-ai-engineering/site/modules/m5-production.md

16 KiB

Module 5: Production Patterns

Lesson 5.1: What Production Means for Agents

Production for agents is fundamentally different from traditional software:

Traditional Software Agent Systems
Deterministic output Non-deterministic behavior
Fixed cost per operation Variable cost per session
Error = known exception Error = unexpected behavior
Rollback = revert code Rollback = revert prompt + pin model
Monitoring = latency + errors Monitoring = token usage + loop depth
Testing = unit + integration Testing = golden datasets + evals

Production Readiness Checklist

[ ] Version-locked prompts (hashed, diffed, reviewed)
[ ] Model pinning (not "latest", specific version)
[ ] Cost budgets per session/task/user
[ ] Iteration limits (max tool calls per session)
[ ] Observability (every tool call logged)
[ ] Shadow deployment capability
[ ] Rollback plan (prompt + model + env)
[ ] Security review (L3+ minimum)

Lesson 5.2: CI/CD for Agents

Golden Dataset

A curated set of input/output/behavior pairs that define correct agent behavior:

[
  {
    "input": "Find all users created in the last 24 hours",
    "expected_tools": ["query_database"],
    "expected_tool_params": {"query": "SELECT * FROM users WHERE created_at > now() - interval '24 hours'"},
    "expected_output_contains": ["users", "24 hours"]
  }
]

Pipeline

1. Agent runs against golden dataset
2. Compare: tool selections match expected?
            params match expected?
            output contains expected strings?
3. Calculate pass@k
4. If pass@k < threshold (e.g., 80%), FAIL build
5. If pass, deploy new prompt/config

Lesson 5.2b: Case Study — The 5-Tool Production Stack

A real production multi-agent deployment uses multiple agent tools together, each for its strength. See TOOL-REFERENCE.md for full command references.

The Stack

agent-mux (Tauri UI) —— Meta-agent control plane
    │   └── cc agent SDK, pi-coding-agent SDK, opencode SDK via sidecar
    ▼
mprocs (process monitor) —— Launches all agents
    │   mprocs -c ~/mprocs-teams.yaml
    │
    ├── claude-lead (Claude Code)
    │     └── psmux → tmux.exe → --teammate-mode → split panes
    │           └── Each teammate = separate Claude session
    │
    ├── pi-agent (Pi Coding Agent)
    │     └── Extensions: damage-control, tilldone, coms
    │
    ├── opencode (OpenCode CLI)
    │     └── Model: opencode-go/deepseek-v4-flash (via proxy)
    │
    ├── hermes (Hermes Agent)
    │     └── TypeScript-native, MCP-first workflows
    │
    ├── openclaw (OpenClaw daemon)
    │     └── Always-on employee, heartbeat-driven
    │
    ├── gemini (Gemini fallback)
    │     └── Fast/cheap tasks, cascade routing
    │
    ├── qwen (Qwen specialist)
    │     └── Chinese + structured tasks
    │
    └── sidecar (agent-mux IPC proxy)
          └── RPC bridge between Tauri UI and agent processes
          │
          ▼
    psmux (tmux session manager)
    │   tmux.exe at ~/.cargo/bin/tmux
    │   Requires: start agent-teams first, then dmux inside it
    │
    ▼
    dmux (git worktree isolation)
        Each task gets an isolated worktree
        Rollback = delete worktree

Tool Roles and Selection Logic

Tool Role When to Use Stack Position
Claude Code Primary coding agent Complex multi-step tasks, general development claude-lead in mprocs
Pi Agent Customizable harness Custom workflows, safety-critical ops, P2P Side agent with extensions
OpenCode OSS alternative Budget tasks, CI/CD, when license matters Backup in mprocs
Hermes TypeScript pipelines MCP-native workflows, structured output Specialist in mprocs
OpenClaw Always-on employee Scheduled tasks, heartbeats, recurring Daemon (always running)
Gemini Fast/cheap fallback High-volume simple tasks Cascade routing tier 1
Qwen Specialist model Chinese content, structured generation Cascade routing tier 2

How They Work Together (Real Session Flow)

1. Human opens agent-mux Tauri UI
2. mprocs launches all agents from mprocs-teams.yaml
3. Claude Code (lead) runs in tmux via psmux
     └── --teammate-mode creates split panes:
           ├── pane 1: lead (primary coder)
           ├── pane 2: worker (sub-tasks)
           ├── pane 3: reviewer (code review)
           └── pane 4: verifier (read-only checks)
4. OpenCode runs alongside as budget-aware backup
5. OpenClaw daemon handles scheduled background tasks
6. dmux isolates each task in its own git worktree
7. agent-mux sidecar collects status from all agents
8. Human monitors via Tauri UI, intervenes when needed

Key Production Patterns

  1. Model heterogeneity — Different models for different roles. Cascade routing in practice (M6).
  2. Tool heterogeneity — Five CLIs, each with different strengths. No single point of failure.
  3. Process management — mprocs supervises. If one agent crashes, the stack keeps running.
  4. Session isolation — psmux (terminal sessions) + dmux (git worktrees) = two layers.
  5. Meta-control plane — agent-mux Tauri UI. Human watches and intervenes, not drives.
  6. Defense in depth — tool-level (damage-control), session-level (psmux), filesystem-level (dmux).

Lesson 5.2c: The Agent Manager Role

In enterprise deployments, someone owns the agent harness. This is the Agent Manager (or DevEx Lead for AI).

Responsibilities

Agent Manager
├── Harness design (CLAUDE.md, skills, hooks, MCPs)
├── Tool selection (which agent CLIs, which models)
├── Security policy (damage-control rules, access levels)
├── Cost management (budgets per agent/task, optimization)
├── Quality gates (golden datasets, regression testing)
├── Update cadence (prompt versioning, model pinning)
└── Incident response (tool loops, cost spikes, failures)

90-Day Setup Playbook

Month 1: Foundation

  • Set up agent CLI (Claude Code, Pi, or OpenCode)
  • Create CLAUDE.md with project context
  • Install damage-control with 3 access levels
  • Set up basic observability (tool call logging)

Month 2: Scale

  • Add multi-agent teams (lead + workers)
  • Create golden dataset (10+ test cases)
  • Implement CI/CD gate
  • Set up cost tracking and budgets

Month 3: Production

  • Shadow deployment pipeline
  • Rollback procedures documented
  • Monitoring dashboard live
  • Team trained on agent interaction patterns

Lesson 5.3: Shadow Deployments

How It Works

Production agent: serves user traffic
Shadow agent: runs IDENTICAL inputs, but outputs are NOT served
Compare: did shadow make same decisions as production?
         did shadow cost more/less?
         did shadow hit any errors?
Decision: if shadow improves on all metrics, swap them

When to Shadow Deploy

  • New prompt version
  • New model version
  • New tool addition
  • Agent architecture change

Lesson 5.4: Rollback Strategies

What Rollback Means for Agents

You can't just revert a Git commit. Agent behavior depends on:

  1. Prompt — the text of the system prompt + tools
  2. Model — which model version
  3. Parameters — temperature, top_p, etc.
  4. Configuration — tool list, iteration limits, budget

A proper rollback restores ALL four.

Implementation

# agent-config-v42.yaml
prompt_hash: "a1b2c3d4"
model: "claude-sonnet-4-20260501"  # pinned, not "latest"
temperature: 0.0
max_iterations: 25
tools: ["read", "write", "bash", "search"]
budget_per_session: 0.50

Rollback = cp agent-config-v41.yaml agent-config.yaml + reload.


Lesson 5.5: Observability & Monitoring

What to Trace (Every Single Turn)

  1. Input prompt (full, including system prompt)
  2. LLM response (including tool call choices)
  3. Tool calls (name, params, timestamp)
  4. Tool results (output, error status, duration)
  5. Token counts (input, output, cached)
  6. Cost (per-call and running total)
  7. Loop depth (current turn number)

Decision Tracing

Standard APM (Datadog, Grafana) captures latency and errors. Agents need decision tracing — the full chain of reasoning and actions:

{
  "session_id": "sess_abc123",
  "turn": 5,
  "input_tokens": 12400,
  "output_tokens": 350,
  "tool_calls": [
    {"tool": "search_web", "params": {"query": "latest pricing"}, "duration_ms": 1200}
  ],
  "decision": "Found pricing page, will extract"
}

Key Metrics

Metric Warning Critical
Tool calls per session >20 >50
Cost per session >$0.50 >$2.00
Loop depth >15 >30
Same tool >5x in row Investigate loop Kill session
Context utilization >80% >95%

Lesson 5.6: Alerting on Agent-Specific Signals

What to Alert On

  1. Tool loop detected — same tool called 5+ times with same params
  2. Cost spike — session cost > 3x average
  3. Context overflow imminent — token count within 10% of limit
  4. Permission escalation — agent attempting blocked operations
  5. Error cascade — 3+ tool failures in a row
  6. Grinding detected — identical code rerun without changes

Alert Routing

P0 (immediate): Cost spike > $10, permission escalation, data exfil attempt
P1 (within 5 min): Tool loop, error cascade, grinding
P2 (within 1 hour): Context utilization high, cost trending up
P3 (daily report): Average session cost, success rate, failure modes

When you run agents across 5+ tools (Claude Code, Pi, OpenCode, Gemini, OpenClaw), session history is scattered across different directories and formats.

The Problem

~/.claude/sessions/*.jsonl      # Claude Code format
~/.pi/sessions/*.jsonl          # Pi format
~/.opencode/sessions/*          # OpenCode format
~/.gemini/sessions/*.jsonl      # Gemini format
mprocs-logs/*.log               # mprocs supervisor logs

Searching across all of them is impossible without a unified index.

The Solution

Reference implementation: Jeff Emanuel's coding_agent_session_search (783★)

Indexer:
  ├── Watches all session directories
  ├── Normalizes into canonical format
  ├── Full-text indexes prompts, responses, tool calls
  └── Stores in SQLite with FTS5

Search CLI:
  ├── Search across ALL providers from one command
  ├── Filter by: provider, date, model, tool, token count
  ├── Replay any session from any provider
  └── Export sessions as markdown or JSON

Why This Matters for Production

  1. Debugging: Find what went wrong across all agents in one search
  2. Audit: Full history of every agent action, unified format
  3. Learning: Search past solutions instead of re-solving problems
  4. Cost analysis: Aggregate costs across all providers

Integration with Our Stack

# Add to mprocs-teams.yaml as a sidecar service
session-indexer:
  cmd: ["python", "session-indexer.py", "--watch-dirs",
        "~/.claude/sessions/", "~/.pi/sessions/",
        "~/.opencode/sessions/", "logs/"]

# Search across everything
session-search "deployment error" --providers claude,pi,opencode
# Returns results from all providers in unified format

Lesson 5.7: Deployment Modes

From Paperclip's deployment model:

Mode Auth Exposure Use Case
Local trusted None localhost only Single dev machine
Authenticated private Login required LAN/Tailscale/VPN Team on private network
Authenticated public Login required Internet (behind reverse proxy) Production cloud deployment

Reachability

Bind What It Means
loopback localhost only (default)
lan All interfaces (0.0.0.0)
tailnet Tailscale IP only
custom Specific host/IP

Lesson 5.8: Cost Control

Budget Architecture

Company budget → Agent budgets → Session budgets → Per-call tracking

Budget Policies

budget_policies:
  - metric: "monthly_cost_cents"
    scope: "agent:backend-dev"
    amount: 50000  # $500/month
    warn_at: 80%   # warn at $400
    hard_stop: true # kill at $500
  - metric: "session_cost_cents"
    scope: "global"
    amount: 200     # $2/session max
    hard_stop: true

Warning vs Hard Stop

  • Warning (80%) — Notify operator, agent keeps running
  • Hard Stop (100%) — Agent paused, new tasks queued, running task cancelled

Lesson 5.8b: Dry-Run Workflow for Agent Actions

Before an agent executes a destructive action (write file, delete, deploy), you want a preview mode that shows what the agent WILL do without actually doing it.

The Dry-Run Pattern

Agent proposes action → Preview output → Human reviews → Approve/Reject → Execute
class DryRunContext:
    """Wrap tool execution in dry-run mode."""
    
    def __init__(self, dry_run=True):
        self.dry_run = dry_run
        self.proposed_actions = []
    
    def execute(self, tool_name, params):
        if self.dry_run:
            # Log what WOULD happen
            self.proposed_actions.append({
                "tool": tool_name,
                "params": params,
                "preview": self._generate_preview(tool_name, params),
            })
            return f"[DRY RUN] Would call {tool_name} with {params}"
        else:
            # Actually execute
            return real_execute(tool_name, params)
    
    def _generate_preview(self, tool_name, params):
        if tool_name == "write_file":
            return f"Would write {len(params.get('content',''))} chars to {params.get('path')}"
        elif tool_name == "exec_command":
            return f"Would run: {params.get('command','')[:100]}..."
        elif tool_name == "delete_file":
            return f"Would DELETE: {params.get('path')}"
        return f"Would call {tool_name}"

Implementation Strategies

Strategy How It Works Best For
Flag-based --dry-run flag on agent start Development, testing
Hook-based Pre-tool hook logs intent, skips execution Production agents
UI-based Agent shows preview, human clicks Confirm Interactive sessions
Two-pass Agent plans first (dry), then executes (wet) Complex multi-step tasks

Docker Dry-Run Example

From the dry-run workflow pattern — a Docker-based calculator that logs operations without running them:

# Build the dry-run sandbox
docker build -t dry-run-calc -f calculator/Dockerfile .

# Run in preview mode
docker run --rm -e DRY_RUN=true dry-run-calc add 5 3
# Output: [DRY RUN] Would add 5 + 3 = 8

# Run for real
docker run --rm -e DRY_RUN=false dry-run-calc add 5 3
# Output: 8

When to Use Dry-Run

  • Always for file writes, deletes, and deploys
  • Sometimes for commands that modify state (DB migrations, config changes)
  • Never for read-only operations (search, read file, list directory)

Lesson 5.8c: Cross-Platform Agent Skills

Skills should work on any agent — Claude Code, Pi Agent, OpenCode, or Codex. The cross-platform format uses YAML frontmatter and tool-agnostic instructions:

---
name: init-agents-md
description: Create or refresh AGENTS.md for coding agents.
  Works with Claude Code, Pi Agent, and Codex.
---

# Initialize AGENTS.md

Create a short, repo-specific AGENTS.md.

## Workflow

1. Check if AGENTS.md already exists — if so, stop and ask
2. Explore the repository structure
3. Draft AGENTS.md with project purpose, stack, and conventions
4. Mirror same context into CLAUDE.md if needed

Key Principles

  1. Use ~~ or --- frontmatter — not agent-specific config
  2. Avoid CLI flags — describe the desired outcome, not the command
  3. Include trigger patterns — tell the agent when to invoke this skill
  4. One SKILL.md per skill — no platform-specific variations

Lab 5.9: Set Up Agent Observability

Objective: Trace every tool call + LLM completion to a local SQLite database.

Starter: course/labs/L5-observability/starter/

Lab 5.10: CI/CD Pipeline

Objective: Create a golden dataset and automated regression gate.

Starter: course/labs/L5-cicd/starter/