tropo

Rung 09 · The Agentic Builder Series

In Tropo: Your First Receipt


You read why verification is the harder half — that "it works" from an agent is worth what you paid for it, and the only proof is evidence you produced with your own hands. Here you build the tool that makes you produce it: a reusable receipt you fill with what you saw, not what the agent claimed. You'll take a real intake tool, write one success criterion you can perform, run the receipt against the build, and end holding a review you can trust — and a template you'll re-run on every job after. About twenty minutes.

You already do this. When a report says "it's handled," you ask to see the signed contract. The receipt is that instinct, written down once so it compounds.


Part 1 — The Spec Files

This rung has a build to verify, so it comes with a spec — plus the two small files that spec leans on. You didn't write them; you're borrowing a good build so the whole rung can be about checking it, not authoring it. Read the spec. Notice the line that will do the heavy lifting: every attempt — accepted or refused — is written to the log. That's the difference between a tool that reassures you and one that testifies about itself.

Which folder does this go in? The one your agent is already working in. If you're not sure which that is, just ask it: "What folder are you working in right now?" — and use the folder it names. (Many agents show it at the top of the window.) Everything in this walkthrough lives in that one folder, in a subfolder called intake/.

Getting the files in place — the easy way. Don't hand-craft .md files (on a Mac, TextEdit fights you — it likes .rtf and hides extensions). Let the agent do it. Paste the block below into your agent and say:

Make a subfolder called intake/ in the folder you're working in, and
save the two files below into it exactly as-is — intake.spec.md and
rules.md. Just save them; don't build anything yet.

--- FILE: intake/intake.spec.md ---
<paste the spec below>

--- FILE: intake/rules.md ---
<paste the rules below>

That's it — both files are now real, spelled correctly, no extension surprises. (If you'd rather make the files yourself and you're comfortable doing it, go ahead — the result is the same. Governing these files comes later, in Part 3; today they're just files the agent reads.)

Here's the spec to paste:

# intake.spec.md — Client Intake Tool

*Lineage: this is the grown-up, machine-written version of the personal outreach-tracker
you built in Rung 1. Its whole job: receive other people's submissions, refuse the bad
ones out loud, and file the good ones into a record you can trust.*

## Intent

A single self-contained HTML page that lets someone submit a client lead (name, email,
phone, note). The tool validates the submission against `rules.md`, **refuses** anything
that fails a rule with a visible reason, and **files** anything that passes as a line in
`submissions.log`. Every attempt — accepted or refused — is written to the log so the
record shows what actually happened, not just the happy path.

## What "done" means

- [ ] Opens as one file in a browser, no server, no build step, light theme.
- [ ] Four fields: Name, Email, Phone, Note. Name + Email + Phone are required.
- [ ] Validation rules live in `rules.md` and are enforced by the tool:
 - Email must contain `@` and a `.` after it.
 - Phone must be exactly 10 digits after stripping spaces, dashes, parens.
 - Name must be non-empty.
- [ ] A **bad** submission is REFUSED: it is NOT filed as accepted; the reason is shown
 on screen AND a `REFUSED` line is written to `submissions.log`.
- [ ] A **good** submission is ACCEPTED: an `ACCEPTED` line is written to
 `submissions.log` with a timestamp.
- [ ] `submissions.log` is visible in the page (a live pane) and can be copied out, so
 the record is inspectable without dev tools.
- [ ] The current ruleset version is shown in the footer so a reviewer knows which rules
 were in force.

## One worked example

A reader types phone `555-12` (only 5 digits) with a valid name and email and clicks
Submit. The tool does NOT file it as a lead. Instead it shows:
`REFUSED — Phone must be 10 digits (got 5).` and appends to the log pane:
`2026-07-04T14:22:03Z REFUSED phone=555-12 reason=phone-10-digits`
The reader then fixes it to `555-123-4567` and resubmits; the log shows:
`2026-07-04T14:22:40Z ACCEPTED Ada Lovelace ada@example.com 5551234567`

## Non-goals

- No backend, database, or network calls — the log lives in the page session.
- No auth, no de-duplication, no editing of filed rows (append-only record).
- No styling beyond a clean, readable light theme.
- No handling of international phone formats — 10-digit US only, by rule, this rung.

And here's rules.md — the small file the spec points at. It matters for one reason you'll use in Part 3: the footer of the built tool must name this version, so a reviewer knows which rules were in force:

