Page 6 of 13 · Harness engineering, hands on
The primitives, hands on
A heavy user knows the features. An agentic engineer knows which primitive to reach for: when a rule belongs in AGENTS.md, a skill or a hook, when to split work into a subagent, and when MCP beats a CLI. The examples use Claude Code because its hooks are well documented; Codex, Cursor and Gemini CLI have close equivalents of most of what follows.
5 runnable samples1 prediction3 questions
Level 1 · The rules
The primitives at a glance
| Primitive | What it is | Reach for it when |
|---|---|---|
| CLAUDE.md / AGENTS.md | Project instructions loaded at session start | Stable conventions, commands, architecture notes |
| Skills | Folders with a SKILL.md and scripts; only the description stays loaded | Repeatable procedures needed some of the time |
| Subagents | Agents with their own context, prompt and tools | Noisy exploration, research, parallel independent work |
| Hooks | Commands fired on lifecycle events | Rules that must hold every time; context injection; logging |
| Slash commands | Saved prompts you trigger by name | Workflows you start yourself |
| Plugins | Bundles of skills, hooks, commands, agents and MCP servers | Sharing one setup across projects or a team |
| MCP servers | External tools and data over a standard protocol | No good CLI, managed auth, SaaS integrations |
| Headless mode | claude -p, non-interactive | CI jobs, scheduled tasks, pipelines |
| Git worktrees | Several checkouts of one repo | Parallel agents that must not collide |
| Plan mode | Agent proposes a plan before editing | Unfamiliar code, risky changes |
| Statusline | A command that renders model, context use and cost per session | Always: you can't improve what you can't see |
Level 1 · The rules
Hooks: the only guarantee
Everything else in the harness is advice the model weighs. A hook is code that runs every time its event fires. It receives the event as JSON on stdin and answers with an exit code.
Hook exit codes
- 0: success. The action proceeds. For most events stdout is not shown to the model.
- 2: blocking error. For PreToolUse the tool call is blocked and stderr is sent to Claude as the reason.
- Anything else, including 1: a non-blocking error. The action still proceeds.
def after_pre_tool_use_hook(exit_code, stderr): if exit_code == 0: return "tool runs" if exit_code == 2: return "tool blocked, Claude reads: " + stderr return "tool runs anyway (non-blocking hook error)"for code in (0, 2, 1): print( code, "->", after_pre_tool_use_hook(code, "Migrations are generated, never edited"), )
[ OUTPUT ]
Press Run to see the output this code printed when the course was built.
The hook logic itself, written as a testable function. The payload has the same shape Claude Code sends on stdin for an Edit or Write call:
import jsondef migration_guard(payload): path = payload.get("tool_input", {}).get("file_path", "") if "/migrations/" in path: return ( 2, "Migrations must be generated with prisma migrate, never edited by hand", ) return 0, ""edit_migration = json.loads( '{"tool_name": "Edit", "tool_input": {"file_path":' ' "prisma/migrations/20261012_init/migration.sql"}}')edit_service = json.loads( '{"tool_name": "Edit", "tool_input": {"file_path": "src/users/users.service.ts"}}')print(migration_guard(edit_migration))print(migration_guard(edit_service))
[ OUTPUT ]
Press Run to see the output this code printed when the course was built.
Wired up in .claude/settings.json (configuration, so not executed here):
{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "python3 .claude/hooks/migration_guard.py" } ] } ] }}
SessionStart
Inject context or set environment at the start, resume or after compaction.UserPromptSubmit
Inspect the prompt; add just-in-time context when it matches an intent.PreToolUse
Gate: block, allow or modify a tool call before it runs.PostToolUse
Side effects after a tool: format, lint, log, feed back problems.Stop / SubagentStop
Decide whether the agent may finish, for example "tests must pass first".PreCompact
Save what matters before the conversation is summarized.
Level 2 · Why it works
A Stop hook that can loop forever
A Stop hook that exits 2 forces Claude to keep working. If its condition never becomes true, the agent never stops. Claude Code passes stop_hook_active so your hook can tell it is already continuing because of itself.
def stop_hook(payload): tests_pass = False return 2 if not tests_pass else 0def finish(turn=0): if stop_hook({"stop_hook_active": turn > 0}) == 2: return finish(turn + 1) return "done"finish()
[ TRACEBACK ]
Press Run to see the output this code printed when the course was built.
def stop_hook(payload): tests_pass = False if payload["stop_hook_active"]: return 0 return 2 if not tests_pass else 0def finish(turn=0): if stop_hook({"stop_hook_active": turn > 0}) == 2: return finish(turn + 1) return f"done after {turn + 1} attempts"print(finish())
[ OUTPUT ]
Press Run to see the output this code printed when the course was built.
Level 2 · Why it works
Subagents and the brief
A subagent starts with a clean context. It knows only what the parent writes in the brief. That is its strength (no noise) and its weakness (no implicit knowledge).
parent_knows = { "task", "repo layout", "never edit migrations", "use pnpm", "tests must pass",}brief = {"task", "repo layout", "tests must pass"}lost = sorted(parent_knows - brief)print("subagent never hears:", lost)
[ OUTPUT ]
Press Run to see the output this code printed when the course was built.
Level 3 · Mastery
CLI or MCP, and running many agents
"The agent has a shell and git, gh, kubectl exist."
CLI
The model already knows them, output pipes, almost no context cost.
"No shell (claude.ai, a desktop app) or OAuth is needed."
MCP
Managed auth, typed tools, works in any MCP client.
"Twenty MCP tools loaded, three used."
Trim or defer
Every tool definition costs context on every turn.
| Parallel work need | Tool |
|---|---|
| Several agents on one repo without collisions | One git worktree per agent |
| Agents that survive closing the terminal | A terminal multiplexer such as tmux, or the agent's own background mode |
| Agents in CI | Headless claude -p with tight permissions and structured output |
Predict the output
Level 2 answer before you look
Check your understanding
Levels 1 to 3 open a question to see the answer
A PreToolUse hook exits 1. Does the tool call run?
Yes. Only exit code 2 blocks. Any other non-zero code is a non-blocking error.
When is a skill better than a CLAUDE.md rule?
When the content is a long procedure needed only for some tasks. The description stays loaded; the body loads on demand, so it costs nothing until it matters.
Why does a Stop hook need to check stop_hook_active?
Without it, a hook whose condition never becomes true forces Claude to continue forever.