Claude Code Self‑Repair Explained: Writing Error Feedback into the Harness

The article shows how to turn Claude Code’s occasional mistakes into a reliable feedback loop by using a CLAUDE.md entry file, Hooks, Permissions and Skills, so errors become visible, verifiable and can be written back into the harness for future runs.

Architect
Architect
Architect
Claude Code Self‑Repair Explained: Writing Error Feedback into the Harness

Feedback Loop Overview

Claude Code can generate code quickly, but it repeats typical developer mistakes: committing before tests finish, overlooking file‑boundary constraints, and re‑introducing previously‑encountered bugs. “Self‑repair” does not imply the model suddenly introspects; it means that errors must be observable, validated, and written back into the development pipeline.

Layered Feedback Harness

入口约束:CLAUDE.md / .claude/rules
过程规程:Skills / Commands / Runbooks
执行检查:Permissions / Hooks / Sandbox
反馈证据:Tests / Lint / Typecheck / Logs / Review
长期记录:Auto memory / 复盘后的规则更新

These five layers together form a working harness that turns Claude Code into a disciplined engineering collaborator.

CLAUDE.md Rules

CLAUDE.md is read at the start of every session and should contain concise, high‑frequency rules that apply across tasks. It is best used for three categories of content:

Project commands (install, test, lint, type‑check).

Stable engineering conventions (error handling, logging, directory boundaries, code‑generation policies, migration rules).

Repeated pitfalls (files that must not be edited, patterns to avoid, tests that must never be skipped).

The file should be short—official guidance recommends fewer than 200 lines—because shorter, more specific rules are more likely to be obeyed.

Permissions Layer

Permissions define allow/deny policies at the client side. The order deny → ask → allow is critical: once a deny rule matches, later allow rules cannot override it. A minimal example:

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Read","Glob","Grep","LS","Edit","MultiEdit",
      "Write(src/**)","Write(tests/**)",
      "Bash(npm test *)","Bash(npm run typecheck *)","Bash(npm run lint *)",
      "Bash(git status *)","Bash(git diff *)"
    ],
    "deny": [
      "Read(**/.env*)","Write(**/.env*)",
      "Bash(rm -rf *)","Bash(git push *)","Bash(git push --force *)"
    ]
  }
}

Broad shell permissions still allow many filesystem actions; high‑risk scenarios should be isolated with containers, read‑only workspaces, or CI environments.

Hooks Layer

Hooks run outside the model and enforce deterministic checks. Three hook events are commonly used: PreToolUse – triggered before a tool runs; suitable for blocking dangerous commands, protecting sensitive files, or rewriting inputs. PostToolUse – triggered after a tool finishes; suitable for formatting, audit logging, and providing early feedback to the agent. Stop – triggered when the agent is about to finish a session; suitable for running tests, quality gates, and deciding whether to continue fixing.

Matcher pitfall : a matcher such as Write(*.ts) matches the tool name, not file extensions. File‑type logic must be performed inside the hook script via tool_input.file_path.

PreToolUse Example (Python)

#!/usr/bin/env python3
import json, re, sys
payload = json.load(sys.stdin)
command = payload.get('tool_input', {}).get('command', '')
blocked = [
    r"\brm\s+-rf\b",
    r"\bgit\s+push\b",
    r"\bchmod\s+-R\s+777\b",
    r"\b(cat|grep|sed|awk)\b.*\.env"
]
if any(re.search(p, command) for p in blocked):
    print(json.dumps({
        'hookSpecificOutput': {
            'hookEventName': 'PreToolUse',
            'permissionDecision': 'deny',
            'permissionDecisionReason': 'Command blocked by project safety policy.'
        }
    }))
    sys.exit(0)
sys.exit(0)

PostToolUse Example (Python – formatting with Prettier)

#!/usr/bin/env python3
import json, pathlib, subprocess, sys
payload = json.load(sys.stdin)
tool_input = payload.get('tool_input', {})
file_path = tool_input.get('file_path') or tool_input.get('path')
if not file_path:
    sys.exit(0)
path = pathlib.Path(file_path)
if path.suffix not in {'.ts', '.tsx', '.js', '.jsx'}:
    sys.exit(0)
commands = [[
    'npx', 'prettier', '--write', str(path)
]]
for cmd in commands:
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    if result.returncode != 0:
        print('Post-edit check failed:
' + (result.stdout + '
' + result.stderr)[-3000:])
        sys.exit(0)
sys.exit(0)

Stop Hook Example (Python – minimal quality gate)

#!/usr/bin/env python3
import json, subprocess, sys
payload = json.load(sys.stdin)
if payload.get('stop_hook_active'):
    sys.exit(0)
checks = [
    ['npm', 'run', 'typecheck'],
    ['npm', 'test', '--', '--runInBand']
]
for cmd in checks:
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
    if result.returncode != 0:
        output = (result.stdout + '
' + result.stderr)[-4000:]
        print(json.dumps({
            'decision': 'block',
            'reason': 'Quality gate failed. Fix the issue before stopping:
' + output
        }))
        sys.exit(0)
sys.exit(0)

The stop_hook_active flag prevents infinite loops where the Stop hook repeatedly blocks the session end.

Starting with a Small Version

A minimal project layout:

.claude/
  settings.json
  hooks/
    pre_bash_guard.py
    post_edit_check.py
    stop_quality_gate.py
CLAUDE.md

Write a short CLAUDE.md (≈120 lines) containing project commands, directory boundaries, and recent pitfalls.

Configure permissions with a conservative acceptEdits default, allowing only explicit test, lint, type‑check, and git‑status commands; deny access to .env files and destructive shell commands.

Add three hooks:

Engineering Takeaways

Block dangerous actions first (Permissions → PreToolUse).

Provide immediate feedback after file changes (PostToolUse).

Collect minimal evidence before ending a session (Stop hook).

Write recurring issues back into CLAUDE.md or Skills so they are prevented in future runs.

References

Claude Code Hooks reference: https://code.claude.com/docs/en/hooks

Claude Code Hooks guide: https://code.claude.com/docs/en/hooks-guide

Claude Code memory docs: https://code.claude.com/docs/en/memory

Claude Code permissions docs: https://code.claude.com/docs/en/permissions

Anthropic blog – How Claude Code works in large codebases: https://claude.com/blog/how-claude-code-works-in-large-codebases-best-practices-and-where-to-start

Addy Osmani, Agent Harness Engineering: https://www.oreilly.com/radar/18718-2/

Addy Osmani, Agent Skills: https://www.oreilly.com/radar/agent-skills/

AI Harness Engineering paper: https://arxiv.org/abs/2605.13357

Design space of AI agents paper: https://arxiv.org/abs/2604.14228

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AI agentshooksfeedback looppermissionsself-repairClaude Codeagent engineeringCLAUDE.md
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.