# Week 3: Backpressure

> Harness engineering is the art of giving good negative feedback — the model generates; the harness rejects what's wrong, fast and automatically

# Welcome

---

# Week 3

## Backpressure

---

the model generates

the harness **rejects**

---

## what changed this week?

["believe in yourself" and make progress on the Riemann hypothesis](https://www.anthropic.com/research/riemann-zeta)

DeepSeek V4 Pro 0813

---

## today's beats

code generation is cheap, so pushing back and saying no is the key

SSGs: a website build step

short feedback loops

---

## demo: what will the checks say?

starting from
[MARKDOWN](https://comp4020-agentic-coding-studio.github.io/comp4020-crit2-Astra-Erevos/),
a C2 pick, copied into the demo repo as-is

> Our brand guidelines say this site should be red, white and blue. Add a check
> that enforces that, then make the site pass it.

---

# the harness pushes back

---

## backpressure

code generation is cheap now
([Willison: _writing code is cheap now_](https://simonwillison.net/guides/agentic-engineering-patterns/code-is-cheap/))

what's scarce is automatic rejection of the bad output: checks that run on every
change and tell the agent what's wrong

"negative feedback" in both senses: the control loop that steers a system, and
the crit comment about the prototype rather than the author

---

## guides and sensors

**guides** are in the context window _before_ the model writes: `CLAUDE.md`, a
skill, the spec, the plan

**sensors** read what it wrote _after_: exit codes, lint output, type errors,
test results, the rendered page

([Böckeler, 2026](https://martinfowler.com/articles/harness-engineering.html);
[Learn Harness Engineering](https://walkinglabs.github.io/learn-harness-engineering/en/))

---

# **words**; what do they even mean?

---

## a failing check, fed back

---

## useful sensors

**specific**: file, line, expected versus actual

**fast**: the error lands in the same turn as the mistake

**automatic**: runs on every change, so it costs none of your attention, the
scarcest thing in the loop

**trustworthy**: a check that's sometimes wrong teaches you (and the agent) to
ignore red

---

## the sensors already in your repo

---

## CI's extra checks

`pnpm check` again, on a clean machine

then the ones `pnpm check` doesn't run: `pnpm check:evidence`, internal links
(`linkinator ./dist`), committed secrets (trufflehog), and whether the deployed
page is really up

all in `.github/workflows/checks.yml`

---

## a type error, as the agent reads it

```text
src/data/posts.ts:14:24 - error TS2551: Property 'titel' does not
exist on type 'Post'. Did you mean 'title'?
```

a nag to you; a rule name and a location to the agent

_plausible_ code — the agent's failure mode — is exactly what a type checker
turns red

---

## agents are better at reading errors

a wall of red is demoralising to you and just input to the agent, every line,
every time

so your job becomes deciding which failures are worth reporting at all

---

## a stylelint error

```text
src/styles/main.css
 42:3  ✖  Unexpected duplicate "color"
          declaration-block-no-duplicate-properties
 58:1  ✖  Unexpected unknown pseudo-class ":focus-visble"
          selector-pseudo-class-no-unknown
```

CSS is where agent mistakes go unnoticed longest, because no other check flags a
selector that matches nothing

---

## a failing test

```text
FAIL  spec/invariants.test.ts > every page links home
AssertionError: expected 3 pages to link home, got 2
  dist/about/index.html
```

lint and types reject code that's malformed; only a test rejects code that's
_wrong_\*, because only a test encodes what the code was supposed to do

one well-aimed failing test will reorganise an agent's whole approach

---

## vitest test discovery

`vitest run` globs for `**/*.{test,spec}.?(c|m)[jt]s?(x)`, skipping
`node_modules` and `.git`
([vitest docs: `include`](https://vitest.dev/config/include))

```text
spec/invariants.test.ts   ✓ found
spec/rsvp.test.ts         ✓ found
spec/rsvp-tests.ts        ✗ never runs
```

a file that doesn't match the glob never runs; in one that does, any `it(...)`
that throws fails the run (exit 1)

---

## checks before every commit

**ask**: a line in `CLAUDE.md`; the agent _usually_ does it

**enforce**: a git hook runs on every commit, whoever makes it

```sh
# add to .githooks/pre-commit
pnpm check || exit 1
```

non-zero aborts the commit; the agent reads the failure as its tool result

(your repo's `prepare` script already points git at `.githooks/`)

---

## Ben uses… only push on green

> commit at each logical checkpoint, but only when the full suite of tests,
> lints, and other checks passes — never commit a red state

that line is in my `~/.claude/CLAUDE.md` — the user-level one included in every
session

each project's `CLAUDE.md` names its checks, so "green" means something
different in each

---

## changes (and reverts) are cheap

**interrupt** mid-response (`Esc`), **rewind** the conversation (`/rewind`),
**revert** the commit (`git revert`) — which one is cheap depends on how early
you are

agents drive git far better than most of us, and as long as you have a good
mental model you can be **fearless**

---

## what should it do next?

_on screen: the check it wrote_

(half a minute with the person next to you, then call it out — one of them gets
typed in and run)

---

back to the **demo**

---

# Web

---

## static site generators

the build step between what you write and what you ship: content _in_ (often
`.md`), plain HTML, CSS and JavaScript _out_

[Astro](https://astro.build) is the course default from C2;
[Eleventy](https://www.11ty.dev) and [Jekyll](https://jekyllrb.com) are the same
idea with different conventions for the input

whichever you pick, GitHub Pages serves it

---

# which box does what?

---

## why (not) use a build step?

**for**: the layout, nav and footer written once (html has no `include`); a
restyle touches one layout, not every page; markdown is easier to write than
html

**against**: a config file, a dependency tree, more things to fail and go out of
date

for a three-page site, hand-written html is often the right call — especially
when an agent is writing it

---

## the cheapest backpressure is a shorter loop

`pnpm dev` serves from source and rebuilds on save, and hot reload pushes the
result into the browser

a shorter loop makes every other signal arrive sooner

---

## the dev server is not the built site

the dev server serves every file in your repo; the build copies only what's
imported or in `public/`, so `data/` never reaches `dist/`

```text
fetch("data/ports.json")
  pnpm dev        200
  deployed site   404
```

`pnpm build` then `pnpm preview` serves `dist/`, which is what ships

---

## can the agent see what it built?

everything so far checks the code, but can't tell the agent what the page
**looks like**

[agent-browser](https://github.com/vercel-labs/agent-browser) drives a real
browser: screenshots, the accessibility tree, the console

works in dev and prod

(used deliberately rather than defensively, this is a named pattern — **agentic
manual testing**, week 5)

---

## Ben uses… a format-on-edit hook

every file the agent writes gets reformatted immediately by the same formatter
my editor runs on save

so claude and I never have to fight over whitespace

it's a `PostToolUse` hook —
[`bin/claude-format`](https://github.com/benswift/.dotfiles/blob/main/bin/claude-format)
in my dotfiles

---

## what should it do next?

_on screen: the check, then the page_

(half a minute with the person next to you, then call it out — one of them gets
typed in and run)

---

# Predict, then watch

---

## predict, before we read it back

the site colour-codes five departments; the brand rule allows three colours

where does that information go?

(chat with the person next to you)

---

## what should it do next?

_on screen: the page you predicted_

(half a minute with the person next to you, then call it out — one of them gets
typed in and run)

---

## C3: the assignment 1 retro

no fresh provocation this week — the crit reflects on A1, due **noon, Monday 17
August** (for everyone)

you present it in your pod crit

discuss the breakthrough (a prompt idea, a harness change, etc.) and show the
before and after: what the agent was doing, what changed it, why it worked

---

## `PROCESS.md` contents

one paragraph on what you built, then the moments that mattered (**three or
four** of them, 400–600 words)

what you did _instead of_ the obvious thing, and how you knew it helped

each cites a commit link (can be a deletion)

the strongest moments were changes to the **harness** (a rule, a check, an
attempt thrown away) rather than a retry

---

## your Claude budget is **$200** this week

up from $100, for the run-up to Monday's assignment 1 deadline

it went live before this morning's reset and carries the whole week; back to
$100 at the **Thursday 20 August** reset

(announced on Ed; your status line shows the figure live)

---

## the comp4020 plugin will install **Astro**

update the plugin, then use the `/stack` skill

Astro, the Pages base path, the lockfile, the CI link check — and hands it back
as one staged diff to review

it's a default, not a requirement (spec doesn't require any specific stack)

---

## your C4 starter repo is **much thinner**

the `CLAUDE.md` we ship dropped from \~1700 words to \~200 — the checks are named,
not explained, and no stack or harness decisions are made for you

(from Monday's C4 repos on; your A1 repo keeps the file it was provisioned with)

---

## deadline radar

`/comp4020:radar` reads every cutoff and deadline off the course site, so it
can't go stale

let's run it

---

## tl;dr

code generation is cheap; building the thing that pushes back is most of the
work

a sensor is worth adding if it's specific, fast, automatic and trustworthy

`pnpm check` is five commands joined by `&&`; a git hook makes running it a rule

a build step costs a dependency tree and buys DRY-ness; recovery is cheap

---

# See you in the studio

---

## ask your agent

ask until you can explain these back:

- **guides and sensors**: which files in my repo steer you, and which ones push
  back
- **`pnpm check`**: what does each part of it run, and what does none of it
  catch
- **the dev server**: what can pass tests at `localhost` and still fail once
  built

Source: <https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/lectures/week-3/>\
Licence: [CC-BY-NC-SA-4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)\
Cite as: Swift, B. (2026). _COMP4020/COMP8020 Agentic Coding Studio_ [Course materials]. ANU School of Computing. https://doi.org/10.5281/zenodo.21395760