# rules.md — Intake validation rules (v1.2)

These are the rules the intake tool enforces. The tool reads this file's spirit;
the version string below is shown in the tool footer so a reviewer knows which rules
were in force when a submission was filed.

1. **name-required** — Name must not be empty.
2. **email-shape** — Email must contain `@` and a `.` somewhere after the `@`.
3. **phone-10-digits** — Phone, after stripping spaces, dashes, and parentheses,
 must be exactly 10 digits.

Any submission failing a rule is REFUSED with the rule id shown, and the attempt is
logged as REFUSED. Passing submissions are logged as ACCEPTED.

_ruleset version: v1.2 — history in versions/_

Two files, one job each: the spec says what "done" means and fences off what to leave out; the rules file is the thing the tool must obey and name. You already write acceptance criteria — you just call them something else. Notice the reason id in the worked example: phone-10-digits. That exact string is what you'll go looking for in the log. Hold onto it.


Part 2 — The Build Walkthrough

Three turns. Each is a prompt you paste and a look at what comes back. These prompts produced the intake tool in this walkthrough — they work as written.

A note on what you'll see: the conversation is text — copy the prompts straight out. The tool itself is the one thing you'll see as an image, because verifying it is the whole point of the rung and you have to look at it. And one honest caveat: your agent's exact wording will differ every time — these reply blocks are roughly what you'll see, not a transcript to match. What matters is that a file named intake.html appears in your intake/ folder and opens. Tropo runs the same way across tools; the words matter, the chrome doesn't.

Step 1 — Hand the spec to your agent

The spec and rules are saved in intake/. Now direct the work. You're not writing the tool; you're handing off a clear ask and letting something capable run.

Paste this:

In the intake/ folder there's intake.spec.md and rules.md. Read both
and build exactly what the spec describes — a single self-contained
intake.html I can double-click. It must enforce the rules from
rules.md, refuse bad submissions with a visible reason, file good
ones, and log EVERY attempt (accepted or refused) to an on-page log
pane. Show the ruleset version in the footer. Don't ask me questions,
just build it to the spec.

Roughly what comes back:

Read intake.spec.md and rules.md. Built intake/intake.html — one
self-contained file, no server, nothing to install.

It has the four fields (Name, Email, Phone required; Note optional) and
enforces all three rules from rules.md:
 · name-required
 · email-shape
 · phone-10-digits

A bad submission turns the verdict box red with the reason and writes a
REFUSED line; a good one turns it green and writes an ACCEPTED line.
Every attempt lands in the on-page submissions.log pane, and there's a
"Copy log" button. The footer reads "Rules in force: rules.md v1.2".

Open it with: open intake/intake.html

Now open it. Find intake.html in your intake/ folder and double-click it — it opens in your browser. That's the whole move. (If you're comfortable in a terminal, the agent's open intake/intake.html does the same thing — but you never need the terminal for this.)

[screenshot: the intake tool, empty and waiting] A clean light card on a bone-grey page. Title "Client Intake," a sub-line: "Submit a lead. Bad ones are refused out loud; good ones are filed to the record." Four fields — Name, Email, Phone (placeholder "10 digits, e.g. 555-123-4567"), Note — with a blue Submit button. Below, a second card labelled submissions.log with a dark log pane reading "— no submissions yet —" and a "Copy log" button. A footer: "Rules in force: rules.md v1.2 · append-only record · one file, no server."

You made that happen. You wrote nothing but a hand-off. But an empty tool that looks finished tells you nothing — the whole rung is what you do next.

Step 2 — Write the one success criterion, then build the receipt

This is the move the essay turns on: before you check anything, write down the one thing you can do and watch. Not "the tool validates phone numbers" — that's a claim. Yes: "I can submit a bad phone number and watch it be refused, and the refusal is in the log." That's a criterion you can perform.

You'll capture it in a reusable receipt, so the discipline compounds instead of evaporating. Have the agent lay down the template. Paste this:

Create a reusable verification receipt template at
intake/receipt.template.md. It should be a file I copy next to any
build to sign it off by hand. Structure:
- a one-line performable success criterion (a thing I DO and WATCH)
- a four-cell table: (1) What was asked, (2) What I can now do myself,
 (3) What the record shows, (4) What's not done yet
