Agent Engineering
Module 06 · Shipping/Lesson 6.1/3 min

The spec

The artifact that carries intent across many sessions without carrying any session’s baggage.

Once work exceeds one session, something has to survive the gap. That something is a spec: a handoff artifact describing the objective of a multi-session piece of work, deliberately free of session-specific detail.

A spec is not documentation and not a plan. It is the shared, stable answer to "what are we building and how will we know it is right", written so that a fresh agent with no history can pick it up.

The shape

specs/scheduled-exports.md
# Scheduled CSV exports

## Goal
Let account admins schedule a recurring CSV export of their orders,
delivered by email. Replaces the manual export they run every Monday.

## Not in scope
- Formats other than CSV
- Per-user (non-admin) schedules
- Changing the existing on-demand export

## Constraints
- Must reuse src/export/csv.ts. Do not write a second CSV writer.
- Exports can be large: stream, never buffer a whole result set.
- Scheduling uses the existing queue (src/queue/), not a new mechanism.
- Timezone is the account's, stored in accounts.timezone. UTC at rest.

## Decisions already made
- Schedules stored in a new table, not as a JSON column on accounts.
  (Rejected JSON: we need to query due schedules efficiently.)
- Daily/weekly/monthly only. No cron expressions.

## Acceptance
- An admin can create, edit, and delete a schedule in the UI.
- A due schedule produces an email with a correct CSV attached.
- A failed export retries 3 times, then notifies the admin.
- Deleting an account removes its schedules.
- npm run check passes; new code has tests.

## Open questions
- What is the size limit before we link instead of attaching? (ask Dana)

What makes it work

  • Not in scope does more than the goal section. It is where you spend the agent’s helpfulness in advance.
  • Decisions already made, with the rejected alternative. Without the reason, a later session re-opens the decision and argues for the option you already rejected — usually persuasively.
  • Acceptance as observable statements. Each line is something you could check. "Good UX" is not.
  • Open questions kept visible, so they do not get silently answered by whichever session hits them first.

Write it by grilling

Do not compose a spec cold. Grill (Lesson 4.2), then have the agent draft the spec from the interview, then edit it yourself. The editing pass matters: you are the one who knows which constraints are real.

prompt
Draft a spec from our interview using this structure: Goal, Not in scope,
Constraints, Decisions already made (with rejected alternatives and why),
Acceptance criteria as checkable statements, Open questions.

Only include things I actually said. Put anything you are inferring under
Open questions instead of asserting it.

That last instruction is the whole difference between a spec and a hallucinated one.

Watch out

A spec that specifies implementation is too detailed and will fight reality by session three. Constrain the boundaries — interfaces, invariants, what to reuse, what not to touch — and leave the inside to the implementation sessions.

Try it

Write a spec for the big task from Lesson 1.4, using the grill-then-draft-then-edit flow. Then hand it cold to a fresh agent and ask: "What would you need to ask me before starting?" Every question it raises is a hole in the spec.

Takeaways

  • A spec carries intent across sessions and contains no session-specific detail.
  • Record rejected alternatives with reasons, or they get re-litigated.
  • Acceptance criteria must be checkable statements.
  • Draft from a grilling interview; anything inferred goes under open questions.
Why does a spec need a "not in scope" section when it already has a goal?

Because agents are helpful by default and will build adjacent things that seem obviously useful. The goal says what to build; only the exclusions stop the work from expanding into things you deliberately decided against. It is the cheapest scope control in a multi-session project.

A course by Pieter Zandbergen