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

PrimitiveWhat it isReach for it when
CLAUDE.md / AGENTS.mdProject instructions loaded at session startStable conventions, commands, architecture notes
SkillsFolders with a SKILL.md and scripts; only the description stays loadedRepeatable procedures needed some of the time
SubagentsAgents with their own context, prompt and toolsNoisy exploration, research, parallel independent work
HooksCommands fired on lifecycle eventsRules that must hold every time; context injection; logging
Slash commandsSaved prompts you trigger by nameWorkflows you start yourself
PluginsBundles of skills, hooks, commands, agents and MCP serversSharing one setup across projects or a team
MCP serversExternal tools and data over a standard protocolNo good CLI, managed auth, SaaS integrations
Headless modeclaude -p, non-interactiveCI jobs, scheduled tasks, pipelines
Git worktreesSeveral checkouts of one repoParallel agents that must not collide
Plan modeAgent proposes a plan before editingUnfamiliar code, risky changes
StatuslineA command that renders model, context use and cost per sessionAlways: 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

  1. 0: success. The action proceeds. For most events stdout is not shown to the model.
  2. 2: blocking error. For PreToolUse the tool call is blocked and stderr is sent to Claude as the reason.
  3. Anything else, including 1: a non-blocking error. The action still proceeds.
python[ RUNS ]

How Claude Code treats a PreToolUse hook's exit code

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 ]recorded · Python 3.14.8

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:

python[ RUNS ]

A migration guard, tested with real payload shapes

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 ]recorded · Python 3.14.8

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):

json

settings.json hook registration (configuration file, not executable)

{  "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.

python[ RAISES RecursionError ]

A Stop hook with no escape hatch

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 ]recorded · Python 3.14.8

Press Run to see the output this code printed when the course was built.

python[ RUNS ]

The fix: respect stop_hook_active

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 ]recorded · Python 3.14.8

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).

python[ RUNS ]

What survives a handoff

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 ]recorded · Python 3.14.8

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 needTool
Several agents on one repo without collisionsOne git worktree per agent
Agents that survive closing the terminalA terminal multiplexer such as tmux, or the agent's own background mode
Agents in CIHeadless 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.