- a "perform-it list" of concrete do-this-now checks, left blank for me
 to fill per build
- a verbatim rejection prompt to paste back to you if a check fails
- a sign-off block
Give the file a uid in its YAML frontmatter (generate one) so my
studio can track it. Fill nothing in — leave it blank for me to reuse.

Roughly what comes back:

Created intake/receipt.template.md — a blank, reusable four-cell
receipt. I added YAML frontmatter with a generated uid (uid: <uid>),
type: template, so your studio can track it, plus the performable-
criterion line, the four cells, a blank perform-it list, the verbatim
rejection prompt, and a sign-off block. Copy it next to any build and
rename it receipt-<thing>-<date>.md to run a review.

Notice one honest thing about that uid: the agent generates it fresh — it's random, not a number you'll recognize. You'll never see the same one twice, and you never type it yourself. That's how governed files get their handle: a uid in the frontmatter, which your studio then tracks by. We'll come back to what "tracks" actually means in Part 3.

Now you have a blank receipt. Time to fill it against the real build — which is Part 3, and it's the half that proves the tool is correct, not just finished-looking.

Step 3 — Govern the template so it survives

A receipt you use once and lose is ceremony. The point of a template is that it comes back every rung. So let your studio track it. Paste this:

The receipt template has a uid now. Have my studio pick it up so it's
tracked as a governed file — run whatever index/rebuild step my studio
uses so receipt.template.md shows up as a tracked file, not a loose one.
Confirm it's tracked and tell me its uid.

Roughly what comes back:

Done. Ran your studio's rebuild — receipt.template.md is now picked up
in the studio index and tracked by its uid (uid: <uid>). It's a
governed template now: it persists and you can copy it beside any
build to run a receipt. The build under review (intake.html) and the
log stay ordinary working files — a governed template, not a governed
tool.

Here's the true and light version of what just happened, because the difference matters: governing a file = giving it a uid and letting your studio track it. The studio's index picks it up on a rebuild. It is not a registry you hand-edit, and the rebuild is not automatic — you had to ask for it. One more honest line: the template is now tracked; intake.html and submissions.log are still just working files in your folder. A captured log is a record you can read — it is not a governed vault entry, and you should never call it one.


Part 3 — Perform the Receipt

Directing is half the job. This is the harder half — deciding whether what came back is right, not just whether it exists. "It looks finished" is not "it's correct," and the agent will tell you it works every single time. So don't read this as a table to admire. Perform it. You review other people's work constantly; you know the difference between glancing and actually checking.

First, copy the blank template into a receipt for this build. Paste this:

Copy intake/receipt.template.md to intake/receipt-intake-2026-07-04.md
so I have a working copy to fill in by hand. Don't fill any cells —
leave it blank. I'm doing the verification myself.

Now go to the tool and do these, in order, before you call it done. This is your perform-it list — do them, don't read them:

  1. Read the footer. It must say rules.md v1.2. If it names no ruleset, a reviewer can't know which rules were in force — that's a done-list item unmet.
  2. Submit a bad phone. Type Ada Lovelace / ada@example.com / 555-12 and click Submit. The verdict box must turn red and read "REFUSED — Phone must be 10 digits (got 5)." If it files the lead anyway, the tool is décor, not function — the spec says a bad submission is not filed.
  3. Read the log pane for the refusal. A REFUSED line must appear, and its reason must read reason=phone-10-digits — the rule id, exactly. If the refusal isn't in the log, the tool refused silently, and the spec's whole promise ("every attempt is written") is broken.
  4. Fix the phone and resubmit. Change it to 555-123-4567 and Submit again. The box must turn green — "ACCEPTED — filed to submissions.log." — and an ACCEPTED line with a timestamp must land in the pane.

[screenshot: the tool mid-verification, one refusal and one acceptance in the log] The verdict box glowing green — "ACCEPTED — filed to submissions.log." Below, the dark log pane now holds two lines you can read with your own eyes: 2026-07-04T23:26:48Z REFUSED phone=555-12 reason=phone-10-digits 2026-07-04T23:26:57Z ACCEPTED Ada Lovelace ada@example.com 5551234567

Now fill the receipt — with what you saw, not what you hoped. Here's the filled copy from this walkthrough, so you can see the shape of a real one:

