The Navigator · 18 min mission

Claude Code Harness Engineering and Configuration

Build a repo-specific Claude Code harness with instructions, permissions, hooks, skills, subagents, MCP, and verification.

harness engineeringconfigurationclaude-codepermissionsskillsFact-checked 2026-07-06
On this page

This guide shows you how to turn Claude Code from a capable coding assistant into a repo-specific engineering harness with instructions, permissions, hooks, skills, subagents, MCP, and verification.

Who this is for

Use this if you already run Claude Code and want repeatable results across a real repository. The goal is not more prompting. The goal is a small operating layer around Claude Code that gives it the right context, blocks the wrong actions, routes repeated work into reusable tools, and proves the result before you trust it.

You need:

  • Claude Code installed and authenticated.
  • Permission to add or edit CLAUDE.md, .claude/settings.json, .claude/skills/, and .claude/agents/.
  • At least one validation command, such as lint, tests, typecheck, build, or a browser smoke test.
  • A git branch or worktree for changes.

Expected result: a starter Claude Code harness that a teammate can clone, inspect, and improve without relying on a transcript from your machine.

Define harness engineering in Claude Code

Harness engineering is the work of designing the environment around the agent loop. Claude Code already knows how to read files, edit code, run tools, ask for permission, and continue after tool results. Your harness decides what the agent sees first, what it can do without asking, which workflows load on demand, which external systems are available, and which checks must pass before a task is called done.

A useful Claude Code harness has six layers:

  1. Stable repo context in CLAUDE.md.
  2. Permission and sandbox policy in settings.
  3. Deterministic hooks for checks and blocks.
  4. Skills or custom commands for repeated procedures.
  5. Subagents for fresh-context work.
  6. MCP or plugins for shared external capabilities.

Do not start at layer six. A repo with no test command in CLAUDE.md usually does not need three MCP servers yet.

MechanismUse it forAvoid it when
PromptOne current task, scope, and acceptance criteriaThe instruction should persist across sessions
CLAUDE.mdStable repo facts, commands, constraints, and pointersThe content is a long workflow or reference manual
SkillA repeated procedure, checklist, or reference set loaded on demandThe rule must block unsafe behavior
SubagentNoisy research, fresh review, specialist checks, parallel workThe work needs the main thread to keep every detail
HookA deterministic action or gate at a lifecycle eventThe decision needs judgment
MCPLive external tools or data used repeatedlyA CLI export or pasted context is enough
PluginA shared bundle of skills, agents, hooks, settings, or MCPThe workflow is still changing every day
Permission ruleAllow, ask, or deny exact tool useThe issue is only missing context
Claude Code configuration mechanisms. Use the narrowest mechanism that solves the repeated problem.

Audit and generate a harness starter

Harness workbench

Check the setup before the agent runs

Use this locally before you widen permissions, add MCP, or start a long run.

Switch to Claude Code mode, score the setup, choose a configuration mechanism, scan a CLAUDE.md excerpt, and generate a starter manifest.

Start with a minimal setup

The minimal setup is small enough to review in one sitting. It gives Claude Code the repo map, exact checks, safe default permissions, and one place to put repeated workflows.

