Writing specs for AI agents
CRMTHREE was built by AI agents working from a written specification. Not "AI-assisted" in the autocomplete sense - agents implemented whole features from the spec while I reviewed, tested, and corrected. That experience taught me what a specification actually needs when the reader is not a colleague who can walk over and ask. Five lessons.
1. Acceptance criteria, not descriptions
Prose describes; criteria decide. The difference shows the moment an agent has to make a call. From the CRMTHREE spec, lead conversion does not say "leads can be converted". It says: the dialog pre-fills these fields from these sources, on conversion these three records are created, the status is set to Converted, these reference fields are populated, the user is navigated to the opportunity - or the contact if there is none - and the lead's owner is inherited by every created record. An agent reading that has no room to improvise, which is exactly the point. Every ambiguity you leave in a spec becomes a decision made by whoever - or whatever - reads it.
Here is what that looks like in the raw spec:
### 3. Lead Management As a user, I want to capture and qualify leads so that I can identify new sales opportunities. **Acceptance Criteria:** - Leads can be scored (manually via score field 0-100) and qualified (status transitions: New → Contacted → Qualified/Unqualified → Converted) - A lead can be converted into a contact, account, and/or opportunity via a "Convert Lead" dialog accessible from the lead detail page header. The dialog pre-fills: Contact (first_name, last_name, email, phone, mobile, position), Account (company → name1), and optionally an Opportunity (user enters name). On conversion: records are created, lead status is set to "Converted", conversion fields are populated (converted_contact_id, converted_account_id, converted_opportunity_id, converted_at), and the user is navigated to the new opportunity (or contact if no opportunity). The lead's owner_id is inherited by all created records.
Verbatim from specs/specifications.md - markdown a human can review and an agent can execute.
2. Make the data model machine-readable
The single highest-leverage artifact in the repository is data-model.json: every object, field, type, enum, and relationship in one structured file. Agents can load it whole and generate forms, list views, validation, and services from it without guessing a single field name. The prose spec references it instead of repeating it, so there is exactly one source of truth. If you write only one thing for agents, write this.
3. Write down the UX, not just the features
Agents produce UIs quickly - each one a fresh interpretation. Without a UX spec, screen two will not match screen one. CRMTHREE's UX spec defines the patterns once: what a list page is, what a detail page is, where quick actions live, how linked records appear, parents before children. After that, "build the invoice pages" means the pattern applied to invoices - consistency by construction rather than by review.
4. State the constraints that code cannot show
Some of the most important sentences in the architecture spec look boring: API keys never reach the browser, every external call goes through the server-side proxy, no Firebase project identifier is hardcoded in source. A human absorbs such rules from the codebase's vibe. An agent needs them stated, because it will otherwise cheerfully produce the convenient version. Constraints are the part of the design most worth writing down.
5. Specs before code, as a rule the agent knows
The repository's instruction file for agents opens with the project's one hard rule:
ALWAYS update the spec BEFORE changing any implementation - features, modifications, behavior-changing fixes. No exceptions.
This is what keeps the whole model honest over time. The spec stays the product, the code stays the proof, and any drift between them is by definition a bug - findable, because both are written down.
The result of all five is a repository where "anyone can build it" is not a slogan. The spec was precise enough for agents to build the reference implementation - which means it is precise enough for yours.
← All posts