Build under review: intake/intake.html Ruleset in force: rules.md v1.2 My criterion: I can submit a bad phone number and watch it be refused, and the refusal is in the log.

CellYour evidence (produced by hand)
1 — What was askedA one-file intake tool that takes Name/Email/Phone/Note, refuses bad submissions out loud with a reason, files good ones to submissions.log, and logs every attempt. Done = a bad phone is refused AND appears as a REFUSED line; a good one appears as an ACCEPTED line; ruleset version visible in the footer.
2 — What I can now do myselfI typed Ada Lovelace / ada@example.com / 555-12 and clicked Submit. The verdict box turned red: "REFUSED — Phone must be 10 digits (got 5)." Then I fixed the phone to 555-123-4567 and resubmitted; the box turned green: "ACCEPTED — filed to submissions.log." I watched both happen.
3 — What the record showsI read these two lines straight out of the on-page log pane (not from the agent): 2026-07-04T23:26:48Z REFUSED phone=555-12 reason=phone-10-digits and 2026-07-04T23:26:57Z ACCEPTED Ada Lovelace ada@example.com 5551234567. The refusal is in the record with its rule id. The criterion is met.
4 — What's not done yetNon-goals still open by design: no backend/persistence (the log is session-only and clears on refresh), no de-dup, no international phone formats, no editing filed rows. Nothing found broken this pass. Persistence is the honest gap a future rung would close.

If check 2 filed the bad lead anyway, or check 3's reason wasn't in the log, or the footer named no ruleset — you caught it, which is exactly the job. Send it back with the template's rejection prompt, unsoftened:

The build fails its own spec. Here is the check I performed and what I
saw: I submitted phone 555-12 with a valid name and email and it was
filed as ACCEPTED / no REFUSED line appeared in the log. The spec says
"A bad submission is REFUSED: it is NOT filed as accepted... AND a
REFUSED line is written to submissions.log," logged with
reason=phone-10-digits. Do not explain why it happened — fix the build
so the check passes, then tell me the exact steps to re-perform the
check myself. I will re-run the receipt against your fix.

Directing includes rejecting. That's not the loop failing; that's the loop working.

A note on the agent's own record. If you asked the agent to keep a decisions.log while it built (a good habit from rung 7), it's evidence too — but read it with the same eyes. A decisions.log and a submissions.log are records you can inspect, not governed vault entries. The receipt template is the governed thing here; the logs are the evidence it points at.


Part 4 — What You Now Have in Your Studio

You started with a tool that claimed to work. You end with proof it does — proof you produced, that you could hand to someone else.

In your intake/ folder, right now:

  • A verified toolintake.html, a real intake screen that refuses bad leads out loud and files good ones. Not a demo. But more than that: a tool you checked, so "done" means done.
  • A completed receiptreceipt-intake-2026-07-04.md, four cells filled with what you saw with your own hands: the red REFUSED, the green ACCEPTED, the two log lines you read yourself. That's a review, not a rubber stamp.
  • A reusable template you now governreceipt.template.md, tracked by its uid in your studio's index. Copy it beside any build, fill the cells with evidence, run the review. You'll re-run it on every rung after this. That's the compounding: judgment turned into something you keep.

It's doable. It's not automatic — the agent won't verify itself, you had to write the criterion, click the button, and read the log with your own eyes, and you had to ask for the rebuild before the template was tracked. But you did all of it, and now you can tell "it works" from "it's true."

The Power Play — set a fresh agent against your build. Don't verify with the agent that built it; it's the last one who'll tell you it's wrong. Open a fresh agent that never saw the work, point it at the two files this companion created, and set it against you:

Here is a spec (intake/intake.spec.md) and here is what was built from
it (intake/intake.html). Your job is to prove the build does NOT meet
the spec. Find every requirement it misses, every case where it does
something other than what was asked — especially: does it log EVERY
attempt, is a bad phone actually refused and NOT filed, does the footer
name the ruleset? Assume it's flawed and show me where.

An agent told to find fault will find it. What survives that — what the skeptic can't knock down — is the part you can actually trust.

That's the whole rung. The agent builds; you decide it's done — and that call, the harder half, is the one that doesn't delegate, because you're the one accountable for what ships under your name. You didn't just take its word. You made it show you. Next rung, you'll practice ending a session on purpose and watching a fresh one resume from files alone. For now — you asked for the proof, and you held it in your hand.