Agent Harness Design
Use when designing or improving how an agent invokes tools, handles errors, and decides when to stop.
When to Use
- Designing tool definitions for a new agent or subagent
- Observing high retry rates or ambiguous tool invocations
- Agent is failing silently or completing without verifying outcomes
- Reviewing an existing agent harness for quality issues
Tool Design Rules
Naming
- Use explicit, stable names:
read_file, run_tests, apply_patch
- No generic names:
do_action, execute, handle
- One tool per distinct operation; do not overload parameters to compensate
Schema
Keep tool inputs narrow:
- Required fields only; no optional fields that change behavior
- Use enums for mode/type values — never free-text strings that require parsing
- Validate at the boundary; reject malformed input with a clear error, not a fallback
{
"name": "run_tests",
"parameters": {
"path": { "type": "string", "description": "Path to test file or directory" },
"filter": { "type": "string", "description": "Optional test name filter" }
}
}
Output Shape
Every tool response must include:
status: "success" | "warning" | "error"
summary: one-line result (human-readable)
next_actions: list of follow-up steps the agent should consider
artifacts: file paths or IDs produced (empty list if none)
Catch-All Tools
Avoid run_bash / shell_exec style catch-all tools unless:
- The task is genuinely open-ended and the toolset cannot be pre-defined
- You explicitly document the risk and add an allowlist or preflight check
If you must use a catch-all, add a PreToolUse validation hook for dangerous patterns.
Error Path Rules
Every tool must define what happens on failure:
| Case |
Required response |
| Invalid input |
Reject immediately with status: "error" and exact field name |
| Transient failure |
Include retry_after hint and idempotency note |
| Non-recoverable |
State stop: true and describe the manual resolution step |
Do not return partial success with no indication that something failed.
Retry and Stop Conditions
Define retry limits in the harness, not inside tool implementations:
max_retries: 2
stop_conditions:
- tool returns status: "error" with stop: true
- same tool called with identical inputs twice in a row
- completion signal received
Never retry indefinitely. Declare a hard ceiling.
Context Budget
- Keep system prompt fixed and minimal — it is loaded on every turn
- Put large reference material (schemas, docs) in skills loaded on demand
- Compact at phase boundaries (after research, after planning, after debugging)
- Do not pass growing tool-call history to subagents; summarize into a context bundle
Granularity Guide
| Risk level |
Tool granularity |
| High (deploy, migrate, permissions) |
Micro — one action, one confirmation |
| Medium (edit, read, search) |
Standard — composite is fine |
| Low (format, report, list) |
Macro — batch operations acceptable |
Benchmarks to Track
- Completion rate (task finished without escalation)
- Retries per task
- Pass@1 rate (completed on first attempt)
- Cost per successful task
Anti-Patterns
- Overlapping tool semantics (agent cannot choose between them)
- Tool returns only on error — no output on success
- No explicit stop condition — agent loops indefinitely
- Context overload — every tool call inlines full file contents
Verification
1---2name: agent-harness-design3description: Use when designing tool definitions for a new agent or subagent, an agent shows high retry rates, ambiguous tool invocations, or silent failures, or an existing agent harness needs a quality review.4---56# Agent Harness Design78Use when designing or improving how an agent invokes tools, handles errors, and decides when to stop.910## When to Use1112- Designing tool definitions for a new agent or subagent13- Observing high retry rates or ambiguous tool invocations14- Agent is failing silently or completing without verifying outcomes15- Reviewing an existing agent harness for quality issues1617## Tool Design Rules1819### Naming2021- Use explicit, stable names: `read_file`, `run_tests`, `apply_patch`22- No generic names: `do_action`, `execute`, `handle`23- One tool per distinct operation; do not overload parameters to compensate2425### Schema2627Keep tool inputs narrow:28- Required fields only; no optional fields that change behavior29- Use enums for mode/type values — never free-text strings that require parsing30- Validate at the boundary; reject malformed input with a clear error, not a fallback3132```json33{34 "name": "run_tests",35 "parameters": {36 "path": { "type": "string", "description": "Path to test file or directory" },37 "filter": { "type": "string", "description": "Optional test name filter" }38 }39}40```4142### Output Shape4344Every tool response must include:45- `status`: `"success" | "warning" | "error"`46- `summary`: one-line result (human-readable)47- `next_actions`: list of follow-up steps the agent should consider48- `artifacts`: file paths or IDs produced (empty list if none)4950### Catch-All Tools5152Avoid `run_bash` / `shell_exec` style catch-all tools unless:53- The task is genuinely open-ended and the toolset cannot be pre-defined54- You explicitly document the risk and add an allowlist or preflight check5556If you must use a catch-all, add a PreToolUse validation hook for dangerous patterns.5758## Error Path Rules5960Every tool must define what happens on failure:6162| Case | Required response |63|------|------------------|64| Invalid input | Reject immediately with `status: "error"` and exact field name |65| Transient failure | Include `retry_after` hint and idempotency note |66| Non-recoverable | State `stop: true` and describe the manual resolution step |6768Do not return partial success with no indication that something failed.6970## Retry and Stop Conditions7172Define retry limits in the harness, not inside tool implementations:7374```75max_retries: 276stop_conditions:77 - tool returns status: "error" with stop: true78 - same tool called with identical inputs twice in a row79 - completion signal received80```8182Never retry indefinitely. Declare a hard ceiling.8384## Context Budget8586- Keep system prompt fixed and minimal — it is loaded on every turn87- Put large reference material (schemas, docs) in skills loaded on demand88- Compact at phase boundaries (after research, after planning, after debugging)89- Do not pass growing tool-call history to subagents; summarize into a context bundle9091## Granularity Guide9293| Risk level | Tool granularity |94|------------|-----------------|95| High (deploy, migrate, permissions) | Micro — one action, one confirmation |96| Medium (edit, read, search) | Standard — composite is fine |97| Low (format, report, list) | Macro — batch operations acceptable |9899## Benchmarks to Track100101- Completion rate (task finished without escalation)102- Retries per task103- Pass@1 rate (completed on first attempt)104- Cost per successful task105106## Anti-Patterns107108- Overlapping tool semantics (agent cannot choose between them)109- Tool returns only on error — no output on success110- No explicit stop condition — agent loops indefinitely111- Context overload — every tool call inlines full file contents112113## Verification114115- [ ] Every tool has an explicit, stable name and exactly one distinct operation116- [ ] Schemas use required fields and enums — no free-text mode strings, no behavior-changing optionals117- [ ] Every tool response carries `status`, `summary`, `next_actions`, and `artifacts`118- [ ] Every tool defines its invalid-input, transient-failure, and non-recoverable paths119- [ ] Retry ceiling and stop conditions are declared in the harness, not inside tools120- [ ] Any catch-all tool is documented with its risk and guarded by an allowlist or preflight check