Minimal Claude Code harness layout
bash
.
|-- CLAUDE.md
|-- .claude/
|   |-- settings.json
|   |-- hooks/
|   |   `-- validate-edits.sh
|   |-- skills/
|   |   `-- release-check/
|   |       `-- SKILL.md
|   `-- agents/
|       `-- code-reviewer.md
|-- docs/
|   `-- agent-runs/
`-- package.json
Starter CLAUDE.md
markdown
# CLAUDE.md
 
## Project map
- Next.js app router site.
- Routes live in app/.
- Shared logic lives in lib/.
- Reusable UI lives in components/.
- Generated output lives in out/ and must not be edited.
 
## Setup
- Install: npm install
- Dev server: npm run dev
 
## Checks
- Lint: npm run lint
- Test: npm test
- Build: npm run build
 
## Working rules
- Read the nearest domain docs before editing that area.
- Keep edits scoped to the requested outcome.
- Do not change auth, payments, secrets, migrations, deploy scripts, or generated files without explicit approval.
- Before completion, report changed files, checks run, and remaining risk.
 
## Routing
- Use .claude/skills/release-check/SKILL.md for release readiness work.
- Use .claude/agents/code-reviewer.md for fresh review of non-trivial diffs.
.claude/settings.json starter permission policy
json
{
  "permissions": {
    "allow": [
      "Bash(npm run lint *)",
      "Bash(npm test *)",
      "Bash(npm run build *)",
      "Bash(git status *)",
      "Bash(git diff *)"
    ],
    "ask": [
      "Bash(git commit *)",
      "Bash(git push *)",
      "Bash(npm install *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Bash(rm -rf *)",
      "Bash(curl *)",
      "Bash(wget *)"
    ]
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/validate-edits.sh"
          }
        ]
      }
    ]
  }
}
.claude/hooks/validate-edits.sh
bash
#!/usr/bin/env bash
set -euo pipefail
 
payload="$(cat)"
file_path="$(printf '%s' "$payload" | jq -r '.tool_input.file_path // empty')"
 
case "$file_path" in
  *.ts|*.tsx|*.js|*.jsx)
    npx prettier --write "$file_path"
    npm run lint -- --file "$file_path" >/tmp/claude-lint.log 2>&1 || {
      tail -n 40 /tmp/claude-lint.log >&2
      exit 2
    }
    ;;
esac

Move repeated work into a skill

A skill is better than a long CLAUDE.md section when the instruction is procedural. The description is the trigger surface. Keep it specific so Claude loads the skill only when it fits the task.

.claude/skills/release-check/SKILL.md
markdown
---
name: release-check
description: Use before merging or publishing a web app change that needs lint, tests, build, preview review, and a short risk note.
allowed-tools: Bash(npm run lint *) Bash(npm test *) Bash(npm run build *) Bash(git diff *) Bash(git status *)
---
 
# Release check
 
Run this procedure before saying a change is ready.
 
1. Inspect the current diff.
2. Run lint, tests, and build.
3. If the app has a UI change, start the preview and inspect the route.
4. Summarize changed files, validation commands, failed checks, and remaining risk.
5. Do not commit unless the user asks.

Add subagents with narrow roles

Use a subagent when the side task would flood the main context or when the implementation needs a fresh reviewer. Avoid vague roles such as "senior engineer" because they do not tell Claude when to delegate or what evidence to return.

Subagent role quality

Too vague

name: expert-reviewer\n\ndescription: Reviews code and finds problems.\n\nThis role has no scope, severity model, tool limit, or return format.

Usable

name: regression-reviewer\n\ndescription: Use after implementation to review the diff for behavior regressions, missing tests, unsafe auth/payment changes, and P0/P1 blockers. Return only findings with file paths, severity, evidence, and suggested fix.

.claude/agents/code-reviewer.md
markdown
---
name: code-reviewer
description: Use after a non-trivial implementation to review the current diff for correctness, regressions, missing tests, and unsafe changes.
tools: Read, Grep, Glob, Bash
---
 
Review only the current diff and directly related files.
 
Report findings as:
- severity: P0, P1, P2, or P3
- file and line when available
- evidence from the code
- suggested fix
 
Do not rewrite the code. Do not comment on style unless it hides a bug.
NeedUse MCP?Better simpler option
Read a single ticket onceNoPaste the ticket or export it with a CLI
Repeatedly query Jira, Linear, Sentry, or docsYesNone, if the workflow repeats across tasks
Run a local script already in the repoNoAllow the exact Bash command
Share a tool with a teamMaybeA plugin if it bundles skills, MCP, and settings
Access production dataOnly with reviewRead-only export, audit log, and explicit owner approval
MCP is useful when the external state is live, repeated, and safer to query through a tool than paste into chat.

Expand to a production setup

The production setup is not bigger for its own sake. It adds ownership and proof:

  • CLAUDE.md stays short and imports deeper docs only when useful.
  • .claude/settings.json denies secrets, destructive commands, and production paths by default.
  • Hooks enforce deterministic checks and never hide their failures.
  • Skills hold release, incident, migration, and review procedures.
  • Subagents separate research, implementation review, test repair, and security checks.
  • MCP servers are pinned, documented, and limited to workflows with repeated external state.
  • Worktrees isolate long-running or parallel work.
  • Verification evidence is written to docs/agent-runs/<task>.md for long tasks.
Weak ruleCorrected rule
Always write clean code.Run npm run lint and npm test before completion. Flag any remaining failure with command output.
Claude can run any command it needs.Allow Bash(npm test *), Bash(npm run lint *), Bash(git diff *); ask for git commit; deny rm -rf, curl, wget, and .env reads.
Use MCP for docs.Use MCP only when the task needs current external docs repeatedly. For one-off docs, paste the relevant source link or export.
Review your own work carefully.After implementation, invoke code-reviewer on the diff and require no P0/P1 findings before completion.
Examples of weak harness rules and corrected versions.
Failure modeWhat it looks likeFix
Context bloatCLAUDE.md contains tutorials, API docs, and old run logsMove procedures to skills and references; keep CLAUDE.md as a router
Conflicting instructionsRoot file says run all tests; package file says never run all testsMake default and exception explicit, with package owner
Unsafe permissionsBroad Bash(*) or network commands allowed by defaultAllow exact commands; ask or deny everything else
Stale docsCommands in CLAUDE.md no longer existRun the setup from a clean checkout and update the file
Overused MCPEvery external system is connected before a workflow needs itStart with one high-frequency tool and audit usage
Vague subagentsSubagent names are roles, not jobsDefine trigger, scope, tools, evidence, and output format
Blocking hooksHooks run slow global checks after every editScope hooks to file type, event, and fast checks
Failure modes to catch during a harness audit.

Verification workflow before trusting output

  1. Check the diff

    Run git diff --stat and inspect changed files. Confirm the diff matches the requested scope.

  2. Run deterministic checks

    Run lint, typecheck, tests, and build. Use scoped checks while iterating and the full gate before completion.

  3. Review the runtime behavior

    Start the app or preview route. Inspect the affected path on desktop and mobile when UI changed.

  4. Ask for fresh review

    Use a reviewer subagent or /code-review style workflow. The implementing context should not be the only grader.

  5. Record evidence

    List commands, screenshots or preview notes, changed files, and remaining risks in the final response or a state file.

Adopt the harness incrementally

  1. Write the minimal CLAUDE.md

    Add setup, checks, protected paths, and completion evidence. Keep it under reviewable length.

  2. Add permission policy

    Allow the exact safe commands. Ask for package installs and git operations. Deny secrets and destructive commands.

  3. Add one hook

    Start with a fast edit validation or Stop gate. Remove it if it blocks normal work without producing useful evidence.

  4. Extract one skill

    Pick the workflow you paste most often and turn it into a skill with a narrow description.

  5. Add one reviewer subagent

    Use it after implementation. Tune its output until it finds concrete issues without dumping broad commentary.

  6. Connect one MCP server

    Add MCP only when a repeated workflow needs live external state. Document the risk and owner.

Reach the end and this star joins your charted sky.