# Set up an agent harness that gets code right the first time

This lesson sets up the harness we build with every day: the context, conventions, memory,
loop and checks around a coding agent, so that more of its work is right before anyone
reviews it. There are eight steps. Each one says what to do, how to tell it worked, and links
to a short post on why we do it that way. Plan on about an hour, most of it in steps 1, 4
and 7.

You can follow it yourself, or hand this page to your agent.

> **If you are an agent reading this for your person:** do the steps in order. Run each
> command from the step, show your person the result of each "You're done when" check before
> you start the next step, and stop for them whenever a step installs software, asks them to
> trust hooks, or edits their `CLAUDE.md`. Use the exact versions and hashes shown; if a hash
> does not match, stop and say so.

## Before you start

- Claude Code, signed in. (Using Codex? The PER kit, engram and Amber CLI each document a
  Codex path in their READMEs; this lesson follows Claude Code.)
- A git repository you build in. The steps call it *your project*.
- macOS or Linux with `git`, `ruby`, `shasum` (or `sha256sum`) and Homebrew.
- Step 7 is for Crystal projects. On another language, do step 7's shape with your language's
  tools, as its post explains.

## Step 1. Keep one short file of rules for every task, and put each procedure in a skill

Download the kit from
[the PER kit v0.1.0 release](https://github.com/crimson-knight/per-kit/releases/tag/v0.1.0),
then check it and install it:

```sh
curl -fLO https://github.com/crimson-knight/per-kit/releases/download/v0.1.0/per-kit-v0.1.0.zip
shasum -a 256 per-kit-v0.1.0.zip   # 7f57b4ea90db01fb9a3bfb1fef12551b857915f36e9a4795679c79842070f795
unzip per-kit-v0.1.0.zip && cd per-kit
shasum -a 256 SHA256SUMS           # a54cba20f30dc6f9c5e097c98bdb0a1fa3b8ac7d0aab5609765011c245f5efa5
./verify.sh --strict               # ends with RESULT: PASS
./install.sh ~/per-kit
```

Open `~/per-kit/CLAUDE.md` (eleven rules that hold on every task) and
`~/per-kit/.claude/skills/` (four procedures: `plan`, `execute`, `reflect`, `run-task`).
Then give your project the same shape. In Claude Code, in your project, send:

```text
Read CLAUDE.md. List every section that only matters for one kind of task (a deploy, a
migration, a release, a review). For each one, create .claude/skills/<task-name>/SKILL.md
with frontmatter `name:` and `description:` (what it does, then "Use when ..."), move the
section's text there, and leave CLAUDE.md with only the rules that hold on every task.
Show me the before and after line counts.
```

**You're done when:** `./verify.sh --strict` ended with `RESULT: PASS`; your project's
`CLAUDE.md` holds only rules that apply to every task; and `ls .claude/skills` lists one
folder per procedure, each `SKILL.md` starting with a `name:` and a `description:` that says
when to use it.

**Why?** [The CLAUDE.md that grew a line every time the agent got something wrong](/blog/why-skills-instead-of-one-global-configuration)

## Step 2. Name things with the AED conventions

Install the AED plugin at its release tag and confirm the commit:

```sh
claude plugin marketplace add AgentC-Consulting/aed-conventions#plugin-v0.2.1
claude plugin install aed@aed-conventions
git -C ~/.claude/plugins/marketplaces/aed-conventions rev-parse HEAD
# 75f49f2c7fc299de2aac7afc0c69fc30abe324a6
```

Start Claude Code in your project and run:

```text
/aed:adopt
/aed:check src
```

`/aed:adopt` adds an "AED conventions" section to your `CLAUDE.md`, or to `AGENTS.md` (imported
from `CLAUDE.md`) if your project uses one. `/aed:check` lints the
folder (Ruby, Crystal and Elixir), applies the clear renames, and lists the judgment calls.
From now on the plugin's hook reports naming findings after every edit. It never blocks one.

**You're done when:** `rev-parse` printed the commit above; `CLAUDE.md` (or `AGENTS.md`) has the AED section;
and `/aed:check src` has run, with each finding renamed or noted with a reason.

**Why?** [You wrote the late-fee rule. What does it mean now?](/blog/why-we-name-code-for-the-agent)

## Step 3. Give the agent shared memory with engram, and make each lesson name what enforces it

```sh
brew install crimson-knight/tap/engram
engram version          # engram 0.2.0
cd ~/path/to/your-project
engram init
engram hook install     # memories follow branches on checkout, merge and rebase
engram new "<one decision your project already made>" --topics <subject>,lesson
```

Open the file `engram new` printed. Fill in **Decision**, **Why** and **Rejected**. Because
this one is a lesson, end it with a line that names what makes it true without anyone
remembering it:

```text
Enforced by: spec/billing/apply_late_fee_to_overdue_invoice_spec.cr
```

or, when nothing can check it, `Automation impossible: <the reason>`. Then:

```sh
engram sync
engram search "<a word from your title>"
git add .agents .gitignore && git commit -m "Record the first engram memory"
```

**You're done when:** `engram search` finds your memory, it is committed under
`.agents/memories/`, and this check prints nothing:

```sh
for f in .agents/memories/*.md; do
  grep -q '^topics:.*lesson' "$f" && ! grep -qE '^(Enforced by|Automation impossible):' "$f" && echo "$f"
done
```

**Why?** [We wrote the lesson down twice, and the mistake kept happening](/blog/why-every-memory-names-what-enforces-it)

## Step 4. Run one task through plan, execute and reflect

Feel the loop once on the kit's sample data. It takes about 10 minutes and needs no accounts:

```sh
cd ~/per-kit
claude
```

Type `/run-task workspace/tasks/invoice-follow-up` and answer "yes" when it asks
"Go ahead with this plan?". Read the plan before you say yes, and read `report.md` when it
finishes.

Then bring the loop to your project. Paste this block into your project's `CLAUDE.md`. Its six
rules are the kit's rules 1, 2, 3, 4, 7 and 8, rewritten for code and for engram:

```markdown
## The loop: plan, execute, reflect
1. Plan before you do. Write the plan to plans/<task>.md before you change code: the goal,
   what done means, and milestones a stranger could carry out with no questions. Wait for
   my go-ahead.
2. Read the notes first. Start every plan by searching engram for the task's subject, and
   list the memories that apply under "Lessons applied" (or write "none apply").
3. One milestone at a time. Finish and check one before you start the next.
4. A self-report is a claim. Done means the code was run: the build is clean, the specs
   pass, and each user journey the change touches was exercised once.
5. Stuck twice, stop and write it down: what happened, what you tried, your best guess at
   the cause, and what you need.
6. Write down what you learned. Every task leaves at least one engram memory, and a lesson
   ends with "Enforced by:" or "Automation impossible:".
```

**You're done when:** `~/per-kit/workspace/runs/invoice-follow-up-<stamp>/` holds `plan.md`,
`output/` and `report.md`; the report ends with "Estimated vs actual time" and "What this
run could not do"; `~/per-kit/workspace/lessons.md` has a new entry with an `Applies when:`
line; and your project's `CLAUDE.md` has the loop block.

**Why?** [Would you send the reminder your agent just checked?](/blog/why-plan-execute-reflect)

## Step 5. Install the hooks that check each stage of the loop

The engram agent kit adds the session-start, stop and compaction hooks. Install it at its
release tag and confirm the commit:

```sh
claude plugin marketplace add crimson-knight/engram#v0.2.0
claude plugin install engram@engram-agent-kit
git -C ~/.claude/plugins/marketplaces/engram-agent-kit rev-parse HEAD
# 96594873f6b7e12b1afbc8287defb4b6ed010986
```

Read the hooks before you rely on them, since a hook runs with your permissions:
`~/.claude/plugins/marketplaces/engram-agent-kit/plugins/engram/hooks/hooks.json`. Then restart
Claude Code in your project and type `/hooks`.

Now test the reflect gate: ask the agent to add one comment line to any file and then stop,
without recording a memory. The stop is refused once with this message:

```text
engram-reflect-gate: state changed but no ledger write was found. Before stopping, record one useful decision, result, or lesson as an engram migration under .agents/memories/ and run engram sync. A reader miss also requires a memory with topic reader. Escape hatch: ENGRAM_GATE_BYPASS=1.
```

**You're done when:** `/hooks` lists SessionStart, Stop, PreCompact and PostCompact from
engram and PostToolUse from aed; and the test stop was refused with the message above, then
allowed after the agent recorded a memory.

**Why?** [They asked Claude Code for a code review. Then they checked the commits.](/blog/why-rules-belong-in-hooks)

## Step 6. Decide what survives compaction: waypoints and checkpoints

A waypoint is one plan milestone sized to finish inside one context window: one goal, the
files it touches, and the check that proves it. Add this rule to the loop block from step 4:

```markdown
7. One waypoint per context window. Size each milestone so it can finish before the context
   fills. Before compacting or stopping, run /engram:checkpoint.
```

Then try it once on real work. Partway through a task, type `/engram:checkpoint`, then
`/compact`, then ask: "What is the next action?"

**You're done when:** the checkpoint prints its file path and line count; the file has
MISSION, STATE, NEXT, SKILLS, RULES and TRAPS sections; and after `/compact` the agent names
the NEXT action from the checkpoint, word for word, before it reads any file.

**Why?** [After the summary, where did your agent's checklist go?](/blog/why-waypoints-decide-what-survives-compaction)

## Step 7. Let the language server check conventions while the agent writes

For a Crystal project (an Amber V2 app, a plain Crystal app or a shard):

```sh
HOMEBREW_NO_AUTO_UPDATE=1 brew install amberframework/amber_cli/amber_cli
amber --version          # Amber CLI v2.0.7
amber-lsp --version      # amber-lsp 1.0.0 (amber_cli 2.0.7, ...)
cd ~/path/to/your-project
amber setup:agent
amber doctor
amber-lsp lookup 'Dir.mkdir_p'
```

Open the project in Claude Code and accept the workspace trust prompt, then run
`amber doctor` again. Commit what `setup:agent` wrote, so every clone and worktree gets it:

```sh
git add .amber .claude/settings.json .codex/hooks.json CLAUDE.md AGENTS.md
git commit -m "Connect the agent to amber-lsp"
```

**You're done when:** every `amber doctor` line shows `[PASS]` or `[SKIP]`, and the lookup printed
`Dir.mkdir_p(path : Path | String, mode : Int32 = 511) : Nil`.
One exception on Amber CLI 2.0.7: if Codex is installed but you do not use it in this project,
the Codex trust line shows `[FAIL]`, and you can leave it. A fix that reports that line as
`[SKIP]` is in review ([amber_cli PR #46](https://github.com/amberframework/amber_cli/pull/46)).

Not on Crystal? Put your language's tools in the same two places: a lookup the agent runs
before it calls an API it has not used, and a PostToolUse hook that checks each edited file.

**Why?** [Your agent called a method that doesn't exist. When should it find out?](/blog/why-the-language-server-checks-while-the-agent-writes)

## Step 8. Review the work that is left: behavior and decisions

When the agent says a change is done, review it in four reads, in this order:

```sh
git log --oneline main..HEAD
git diff --stat main..HEAD -- plans .agents/memories
```

1. Read the plan, and the check recorded for each milestone.
2. Read each memory the change added. That is the "why" you would otherwise ask for.
3. Run the change: each user journey it touches, once.
4. Read the diff for behavior and decisions.

When review finds something a check could have caught, record it as a lesson with its
`Enforced by:` line, and build that check.

**You're done when:** you have reviewed one change this way and none of your comments were
about names, types or formatting, because the hooks had already reported them.

**Why?** [To the builder who is worn out from reviewing their agent's code](/blog/review-less-code-by-getting-it-right-the-first-time)

## What you have now

| Stage | What runs | From |
|---|---|---|
| Session start | Memory index and setup check load | engram kit, `amber setup:agent` |
| Plan | Loop rules, engram search, AED planning skill | your `CLAUDE.md`, aed plugin |
| Before an edit | `.cr` edits held until `amber-lsp` is installed and verified | `amber setup:agent` |
| After an edit | Naming check, format, Amber rule check | aed plugin, `amber setup:agent` |
| Stop | Build check; a memory must be written | `amber setup:agent`, engram kit |
| Compaction | Checkpoint first, restored word for word after (up to 6,000 characters) | engram kit |
| Review | Plan, memories, a run, then the diff | you |
