Self-Reflective APIs: Why Structured Error Recovery Beats Plain English for Coding Agents — and How to Build It into Codex CLI
Self-Reflective APIs: Why Structured Error Recovery Beats Plain English for Coding Agents — and How to Build It into Codex CLI
When a coding agent hits a validation error calling an API or tool, what comes back matters enormously. A plain-English message like "Invalid input: ingredient not compatible" forces the model to reason about what went wrong, hallucinate a fix, and retry — burning tokens and often failing. A self-reflective API returns a machine-readable recovery payload that tells the agent exactly what to change, lifting task-completion rates by up to 40 percentage points 1. This article unpacks the research, maps it to Codex CLI’s hook architecture, and shows how to wire structured recovery into your own tool integrations.
The Research: Structure Beats Verbosity
Canedo and Chethan (arXiv:2606.05037, June 2026) tested three error-response modes against identical validation logic across 270 attempts on three LLMs 1:
| Response Mode | What the Agent Sees | Haiku 4.5 Success | Sonnet 4.6 Success |
|---|---|---|---|
| Traditional | Generic error string | 10.0% | 16.7% |
| Verbose | Per-rule diagnosis, no fix | 60.0% | 46.7% |
| Reflective | Diagnosis + typed suggestions[] |
96.7% | 86.7% |
The reflective mode’s recovery_feedback.suggestions[] payload contains structured actions with literal parameter values — not prose hints, but typed repair instructions the model can consume directly 1.
Why It Works
Three mechanisms explain the gap:
-
Eliminated inference burden. The model does not need to guess the fix from a natural-language description. The action vocabulary (
ADD_INGREDIENT,REPLACE_INCOMPATIBLE_INGREDIENT,MODIFY_PARAMS) is registered and disclosed via OpenAPI or system prompt 1. -
Reduced retry count. Mean retries dropped from 4.0–4.6 (traditional) to 1.3–2.0 (reflective) within a five-retry budget 1.
-
Token efficiency. Tokens-per-success improved 1.8–2.2× on Anthropic models. Sonnet 4.6 consumed 2,504 tokens per success in reflective mode versus 19,237 in traditional mode 1.
The Caveat
The lift was not statistically significant on gpt-4o-mini (p=0.435), suggesting smaller models may not reliably parse structured recovery payloads 1. This aligns with the broader observation that structured tool-use contracts benefit larger, more capable models disproportionately.
The Self-Reflective Payload Schema
The minimal schema wraps validation errors with a typed suggestions array 1:
{
"data": { /* original request payload */ },
"feedback": {
"type": "recovery_guidance",
"suggestions": [
{
"action": "REPLACE_INCOMPATIBLE_INGREDIENT",
"parameters": {
"current": "coconut milk",
"replacement": "crème fraîche",
"reason": "coconut milk is incompatible with French classical technique"
}
},
{
"action": "CLARIFY_MEASUREMENT",
"parameters": {
"field": "sugar",
"current_value": "a handful",
"suggested_value": "50g"
}
}
]
}
}
The critical design decision: suggestions carry literal values, not instructions. The agent does not reason about what crème fraîche means — it substitutes the value and retries 1.
Mapping to Codex CLI: PostToolUse Hooks as Recovery Injectors
Codex CLI’s hook system already supports precisely this pattern. A PostToolUse hook receives the tool’s output, analyses it, and can inject structured feedback back into the model’s context window 23.
sequenceDiagram
participant Model as Codex Model
participant Tool as MCP Tool / Bash
participant Hook as PostToolUse Hook
Model->>Tool: Tool call (e.g. API request)
Tool-->>Hook: Tool output (including errors)
alt Validation error detected
Hook-->>Model: additionalContext with recovery suggestions
Model->>Tool: Retried call with fixes applied
else Success
Hook-->>Model: Pass through (no intervention)
end
The Exit Code 2 Pattern
For simple recovery steering, a PostToolUse hook can exit with code 2 and write the recovery reason to stderr 2. This blocks the original result and substitutes the hook’s feedback:
#!/bin/bash
# hooks/post-tool-use/api-recovery.sh
# Reads tool output from stdin, checks for validation errors,
# returns structured recovery suggestions
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
TOOL_RESPONSE=$(echo "$INPUT" | jq -r '.tool_response')
# Only process API tool calls
if [[ "$TOOL_NAME" != "mcp__api__"* ]]; then
exit 0
fi
# Check for validation errors in the response
if echo "$TOOL_RESPONSE" | jq -e '.error.validation_errors' > /dev/null 2>&1; then
# Extract and reformat as structured recovery
echo "$TOOL_RESPONSE" | jq '{
decision: "block",
additionalContext: (
"RECOVERY GUIDANCE: The API returned validation errors. " +
"Apply these fixes and retry:\n" +
(.error.recovery_feedback.suggestions | map(
"- Action: " + .action + " | " +
(.parameters | to_entries | map(.key + "=" + (.value | tostring)) | join(", "))
) | join("\n"))
)
}'
exit 0
fi
exit 0
The Full JSON Pattern
For richer recovery, return a JSON object with additionalContext — this gets injected into the model’s context window, subject to the additionalContextLimit (default 2,500 tokens) 2:
{
"decision": "block",
"additionalContext": "STRUCTURED RECOVERY:\n1. Replace field 'ingredient' value 'coconut milk' with 'crème fraîche' (French cuisine incompatibility)\n2. Replace field 'sugar_amount' value 'a handful' with '50g' (vague measurement)\nRetry the API call with these substitutions applied.",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"recoveryType": "self_reflective",
"suggestionsCount": 2
}
}
AGENTS.md Directives for Self-Reflective Recovery
Wire the pattern into your project’s AGENTS.md to instruct Codex CLI how to handle structured recovery payloads 4:
## Tool Error Recovery Protocol
When an MCP tool or API call returns a validation error with a
`recovery_feedback.suggestions[]` array:
1. Parse each suggestion's `action` and `parameters` fields
2. Apply the literal parameter values to the original request
3. Retry exactly once with all suggestions applied simultaneously
4. If the retry fails, report both the original and retry errors
Do NOT:
- Ignore structured suggestions and attempt your own fix
- Apply suggestions one at a time (cascading failures will multiply retries)
- Retry more than once without human approval
Designing Self-Reflective MCP Servers
If you maintain MCP servers that Codex CLI connects to, the self-reflective pattern requires roughly 20 lines of wrapper code 1. The key requirements:
-
Typed action vocabulary — register every recovery action your API can suggest. Disclose the vocabulary in the tool’s description or via OpenAPI 1.
-
Literal parameters — every suggestion must include the exact values to substitute, not descriptions of what to change.
-
Validation isolation — the
recovery_feedbackpayload must not leak ground-truth answers. Canedo and Chethan’saudit_prompt_leakage.pyCI tool detects two leakage classes: validator-message leaks (literal fixes in error messages) and task-prompt leaks (success criteria in metadata) 1.
# config.toml — MCP server with self-reflective error handling
[mcp_servers.billing-api]
command = "npx"
args = ["-y", "@acme/billing-mcp-server", "--reflective-errors"]
env = { REFLECTIVE_MODE = "true" }
When Not to Use Self-Reflective Recovery
The pattern has clear boundaries:
- Small models. The gpt-4o-mini result (p=0.435) suggests models below a certain capability threshold cannot reliably parse and apply structured recovery 1. Stick to verbose prose for smaller models.
- Non-deterministic failures. Network timeouts, rate limits, and transient errors do not benefit from recovery suggestions — a simple retry suffices.
- Security-sensitive operations. Recovery suggestions that include credential values, file paths, or SQL fragments could be exploited. Use PreToolUse hooks to sanitise recovery payloads before they reach the model 2.
The Broader Pattern: Shifting Repair Knowledge from Model to API
The self-reflective API research confirms a principle that experienced Codex CLI users already know: the less reasoning you ask the model to do about tool failures, the better it performs. This is the same principle behind Codex CLI’s exit code 2 steering 2, the SecTDD structured feedback pattern 5, and the bounded-efficiency prompt template 6. Each moves domain-specific repair knowledge out of the model’s reasoning and into typed, machine-readable contracts.
The PostToolUse hook system is the natural integration point. It sits between the tool’s output and the model’s next reasoning step, exactly where a self-reflective payload needs to be injected. Combined with additionalContext injection and the 2,500-token budget 2, it provides a clean, bounded channel for structured recovery that does not pollute the model’s broader context.
Citations
-
Canedo, A. and Chethan, G. (2026) ‘Self-Reflective APIs: Structure Beats Verbosity for AI Agent Recovery’, arXiv:2606.05037. Available at: https://arxiv.org/abs/2606.05037 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13
-
OpenAI (2026) ‘Hooks — Codex CLI Documentation’. Available at: https://developers.openai.com/codex/hooks ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
OpenAI (2026) ‘Codex CLI v0.147.0 Release Notes’. Available at: https://github.com/openai/codex/releases ↩
-
OpenAI (2026) ‘AGENTS.md — Codex CLI Documentation’. Available at: https://developers.openai.com/codex/agents-md ↩
-
Liang, Y. et al. (2026) ‘Security Tests as Executable Specifications for LLM Code Generation’, arXiv:2608.09740. Available at: https://arxiv.org/abs/2608.09740 ↩
-
Weinberger, N. and Hozez, R. (2026) ‘Same Task, Different Work: Prompt-Induced Waste in Coding Agents’, arXiv:2608.01347v3. Available at: https://arxiv.org/abs/2608.01347 ↩