Every few months the AI world ships a new noun with “Engineering” stapled to it. Prompt Engineering. Context Engineering. Harness Engineering. Since June the feed has decided the skill that matters is Loop Engineering, and my default reaction to a new one of these is somewhere between an eye-roll and a browser tab I’ll never read.
This one I decided to test instead of dismiss. In mid-July I got a good excuse: a small, well-bounded Salesforce ticket — one new action on a payment record, one middleware call, clear acceptance criteria. About the right size to run the way the Loop Engineering posts say to run things: design the loop up front, stay out of the loop body, and see what survives contact with a real org. So this post does two things. First, what Loop Engineering actually says, minus the vapor. Second, how the experiment went — including the parts where the loop failed, because those turned out to be the point.
What the term actually says
The lineage is short. On June 7, Peter Steinberger — the developer behind OpenClaw — posted: “You shouldn’t be prompting coding agents anymore. You should be designing loops that prompt your agents.” The same day, Addy Osmani published a post titled “Loop Engineering” that gave the idea its shape (O’Reilly republished it two weeks later). Osmani quotes Boris Cherny, who leads Claude Code at Anthropic: “I don’t prompt Claude anymore. I have loops running that prompt Claude.” To be clear about sourcing: these are industry posts, not official vendor docs — I’ll come back to what the official docs do and don’t say.
Strip the branding and the idea is one sentence: stop being the loop body. An agent acts, observes feedback, decides the next move, and repeats until a termination condition is met. If you’re the one reading every output and typing every next instruction, you are that loop’s body. Loop Engineering is designing the machinery so you don’t have to be:
- An oracle — a deterministic check that decides “done”, so the loop grades itself against reality instead of against its own vibes.
- Stop conditions — success, attempt caps, budgets. A loop that can’t stop isn’t autonomous, it’s a bill.
- State that survives iterations — notes, commits, test files. The model forgets; the repo doesn’t.
- Gates — named points where a human must re-enter before anything irreversible happens.
And the distinction from the previous buzzwords, since the whole genre invites confusion: prompt engineering is the wording of a single turn. Harness engineering is the environment an agent acts in — tools, skills, permissions. Loop engineering sits above the harness: the runtime that drives the agent through that environment again and again. Each layer wraps the previous one; none of them replaced it.
Worth keeping the skeptics in frame too. The Register covered the term with visible fatigue a couple of weeks after it appeared, and Ed Zitron’s critique — that agent loops mostly benefit whoever sells the tokens — is not wrong as a warning. A loop is a machine for spending compute without you watching. That’s exactly why the boring parts below matter.
The ticket
The feature: when a booking is cancelled, guest services could only refund a payment transaction back to the original tender. The ticket added a second option — issue the amount as a gift card instead. In Salesforce terms: a new “Credit Gift Card” action on the Payment Transaction record, calling our middleware, which asks the gift-card provider to issue the card. I ran the build with a coding agent over two days.
The experiment lives or dies in the brief, before any code. (The full brief, masked, is in the appendix.) I wrote the loop down first. The oracle: Playwright end-to-end specs, run against a deployed org, are “the ORACLE for ‘done’” — the feature is done when the acceptance specs pass, not when the code looks right. The stop conditions: three failed attempts at the same failing spec → stop and report; an unresolvable spec contradiction → stop and ask. The gates: deploying to the shared UAT sandbox is a side effect on a live org, so it needs explicit sign-off.
The loop earned its keep before the first commit. Told to read the middleware’s actual code and not just its API docs, the agent found the two disagreeing in ways that changed the design: the docs promised failures would come back as 4xx errors, but the code returns HTTP 200 “Success” even when the provider declines. The only honest success signal is a response code buried in the body plus a non-blank order reference. Worse, the docs described a safe, idempotent retry; the code has none. Every call mints a fresh order reference, so a retry issues a second real gift card. And a third conflict was structural: the middleware creates the credit record itself, so the original Salesforce design would have written a duplicate record for every credit — the redesign made the middleware’s record the source of truth. Per the brief, the agent stopped, listed the conflicts, and proposed the redesign. I reviewed the plan and approved it — the first human decision since the brief.
Then the actual loop — deploy, run the oracle, read the failure, fix, repeat. A validation run caught an interface still returning a stale type. Org reality ate the test data next: a validation rule demanded a phone number on the test account, and a before-save flow kept backfilling the payer email. That flow made one negative test unreachable in a real org, so the test got dropped rather than faked. The acceptance spec was written before the deploy, so its first run failed RED on purpose. An oracle that has never failed proves nothing.
Two moments made the whole exercise worth a blog post.
First, the gate held against me. With the package validated, the agent moved to promote the deploy to UAT — and the harness’s permission gate blocked it, because my approval had covered the plan, not this specific deploy to a shared org. The agent’s response, verbatim from my notes: “I won’t work around that.” I typed the authorization explicitly and it proceeded. Friction, briefly — and exactly the property you want in a system that acts while you’re not watching.
Second, the loop caught itself lying. Early Playwright runs reported a pass — and the agent noticed the page snapshot was a login screen. The stored browser session was two months stale, and on a login page, every “button should be hidden” assertion passes trivially. It declared its own earlier greens false, rebuilt the session, and re-ran. That’s the difference between an oracle and a rubber stamp, and it’s also the strongest argument I have against letting a loop run with a check it can pass by accident.
The rest of the iterations were unglamorous in the way real work is: the CLI’s colored output corrupted JSON parsing under the test runner; parallel test workers raced each other deleting shared seed data; a combobox rendered slower than the assertion that clicked it. The last real failure produced the best fix — the seeded transactions kept losing their payer email to that before-save flow, and instead of hacking the seed, the agent noticed email wasn’t one of the ticket’s stated visibility conditions at all. The guard moved from button-visibility to issue-time, which is what the ticket actually specified. The oracle was defended; the code conformed to the spec, not to the test data.
Final state: 22 Apex tests passing, 21 components deployed, all 5 acceptance specs green against UAT — and no real gift card ever issued, because the live issuance path stayed behind an environment flag I never set. Three local commits, nothing pushed. Honest leftovers: seed records in the sandbox, and an expired credential the loop couldn’t fix — it worked around it by bootstrapping the browser session from my CLI login, and left me a note to reset the token. The decisions I made while the loop ran were three: approving the plan, authorizing the deploy, and reviewing the result.
The ingredients were already on the shelf
Here’s the twist I didn’t expect. While writing this post I went looking for where the canonical guidance defines Loop Engineering — and the name is nowhere. I checked ten of the standard prompt-engineering references, Anthropic’s official docs among them; the term appears in none of them. The concept is a different story. The parts are everywhere:
- The prompt engineering overview refuses to even start until you have “a clear definition of the success criteria” and “some ways to empirically test against those criteria”. That’s the oracle, demanded before the first prompt.
- The current best-practices doc describes the core cycle plainly — “generate a draft → have Claude review it against criteria → have Claude refine” — tells you to provide verification tools (it names Playwright), to keep tests in a structured file the model must not touch (“it is unacceptable to remove or edit tests”), and to make agents ask before “actions that are hard to reverse”. Oracle, protected tests, gates.
- The business-facing guidance says to “approach it like a scientist: test your prompts and iterate often”, and there’s an entire official course on production prompt evals.
And the concept scales well past tickets. Anthropic’s Institute has an essay on recursive self-improvement — AI helping build the next AI — that describes the same machinery, bigger: Claude running code and delegating hours of work to other agents, a separate Claude judging afterwards whether the AI or the human had suggested the better next step, and the prediction that humans “will stop writing code entirely, and shift to only reviewing it”. Nobody in that essay says Loop Engineering either. The loop is just how the work gets described once you look for it.
So my honest verdict on the buzzword: what’s new is who runs the iteration — and the name. The advice didn’t change; the loop body did. That’s not a dunk. Naming a practice is how it spreads — the name is why I bothered running the experiment at all. But you don’t need to learn a new discipline this quarter. You need to finally do the old one — success criteria, honest tests, explicit gates — because now there’s something that will execute it tirelessly, and it amplifies whatever rigor or sloppiness you wrote down.
What I’d steal from this
Five things that transfer to any dev team, none requiring new tools:
- Write the oracle before the feature, and watch it fail. A check that’s never been RED proves nothing. Mine failed on purpose pre-deploy — and still produced a false green later. If your oracle can pass on a login page, it isn’t an oracle yet.
- Write stop conditions down. Attempt caps, budgets, “contradiction → stop and ask”. The loop that can’t stop is the one Zitron is warning you about.
- Gate irreversibles by name. Approving a plan is not authorizing a deploy. Make the loop require the specific side effect to be named before it runs. Mine blocked me once; that block was the system working.
- Keep state outside the model. Checkpoint commits, a lessons file, seeded test data that self-cleans. Osmani’s phrasing is right: the model forgets, the repo doesn’t.
- Stay the engineer. The day after, I was staring at a record wondering why I couldn’t see the new button — the answer traced cleanly to a visibility rule, but I had to go understand it. Osmani calls the gap “comprehension debt”, and his caveat is the one to keep: “The loop changes the work, it does not delete you from it.”
And the price of admission, stated plainly: a loop was worth building here because there was a real org to contradict the docs and an end-to-end surface worth an oracle. For a one-off small fix, the loop is ceremony — type the three prompts yourself. Loops also eat tokens by design; the skeptics are right that somebody profits from that either way.
Next quarter there’ll be another noun with “Engineering” stapled to it. Whatever it’s called, I’d bet the load-bearing parts will still be these: success criteria you wrote down, a test that can actually fail, and a gate that won’t confuse approving a plan with authorizing a deploy.
Appendix — the brief that ran the loop
If you want to steal the structure, steal it from the source. This is the actual brief I gave the agent, with company names, systems, links, and paths masked and a couple of typos cleaned — otherwise as I ran it. Some bracketed placeholders ([path], [command], [sandbox]) were already in the original; the parts that carry the loop are “Sources of truth”, the ORACLE line, “Plan, then STOP”, “Boundaries”, and “Budgets & caps”.
# Build [feature: Payment Txn Options for Refund or Credit Gift Card] in Salesforce per [TICKET-123]
## Context & purpose
I'm a Salesforce developer at [COMPANY]. This task implements [TICKET-123] in
our Salesforce org and integrates it with the middleware API. The full
requirement lives in Jira and Confluence — those are the source of truth, not
my summary here.
## Sources of truth — read these BEFORE any code
- Jira [TICKET-123] acceptance criteria and scope. Build to the ticket, nothing
more. (Use the Atlassian tools to read it and its linked issues/subtasks.)
- Confluence: the detailed spec/design from the middleware team.
- The middleware API (built by another team): [Confluence link — middleware API
reference]. This is the system we integrate with. Treat its behavior as ground
truth — if its docs and its code disagree, trust the code and flag it. Do NOT
invent endpoints, fields, payloads, or auth behavior you can't confirm from
the code/docs.
If the ticket is ambiguous, or Jira/Confluence and the middleware API contradict
each other, STOP and list the conflicts for me — do not guess past a spec gap.
## The system
- Salesforce org: [UAT-SANDBOX — NOT production unless I say so].
Metadata via Salesforce CLI (`sf`); source at [local path]. Deploying to
[UAT-SANDBOX] is a side effect on a live org — treat that deploy as a
gated action (see Boundaries). Deploying to a scratch org / my own sandbox is
fine and expected.
- Code base:
- Salesforce repo: [path to Salesforce project]
- middleware repo: [path to middleware repo]
- YOU CAN ONLY make changes in the Salesforce repo; the middleware repo is
view only.
- Test harness: Playwright at [path], run with [command]. These UI-level e2e
tests run against a deployed org and are the ORACLE for "done": the feature is
done when the acceptance-criteria specs pass against a real org.
## How to work
1. Inspect first. Read the ticket, the Confluence doc, and the middleware API
code/docs; read the existing force-app metadata and current Playwright suite.
Ground everything in these sources — no generic Salesforce advice.
2. Baseline. Spin up a fresh scratch org (or [sandbox]), run the Playwright
suite, and record what passes/fails today before changing anything. If the
suite doesn't yet cover the ticket's acceptance criteria, writing those specs
is deliverable #1 — an honest oracle comes before the feature.
3. Plan, then STOP. Restate the acceptance criteria in your own words, list the
metadata you'll add/change and the middleware calls you'll make, and flag any
spec gaps or risks. Do not build until I confirm.
4. Build + self-test loop. Implement on a branch. Deploy to scratch/[sandbox] →
run the Playwright specs → read failures → fix → redeploy → rerun, iterating
until the acceptance-criteria specs pass. Measure against the baseline: keep
what passes, revert anything that breaks a previously-passing test. Delegate
independent pieces (separate specs, unrelated metadata) to subagents and keep
working while they run.
## Boundaries
- Do NOT deploy to [production / the shared sandbox] without asking; treat a push
to [auto-deploying branch, e.g. main] as a deploy. Scratch orgs, my sandbox,
and feature-branch commits: go freely.
- Middleware API: hit only [the sandbox/test endpoint]; read-only calls are fine,
but flag before any call that writes to their system or costs money.
- Don't touch org credentials or connected-app keys. [If needed: the ONLY
permitted secret is the middleware sandbox token from .env, for their test API
only — never print, log, or commit it.]
- Build only what [TICKET-123] specifies. Note other bugs/improvements for me;
don't fix them unasked.
- If I'm thinking out loud rather than requesting a change, give me your
assessment and stop.
## Budgets & caps
- Stop conditions: acceptance-criteria specs pass → report; OR 3 failed attempts
at the same failing spec → stop and report what you tried and your diagnosis;
OR an unresolvable spec gap / API contradiction → report.
- [If the middleware test API is metered: hard cap of N calls; keep a tally in
the memory file; stop and ask before exceeding.]
## Progress accuracy
Before reporting progress, audit each claim against a tool result from this
session (a real `sf` deploy output, an actual Playwright run). Report only work
you can point to evidence for; label anything unverified. If specs failed or a
step was skipped, say so plainly.
## Memory
Keep notes/lessons.md — one entry per non-obvious thing learned (a middleware
quirk, an `sf` deploy gotcha, a flaky selector) with a one-line summary of what
and why. Update, don't duplicate; delete what proves wrong. Read it at the
start of future runs.
## When you report back
One sentence first: is it built, and do the acceptance-criteria specs pass?
Then: which criteria are met (mapped to the ticket), before/after Playwright
results as evidence, any spec gaps or middleware issues hit, anything
unverified, and what's left. Skip the play-by-play.
Start with step 1 — read the ticket, the Confluence doc, and the middleware
API, then give me your restated plan.
Sources — the term (industry posts, not vendor docs): Steinberger’s June 7 post; Addy Osmani, “Loop Engineering” (June 7, republished by O’Reilly Radar); The Register’s skeptical take (June 24), which also carries Ed Zitron’s critique. The Cherny quote is as given in Osmani’s post. The ingredients (official docs): Anthropic’s prompt engineering overview, prompting best practices, prompt engineering for business performance, and the Anthropic courses repo. Also official, and loop-shaped without the name: the Anthropic Institute’s essay on recursive self-improvement, “When AI builds itself”. The case study is from my own working notes and session transcript, lightly anonymized: names, ticket numbers, and internal system names are changed; the technical sequence and results are as they happened.