Harness Design Principles
Building a great agentic harness requires balancing power, safety, usability, and reliability. These principles guide design decisions.
Core Principles
1. The Harness Controls, The Model Advises
The harness should make critical decisions (loop control, permissions, timeouts) deterministically. The model suggests actions, but the harness enforces rules.
Example: Don't let the model decide "ignore permissions" - the harness enforces them.
2. Safety By Default
Every potentially destructive action should require explicit permission or be sandboxed by default.
- Default to read-only operations
- Require approval for writes, deletes, shell commands
- Sandboxing for untrusted code execution
- Principle of least privilege
3. Transparency and Observability
Users should always understand what the agent is doing and why.
- Show tool calls before execution (or after with details)
- Display reasoning/thinking when available
- Provide trace/debug views
- Log all significant actions
4. Human Agency
The user must be able to intervene at any time.
- Interrupt/cancel execution
- Approve or reject tool calls
- Correct course mid-task
- Take over manually
5. Composability Over Monoliths
Build from small, reusable components.
- Tools are independent and composable
- Sub-agents for specialized tasks
- MCP for extensibility
- Clean interfaces between components
Architectural Principles
6. Context is King, but Budget-Constrained
Smart context beats more context.
- Prioritize relevant information
- Use summaries for old history
- Index and retrieve on demand
- Respect token budgets
- Compact when necessary
7. Fail Gracefully
Assume tools will fail, models will be rate-limited, and things will go wrong.
- Retry with backoff for transient errors
- Provide fallback strategies
- Don't crash on tool failure
- Clear error messages
- Recovery paths
8. Idempotency and Checkpointing
Long-running tasks must be resumable.
- Checkpoint state after major steps
- Make tool calls idempotent where possible
- Support resumption after crashes
- Track what has been done
9. Parallelize Safely
Speed up independent work without breaking things.
- Only parallelize independent tool calls
- Serialize dependent operations
- Track parallel task state
- Handle partial failures
10. Model Agnostic
Don't lock into a single provider.
- Abstract model client interface
- Handle different capabilities (tool use, thinking, vision)
- Graceful degradation
- Easy to add new models
UX Principles
11. Show Progress, Not Just Spinners
Keep users informed during long tasks.
- Task lists with status
- Current step indication
- Streaming thoughts/tool calls
- Estimated progress when possible
12. Make Diffs Reviewable
For code changes, make review easy.
- Show diffs before/after
- Syntax highlighting
- Easy to reject individual changes
- Support manual editing
13. Ask When Ambiguous
Better to ask than guess wrong.
- Clarify requirements when unclear
- Ask about approach for complex tasks
- Confirm destructive actions
- Offer choices when multiple valid approaches
14. Learn From the Project
Adapt to the codebase and conventions.
- Read CLAUDE.md/AGENTS.md/rules files
- Follow existing patterns
- Respect project structure
- Use existing tools/libraries
Implementation Principles
15. Explicit Over Implicit
Make behavior predictable and debuggable.
- Explicit tool schemas
- Clear permission rules
- Logged decisions
- Traceable execution
16. Validate Early
Catch errors before they cause damage.
- Schema validation for tool args
- Path validation for filesystem ops
- Command allowlisting
- Type checking
17. Instrument Everything
You can't improve what you don't measure.
- Token usage per turn
- Tool call counts and latency
- Success/failure rates
- Cost tracking
- Error patterns
18. Keep It Simple
Start simple, add complexity only when needed.
- YAGNI - don't over-engineer
- Prefer simple loops over complex state machines initially
- Clear code over clever code
- Good defaults
Trade-off Guidelines
| Trade-off | Guidance |
|---|---|
| Power vs Safety | Err on side of safety; add permissions, don't remove them |
| Automation vs Control | Give users control points (approvals) without blocking everything |
| Speed vs Reliability | Reliability first for destructive actions, speed for reads |
| Context Size vs Cost | Better to be selective and smart than dump everything |
| Flexibility vs Simplicity | Simple for common cases, flexible for advanced users |
Anti-Patterns to Avoid
| Anti-Pattern | Why It's Bad | Better Approach |
|---|---|---|
| Trusting the model blindly | Models make mistakes, can be manipulated | Harness enforces rules |
| Unbounded loops | Can run forever or rack up huge costs | Turn limits, cost limits, progress tracking |
| Dumping entire codebase | Expensive, hits limits, noise | Smart retrieval, relevance filtering |
| Auto-approving everything | Dangerous, risky | Permission system with sensible defaults |
| No observability | Can't debug failures | Tracing, logging, structured events |
| Tight coupling | Hard to extend/test | Modular architecture |
Checklist for a Good Harness
- [ ] Clear loop control - Deterministic orchestration
- [ ] Permission system - Safe by default
- [ ] Tool abstraction - Easy to add tools
- [ ] Context management - Smart and efficient
- [ ] Error recovery - Handles failures gracefully
- [ ] Observability - Traceable and debuggable
- [ ] User control - Interruptible, approvable
- [ ] Checkpointing - Resumable
- [ ] Model abstraction - Provider agnostic
- [ ] Good UX - Clear feedback and diffs
Related Notes
- Harness Architecture — Architecture implementation
- Agent Loop — Loop design
- Permission System — Safety implementation
- Security — Security deep dive
- Observability — Observability
Sources
- Anthropic - Building Effective Agents
- Nielsen Norman Group - UX principles
- Google SRE principles (reliability, observability)
- OWASP - Secure coding practices
- Production engineering best practices