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