# Backpressure

> Most of harness engineering is giving good negative feedback: the model generates, and the harness rejects what's wrong, fast and automatically

A coding agent will generate for as long as you let it. Generation is the cheap
part: the model supplies as much plausible-looking code as you can pay for.
What's scarce is automatic rejection. **Backpressure** is the set of checks that
reject bad output, and configuring it is most of harness engineering.

That observation comes from Simon Willison, who states it as a principle of its
own: _writing code is cheap now_. Generating code is no longer the expensive
part, so practices designed around scarce generation need revision.

"Negative feedback" is meant here in its control-theory sense: the
error-correcting loop that stabilises a system, which is cybernetics in its
original meaning (steering). It's also meant in the everyday sense, the critique
you give and receive at the crit. A good failing test and a good crit comment
must both be specific, early, and aimed at the artefact rather than the author.

## Guides and sensors

The corrective signal runs through two kinds of channel (vocabulary borrowed in
part from
[Learn Harness Engineering](https://walkinglabs.github.io/learn-harness-engineering/en/);
Birgitta Böckeler splits it the same way):

- **Guides** constrain the agent _before_ it generates: the CLAUDE.md in your
  repo, a skill it consults, the published spec and the plan you agreed.
  Feedforward --- they constrain what gets produced.
- **Sensors** measure what it produced _after_: exit codes, lint output, type
  errors, test results, the rendered page. Feedback --- they reject what's
  wrong.

This topic is mostly about sensors; the big guides get their own treatment
(CLAUDE.md in week 2, skills in week 4). Use each sensor to answer one question:
**does the artefact meet the requirement?** Testing and linting are the everyday
instances, but any automatic comparison between the artefact and its
requirements can provide this feedback. A useful sensor is:

- **specific** --- a file, a line, an expected-versus-actual. "Something's off"
  is not a signal the agent can act on.
- **fast** --- the correction appears in the same loop turn as the mistake,
  while the agent still has the context that produced it. Shortening the loop
  does the same work from the other end, which is what a dev server that
  rebuilds on save buys you.
- **automatic** --- it fires on every change without anyone remembering to run
  it.
- **trustworthy** --- a flaky sensor is worse than none, because a red check
  that's sometimes wrong leads you and the agent to ignore red checks.

Once configured, sensors can run on every change at negligible marginal cost.
Your attention is the scarcest resource in the loop, so automating a correction
saves you from repeating the same check.

## Four sensors worth wiring in

The rest of this page covers four concrete sensors, from code checks to the
rendered page itself.

### Linting and types

Lint output gives an agent a machine-readable correction: a rule name and a
location. The agent can act on that output in the next turn without further
instruction or interrupting a human.

Type checkers catch errors with greater consequences. Agents often generate
_plausible_ code that reads correctly but is wrong; a type checker converts many
of those errors into diagnostics with exact locations before anything runs.
Agentic practice has therefore strengthened the case for types and strict lint
configs: every enabled rule automates another correction.

### The sharpest sensor is a failing test

Lint and types reject malformed code. A test can also reject code whose
behaviour differs from the expected result. A failing test is backpressure you
author yourself: it encodes your intent as a check the harness can run and gives
the agent a specific failure to fix.

The resulting habit is short enough to keep: **only push on green**. This
section does not require the full test-driven ceremony. Red-green-refactor is a
fine discipline, but here we are concentrating on the feedback channel. Write a
test when you know something the code should do, and keep the suite green as the
gate on every push.

### stylelint: grounding for CSS

Agents produce particularly unreliable CSS. The cascade has no type checker, a
selector that matches nothing raises no exception, and the model's training data
contains plenty of copied rules with conflicting declarations. An agent can
therefore produce plausible CSS while few automated checks detect the visual
failure. [stylelint](https://stylelint.io) reports invalid values, duplicate or
conflicting declarations, and selectors that cannot match. It cannot judge the
design, but it prevents invalid and contradictory CSS from accumulating.

### agent-browser: the rendered page as ground truth

Everything above checks the code. None of it shows the agent what the page
_looks like_. Without rendered output, an agent may report that the layout is
fixed because the CSS it wrote appears correct. Vercel's
[agent-browser](https://github.com/vercel-labs/agent-browser) CLI closes that
loop: the agent drives a real browser, takes screenshots, reads the
accessibility tree and the console errors, and compares what actually rendered
against what it believes it built. A contradictory screenshot provides evidence
that the claim was wrong.

Used defensively like that, it is a sensor. Used deliberately --- driving the
artefact the way a user would, to find what nothing else reaches --- it is a
named practice called
[agentic manual testing](https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/topics/evaluating-agent-output/#agentic-manual-testing),
which is week 5's business.

On Ubuntu 23.10 and later the browser won't start under the defaults: AppArmor
restricts the unprivileged user namespaces Chrome's sandbox needs, and the run
exits with `No usable sandbox!` before any page loads. Pass
`--args "--no-sandbox"` on whichever command launches the browser:

```sh
agent-browser --args "--no-sandbox" open http://localhost:4321/
```

That turns off Chrome's own process isolation, which is a fair trade for a
browser pointed at your own dev server --- just don't reuse that session for
general web browsing.

## The roster, wired into CI

Your starter repo runs these sensors through one `pnpm check`: the type checker,
oxlint, stylelint, the build, and a test suite that includes the invariant
checks. The crit 7 starter adds
[axe-core](https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/topics/modern-web-best-practices/#specialised-sensors) to those
invariants, an accessibility floor run in jsdom; the final project's template
ships only two checks, that the app answers and that `/readme/` publishes your
README, and leaves the rest of the roster to you. While your repo is private
they run locally via the starter's scripts (the faster loop anyway); from the
moment it goes public at your cutoff, CI runs them on every push. The repo's
CLAUDE.md describes each check and how to interpret a failure. Two habits
complete the loop:

- **read the checks back.** A failed CI check reports a specific problem. Give
  that output to the agent so it can act on the same information.
- **remember what green means.** Passing checks cover only the machine-checkable
  requirements, not the work's overall quality.

The [task list](https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/topics/task-tracking/) is another sensor: an external record
for checking the agent's completion reports.

## When no sensor catches it

Some changes are wrong in ways no sensor catches until too late, and then the
question is which correction to reach for. That judgement is mostly about how
early you are. A wrong direction caught mid-response is cheapest to interrupt; a
few turns later you may need to rewind the conversation; once the change has
reached the repository, use `git revert`. The
[cheatsheet](https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/topics/claude-code-cheatsheet/#interrupt-rewind-or-revert) has the
mechanics, including an important boundary: Claude Code's checkpoints cover the
conversation and its own edits. Use git history after any other tool has changed
your files.

All of that depends on knowing what happened rather than what the agent said
happened. Use the diff, check output and rendered page to verify any claim of
"done". Because `git revert` is cheap, you can let the agent work in bounded
stretches without watching every turn.

## One signal, three channels

This page concentrates on the **automated** channel: corrections that run
without anyone in the loop. **You** provide another channel by reading the diff,
asking the agent to explain itself and checking the task list. Your **peers**
provide a third at the weekly crit. At the crit you practise giving specific
feedback; during the rest of the week you automate as much of it as possible.

Source: <https://comp.anu.edu.au/courses/comp4020-agentic-coding-studio/topics/backpressure/>\
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
