Skip to main content
This walks through building a small support-desk environment from blank. Every command and every output below is from an actual session — you can follow along and get the same results. The order matters. Each step depends on the one before it, and doing them out of sequence means editing generated files by hand.

1. Scaffold

Blank gives you the contract wired up and nothing in it:

2. Add data

Facts only — no computed values.
tickets.json
agents.json
Notice the shape of this seed: two tickets are unassigned, and only one of the two agents is available. That is deliberate — it gives a task a correct answer and a wrong-but-plausible one.

3. Write state.ts before anything else

This is the step people skip, and it costs the most. Scaffolded tools and verifiers import State and are generated against it, so writing state first means the stubs come out correct.
state.ts
Two things worth copying: now is in state because the domain has a clock, and isUnassigned is a helper because both a tool and a verifier will need that definition.

4. Build the world

environment.ts
structuredClone is not optional. Node caches imported JSON for the process lifetime, so without it the second rollout starts from whatever the first one left behind — which presents as flaky grading, not an obvious bug.

5. Scaffold the tools

Three tools for two collections is the minimum here: the agent must be able to see the queue, see who can take work, and act. Anything it cannot see through a tool, it cannot know.

6. Implement them

The generated stub throws on purpose. Replace the TODO:
tools/assign-ticket.ts
The business rules live in the tool. Because assign_ticket refuses an unavailable agent, “assign these to someone who can take them” becomes a real task rather than a formality.

7. Add a task

The instruction states the outcome and nothing else. It does not name the tools, say how many tickets there are, or mention that one agent is unavailable — discovering that is the work.

8. Scaffold and write the verifier

verifiers/VER-001.ts
The set of tickets that needed an owner is derived from initial, not listed here. Add another unassigned ticket to the seed data and this check strengthens automatically.

9. Validate — this is the stopping condition

Do not skip to running. Validation compiles the whole environment, including the tools this task never calls. A run proves one path works; validation proves the environment is sound. The counts are a second check: three tools means all three registered. If you wrote a tool and the number did not move, it is not in the barrel.

10. Run it

helpdesk.agent.ts

11. Prove the verifier can fail

A gate that cannot fail is worse than no gate. Point a different agent at the same task — one that does not do the work:
Now you know the check discriminates. Run this once for every verifier you write.

What to do next

  • Add a second task that produces an answer rather than a change — “how many tickets have been open more than 30 days?” — and derive the expected figure in the verifier using daysOpen.
  • Add the awkward rows: a ticket assigned to an agent who has since become unavailable.
  • Record a passing run’s result.json as a baseline, so a change in behaviour shows up as a diff.