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

529 lines
16 KiB
Markdown

# 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:
```json
[
{
"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
```yaml
# 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:
```json
{
"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
```
## Lesson 5.6b: Cross-Provider Session Search
When you run agents across 5+ tools (Claude Code, Pi, OpenCode, Gemini, OpenClaw), session history is scattered across different directories and formats.
### The Problem
```bash
~/.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
```bash
# 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
```yaml
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
```
```python
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:
```bash
# 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:
```markdown
---
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/`