Harness Engineering in Practice: Building an AI Programming Harness System with Claude Code
In the previous article, we covered the concept of Harness Engineering — AI Agent = Model + Harness. You understand the concept, but how to implement it?
This article uses Claude Code, a real AI programming tool, to walk you through building a complete Harness system step by step. After learning this, you won't just be able to use it with Claude Code — this approach also applies to Cursor, OpenAI Codex, Windsurf, and any other AI programming tool.
Why Choose Claude Code for This Practice?
Three reasons:
- It's a benchmark product for Harness Engineering — Claude Code's design philosophy perfectly embodies all 6 Harness principles
- It's free — Readers can follow along at zero cost
- It's a terminal tool — No GUI interference; Harness configuration is more transparent and easier to understand
If you haven't used Claude Code yet, we recommend reading our Claude Code: From Installation to Mastery first before coming back.
Prerequisites
Make sure Claude Code is installed:
claude --version
# Output: Claude Code 2026.x.x
# If not installed:
npm install -g @anthropic-ai/claude-code
Enter your project directory:
cd your-project
claude
Principle 1 in Practice: Clear Boundaries — Write a CLAUDE.md
CLAUDE.md is Claude Code's "employee handbook." It sits in the project root directory, and Claude Code automatically loads it every time it starts.
Basic Template
Create CLAUDE.md in the project root directory:
# Project Overview
This is a React + TypeScript e-commerce frontend project, using Vite for builds and Tailwind CSS for styling.
## Tech Stack
- Framework: React 18 + TypeScript 5
- Build: Vite 5
- Styling: Tailwind CSS 3
- Routing: react-router-dom v6
- State Management: Zustand
## Code Standards
- Use ESModule imports, do not use require
- Components use function components + hooks, not class components
- Naming: PascalCase for components, camelCase for utility functions
- Each component file should not exceed 200 lines
- Comments in English, user-visible text in code in Chinese
## Forbidden Zones (Red Lines)
- Do not modify dependency versions in package.json
- Do not directly modify any files in node_modules
- Do not modify vite.config.ts unless explicitly requested by the user
- Do not push directly to the main/master branch
- Do not modify .env files
## Operational Standards
1. Read relevant files and understand context before modifying code
2. Explain what you intend to change before each modification
3. Run `npm run typecheck` after modifications to confirm type checking passes
4. Prioritize using existing project components and utility functions
## Verification Requirements
- Run `npm run build` after code changes to confirm the build passes
- If there are tests, run `npm run test` to confirm tests pass
- Explain what verification you performed and the results
Key Element Analysis
This CLAUDE.md includes four types of rules, all essential:
| Rule Type | Purpose | Example |
|---|---|---|
| Project Overview | Let AI know what kind of project this is | Tech stack, project positioning |
| Code Standards | Make AI write consistently styled code | Naming rules, file length limits |
| Forbidden Zones | Tell AI what it must not do | No pushing to main branch, no modifying dependency versions |
| Operational Standards | Tell AI the workflow for doing things | Explain before changing, run checks after changing |
Pro Tip: CLAUDE.md shouldn't be too long. After exceeding 200 lines, AI's attention drops significantly. Put core rules at the front, and split detailed specifications into the docs/ directory for on-demand loading.
Principle 2 in Practice: Precise Information — Layered Context Loading
Claude Code's context loading is layered. Understanding this mechanism is key to using it well:
┌─────────────────────────────────┐
│ System Prompt │ ← Built-in to Claude Code, not user-controllable
├─────────────────────────────────┤
│ CLAUDE.md (Project-level) │ ← Written by you, auto-loaded in every conversation
├─────────────────────────────────┤
│ Conversation History │ ← Auto-managed, old content gets compressed
├─────────────────────────────────┤
│ Tool Return Results │ ← AI actively reads, loaded on demand
└─────────────────────────────────┘
Practical Tips:
- Use CLAUDE.md as an "index" rather than an "encyclopedia" — Only put core rules and project overview; put detailed documentation in
docs/for AI to read on demand - Use
@importto reference external files — Claude Code supports referencing other files in CLAUDE.md, enabling modular rule splitting - Clean up conversations regularly — Use the
/compactcommand to compress old context and keep the workspace tidy
# Using references in CLAUDE.md for splitting
## Core Rules (Always Loaded)
- Don't push to main branch
- Don't change dependency versions
- Explain before changing
## Detailed Specs (Reference as Needed)
- Component specs: see docs/component-guide.md
- API specs: see docs/api-conventions.md
- Testing specs: see docs/testing-guide.md
Principle 3 in Practice: Reasonable Permissions — Sandbox and Tool Control
Claude Code provides granular permission control. Create .claude/settings.json in the project root directory:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Edit",
"Write",
"MultiEdit"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(git push *)",
"Bash(npm publish *)",
"Bash(npm version *)",
"WebFetch"
],
"ask": [
"Bash(git *)",
"Bash(npm run *)",
"Bash(npx *)"
]
}
}
Permissions are divided into three levels:
| Permission Level | Meaning | Suitable Operations |
|---|---|---|
allow |
Auto-approved, no confirmation needed | Read files, search, edit code |
deny |
Directly denied, not allowed to execute | Delete files, push code, publish packages |
ask |
Asks you before each execution | git commands, npm commands, network requests |
Configuration Logic:
- Read operations all
allow(reading files won't cause trouble) - Code writing operations
allow(this is the AI's core task) - Delete/push/publish all
deny(irreversible operations) - git/npm commands set to
ask(requires human judgment)
With this configuration, Claude Code can freely read and write code, but asks you every time before executing git or npm commands — ensuring both efficiency and controlled risk.
Principle 4 in Practice: Task Orchestration — Using Sub-agents to Split Tasks
Claude Code has a built-in sub-agent mechanism that can split complex tasks across multiple agents for parallel execution.
Scenario: Refactoring the User Module
Suppose you need to refactor a user module involving 5 files. Don't have AI modify all files at once:
Wrong Approach:
Help me refactor all the code in the user module
Correct Approach:
Help me refactor the user module, following these steps:
1. First read src/models/user.ts and src/api/user.ts to understand the existing structure
2. Propose a refactoring plan and wait for my confirmation before proceeding
3. Modify in this order:
a. Data model layer (models/)
b. API layer (api/)
c. Component layer (components/)
d. Route configuration (router/)
e. Test files (__tests__/)
4. After each layer, run typecheck to confirm no errors
Using Plan Mode
Claude Code has a Plan Mode that plans before executing:
# Enter Plan Mode
> /plan
# Claude Code will first list the plan; it only proceeds after you confirm
The value of this mode: It gives you the opportunity to review and correct course before execution, preventing AI from going off track from the start.
Principle 5 in Practice: Independent Verification — Don't Let AI Judge Its Own Work
This is the most easily overlooked but most critical principle. After AI writes code, independent mechanisms must verify it.
Option 1: Let Claude Code Run Tests
Add verification specs to CLAUDE.md:
## Verification Checklist
After each code modification, the following verifications must be executed:
1. `npm run typecheck` — TypeScript type checking
2. `npm run lint` — ESLint code checking
3. `npm run test -- --coverage` — Unit tests + coverage
4. `npm run build` — Build verification
If any step fails, analyze the error and fix it — do not skip.
Option 2: Configure Pre-commit Hooks
Use husky + lint-staged for automatic verification before commits:
# Install
npm install -D husky lint-staged
# Initialize
npx husky init
# .husky/pre-commit
npx lint-staged
// Add to package.json
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,json}": ["prettier --write"]
}
}
This way, even if AI forgets to run tests, they'll be automatically caught at commit time.
Option 3: Write Test Cases for AI to Pass
Require in CLAUDE.md:
## Testing Requirements
- Each new feature must include corresponding unit tests
- Test files go in the __tests__ directory
- Test cases must cover both happy paths and error paths
- All tests must pass after code changes
Core Idea: Write verification standards as text, letting AI prove itself correct instead of relying on manual inspection.
Principle 6 in Practice: Fault Tolerance — Making Errors Recoverable
AI will make mistakes; the key is being able to recover quickly after mistakes.
Tip 1: Make Good Use of Git Branches
Mandatory requirement in CLAUDE.md:
## Branch Standards
- All AI modifications must be on branches
- Branch naming: ai/feature-description
- After modifications, do not auto-merge; wait for manual user confirmation
This way, even if AI messes up, a git checkout main will restore everything.
Tip 2: Use /compact to Control Context
In long conversations, AI might "forget" earlier content. Use the /compact command to compress context:
/compact
# Claude Code compresses previous conversations into a summary
When to compact:
- After more than 20 rounds of conversation
- When switching to unrelated tasks
- When AI starts repeating questions you've already answered
Tip 3: Continuation After Interruption
If AI's output gets truncated (Claude Code has output length limits), use these commands to continue:
Continue
# or
Continue from where it left off last time
Claude Code will continue from where it left off.
Tip 4: Emergency Stop
Press Escape to immediately stop AI's current tool calls. If AI goes off track while batch-modifying files, pressing Escape twice in a row will completely interrupt it.
Complete Configuration Summary
Putting it all together, a complete Claude Code Harness system looks like this:
your-project/
├── CLAUDE.md # Principle 1: Clear Boundaries
├── .claude/
│ └── settings.json # Principle 3: Permission Control
├── .husky/
│ └── pre-commit # Principle 5: Independent Verification
├── docs/
│ ├── component-guide.md # Principle 2: Layered Information
│ ├── api-conventions.md
│ └── testing-guide.md
├── package.json # lint-staged configuration
└── src/
Core CLAUDE.md Template (ready to copy and use):
# Project Overview
[One sentence describing the project]
## Tech Stack
[List core dependencies and versions]
## Code Standards
[3-5 most critical rules]
## Forbidden Zones (Absolutely must not do)
- [Rule 1]
- [Rule 2]
- [Rule 3]
## Operational Standards
1. Read relevant files before modifying
2. Explain modification plan and wait for confirmation before proceeding
3. Run typecheck + lint + test after changes
4. Modify on branches, do not touch main directly
## Verification Checklist
- [ ] TypeScript type check
- [ ] ESLint check
- [ ] Unit tests
- [ ] Build verification
## Branch Standards
- All modifications on branches with ai/ prefix
- No auto-merging, wait for user confirmation
One-Sentence Summary
Harness Engineering isn't a specific feature — it's a design mindset. Before AI can work, design how to constrain it, guide it, verify it, and tolerate its faults. Use CLAUDE.md to write clear boundaries, permission controls for safety, independent verification for quality, and Git branches for fault tolerance. With these four tools in place, you've upgraded from "using AI to write code" to "harnessing AI to write code."
Next Article Preview: Harness Engineering Industry Comparison: Claude Code vs OpenAI Codex vs Cursor — A horizontal evaluation of the Harness designs of three major AI programming tools to see who has the most complete harness system.