Welcome

--:-- recording — let's go

Week 3

Backpressure

the model generates

the harness rejects

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

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; Learn Harness Engineering)

words; what do they even mean?

a failing check, fed back

One turn of the edit-check loop The agent's context window holds the guides (system prompt, CLAUDE.md, the spec and the plan) and your prompt. The model writes an edit to src/data/posts.ts in the repo. The checks run: typecheck fails, so build, lint and tests never run. The type error goes back into the context window as a tool result, so the next edit starts from the error. When every check passes, the change is committed. the context window guides system prompt, CLAUDE.md, the spec, the plan your prompt your repo edit src/data/posts.ts edit pnpm check ✗ typecheck – build (not run) – lint (not run) – tests (not run) TS2551: Property 'titel' does not exist on 'Post' tool result the next edit starts here all green: commit otherwise, round again

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

What pnpm check runs pnpm check runs typecheck, build, oxlint, stylelint and vitest run, joined by double ampersands. Each of the first four exits 0, so the next one runs; one test fails and vitest exits 1. pnpm check therefore exits 1, and that exit code is what your terminal, the agent's Bash tool, and a git hook or CI all read. "check": "pnpm typecheck && pnpm build && oxlint && stylelint && vitest run" typecheck tsc --noEmit ✓ exit 0 build vite build && ✓ exit 0 oxlint the JS/TS && ✓ exit 0 stylelint every .css && ✓ exit 0 vitest run every *.test.ts && ✗ exit 1 every page links home expected 3, got 2 pnpm check exits 1, read by your terminal the agent's Bash tool a git hook, or CI

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

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

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

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)

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

# 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 is the course default from C2; Eleventy and Jekyll 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/

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