Structure is the Prompt

By Charlin Joe · 18 July 202613 views

Structure is the Prompt

A senior engineer spends two hours writing a detailed prompt for an AI coding agent. The output is better than the first attempt — noticeably so. The function is cleaner, the variable names make more sense, a few edge cases are handled that weren't before. Then they compare it to the acceptance criteria and find three gaps. The visual weight of the "Continue as guest" button is wrong. The confirmation email is not triggered for guest orders placed through the mobile app. The admin panel query returns guest orders in a registered user's order history if the user's UID happens to match a field value that was null.

The prompt was good. The output was still wrong. The prompt could be made better — but no single prompt, however detailed, can eliminate this class of error. A prompt exists for one session. The constraints the AI needed were encoded in decisions made across multiple sessions, by multiple people, over the past three weeks. A prompt cannot contain what a prompt author does not know.

The thesis of this article is blunt: prompt engineering is the wrong tool for making AI generation reliable. Structured documents — scope records, requirements with acceptance criteria, Architectural Decision Records — are the right tool. The difference is not incremental.


Why this keeps happening

Prompt engineering solves a specific problem: getting the AI to interpret ambiguous instructions in the way the author intended. This is a real problem, and prompts that are precise and detailed are better than prompts that are vague. But solving the interpretation problem leaves the information problem untouched.

The information problem is that the AI cannot generate code that satisfies constraints it has never seen. A prompt written by one developer in one chat session contains that developer's understanding of the task at the moment of writing. It does not automatically contain:

  • The operational constraint that guest orders and registered orders must appear identically in the admin panel — decided by an operations lead in a meeting three weeks ago.
  • The GDPR constraint that guest email marketing requires explicit opt-in — identified by a legal review two weeks ago.
  • The architectural decision to use a unified orders collection with userId: null rather than a separate guest_orders collection — made and recorded in ADR-012 after the team rejected the separate collection approach because it would duplicate all order management logic.
  • The acceptance criterion that the "Continue as guest" option must be displayed at equal visual weight to "Sign in" — specified in REQ-CHECKOUT-00010 because the product team saw a competitor implementation where the guest option was a small link below the form and it underperformed.

None of these can be reliably captured in a prompt, because prompts are written by individuals who may not know all of these constraints, and they are not maintained as the constraints evolve. A prompt is not a living document. It is a snapshot of one person's understanding at one moment. The constraints that govern a production feature are not one-person, one-moment knowledge.

The failure this produces is specific. The AI generates from what the prompt provides, makes reasonable calls for everything the prompt leaves unspecified, and produces output that is coherent but non-conformant. The non-conformance is not detectable from the output alone — it requires comparison against the actual requirement. Without the requirement written down and accessible, the comparison does not happen.

There is a second failure mode: the prompt that tries to contain everything. Teams who understand the information problem sometimes respond by writing exhaustive prompts — multi-page documents that enumerate every constraint, every edge case, every decision. These prompts are hard to write, hard to maintain, and hard to update when constraints change. They also do not survive handovers: a new developer on the team cannot look at a prompt in a chat history and understand which parts of it are settled decisions versus working assumptions. Prompts are not structured for that kind of navigation.

The root cause in both cases is the same: a prompt is the wrong container for engineering decisions.


What most teams try

The first iteration is better prompts. More specific instructions, more examples, more explicit constraints. This reduces errors in the current session and is worth doing. But it does not solve the problem across sessions, across developers, or across the lifetime of a codebase that needs to be maintained after the initial generation sprint.

The second iteration is prompt libraries — saved prompts for common tasks, shared across the team. This is more durable but still not structured: a prompt library entry for "add a Firestore collection" does not know about ADR-012, does not know about the operations constraint, and does not know that the guestEmail field requires a specific index for the returns lookup.

The third iteration is in-context documents — dumping relevant documentation into the prompt before each generation session. This is closer to the right approach, but it depends on the developer knowing which documents are relevant, finding them, and including them consistently. When a constraint changes, every prompt that embedded the old version is stale.

None of these iterations address the underlying structure of the problem. A prompt is a session artefact. The constraints that govern a production codebase are project artefacts. The fix is to treat them that way.


The right approach

The ANN AI-SDLC The ANN AI-SDLC is built on a simple principle: the documents that constrain AI generation should be committed to the repository, reviewed by the team, and maintained alongside the code. They are not prompt inputs — they are first-class engineering artefacts.

Three documents form the constraint layer for every feature:

The scope document captures the business problem and the constraints the implementation must respect. It is written before requirements, before ADRs, before any code. Its purpose is to ensure that everyone who works on the feature — including the AI during generation — has the same understanding of what problem is being solved and what the implementation is not allowed to do.

For the guest checkout feature, the scope document includes the 34% cart abandonment figure that establishes why this feature exists, the operational constraint that guest orders must appear identically to registered orders in the admin panel, and the GDPR constraint on marketing email. These are not implementation details — they are business constraints that determine which implementations are acceptable. A developer writing an ADR needs them. The AI generating code needs them.

The requirements file translates the scope into testable statements. Each requirement has a user story and acceptance criteria specific enough that a developer and a reviewer can independently verify whether they were met. The user story format forces precision about who benefits and why, which the AI uses to make sensible decisions at edge cases:

## REQ-CHECKOUT-00010: Guest purchase without account

User story:
  As a first-time shopper,
  I want to complete my purchase without creating an account,
  so that I can buy without committing to a relationship with the platform
  before I know I trust it.

Acceptance criteria:
- "Continue as guest" option is displayed at the same visual weight as "Sign in"
- Guest checkout collects: email, shipping address, payment details only
- No account is created during the transaction
- A confirmation email is dispatched within 60 seconds of order placement
- Guest order appears in admin order panel with identical fields to a
  registered-user order; no separate guest workflow in operations

The "so that" clause in the user story — "so that I can buy without committing to a relationship with the platform before I know I trust it" — is not decorative. An AI that knows a guest is checking out because they do not yet trust the platform makes different decisions about friction, confirmation copy, and data retention than one told only to "implement guest checkout."

The ADR records the architectural decision with the alternatives explicitly rejected. ADR-012 for the guest checkout feature documents the unified orders collection approach and the rejection of the separate guest_orders collection:

## ADR-012: Guest orders stored in unified orders collection

Status: Accepted

Context: Guest checkout requires order persistence without a user account.
Two options were considered: a separate guest_orders collection, or storing
guest orders in the existing orders collection with a nullable userId field.

Decision: Store guest orders in the unified orders collection with
userId: null and guestEmail: string.

Rejected alternative: Separate guest_orders collection
Reason for rejection: Duplicates all order management logic; creates a
second surface for bugs; violates the single-workflow operations constraint.

Consequences:
- All order queries must handle userId == null explicitly
- Index on guestEmail required for returns lookup by email
- GDPR deletion requests must include guest order cleanup by email, not uid

When the AI generates code with ADR-012 in context, it cannot drift toward the rejected alternative. It knows the constraint. It knows the consequences. The rejected alternatives section is not a history lesson — it is an active constraint on future generation.


Practical walkthrough

The difference between prompt-based generation and structure-based generation is visible in what the output handles without being explicitly asked.

A prompt-based generation for the guest checkout feature produces a Guest model or a GuestOrder model — the natural, obvious approach. When the AI has no information about ADR-012, it makes the reasonable call. The separate model approach is coherent, but it violates the operations constraint and creates the duplication problem that ADR-012 was written to prevent.

A structure-based generation produces the correct implementation from the first run, because the AI has read ADR-012 before writing a line:

// lib/models/order.dart — constrained by ADR-012

class Order {
  final String id;
  final String? userId;       // null for guest orders — per ADR-012
  final String? guestEmail;   // required when userId is null
  final List<OrderItem> items;
  final double total;
  final DateTime createdAt;

  Order({
    required this.id,
    this.userId,
    this.guestEmail,
    required this.items,
    required this.total,
    required this.createdAt,
  }) : assert(
         userId != null || guestEmail != null,
         'Order must have either a userId or a guestEmail',
       );
}

The assertion encodes the architectural constraint at the model level. A future developer cannot create an Order without satisfying the constraint. A future AI session generating code in this codebase encounters the assertion, reads the comment referencing ADR-012, and does not need to re-derive the constraint from scratch.

The Firestore security rules for guest order reads are generated correctly because REQ-CHECKOUT-00010's acceptance criteria state that guest orders must be readable without an authenticated session, and ADR-012's consequences section specifies the orderId + guestEmail lookup pattern for the returns flow:

// firestore.rules — guest reads per REQ-CHECKOUT-00010 and ADR-012
match /orders/{orderId} {
  allow read: if (request.auth != null
      && request.auth.uid == resource.data.userId)
    || (resource.data.userId == null
      && resource.data.guestEmail == request.resource.data.guestEmail);
  allow write: if request.auth != null;
}

This rule is not something a developer would write from a prompt that says "add guest checkout." It requires knowing that guests need read access, knowing the lookup mechanism (order ID plus guest email), and knowing that writes still require authentication. All of that knowledge lives in the structured documents, not in a prompt.


Common mistakes even when trying

Treating ADRs as documentation rather than constraints. The most common misapplication of ADRs is writing them after the code ships. An ADR written post-hoc documents what was built. It cannot constrain what will be generated next sprint. ADRs must be written before generation runs. The ADR is an input, not a retrospective.

Requirements that specify the implementation. A requirements file that says "use a nullable userId field" is an implementation instruction, not a requirement. Requirements specify observable outcomes: what the user can do, what the system does in response, what appears in the admin panel. How the implementation achieves those outcomes is the ADR's domain. Mixing them produces requirements that are both too prescriptive (the implementation detail) and too vague (the actual acceptance criterion).

Scope documents written for stakeholders, not for generation. A scope document written to explain a feature to a non-technical stakeholder uses language like "improve the checkout experience." This does not constrain generation. A scope document written as a generation input names the specific constraints: the 34% abandonment figure, the operations single-workflow requirement, the GDPR email opt-in constraint. It is readable by stakeholders and actionable by the AI.

Keeping documents in Notion or Confluence instead of the repository. Documents that live outside the repository are not available to the AI during generation unless someone explicitly fetches and includes them in the context. They also diverge from the code over time without anyone noticing. Committed documents stay in sync with the codebase through the normal review and merge process.

Writing one document and skipping the other two. Teams who adopt part of the structure — ADRs without scope documents, or requirements without ADRs — capture some constraints but leave significant gaps. A requirements file without an ADR leaves architectural decisions to the generation step. An ADR without a scope document may record a decision that violates a business constraint the ADR author was not aware of. The three documents are mutually reinforcing. Each one is weaker without the other two.

Using structure for large features and prompts for small ones. A feature that will take two days to implement does not look like it needs a scope document, a requirements file, and an ADR. This reasoning is correct for truly trivial changes — a label update, a color value, a configuration flag. It fails for anything that touches a data model, a new collection, a security rule, or an API shape. These changes introduce architectural decisions that constrain every future feature in the same area. The cost of the three documents for a small feature is a few hours. The cost of a missing ADR for a data model decision is every future sprint that has to reverse-engineer the decision instead of reading a committed record.

Generating the structure documents with AI from a task description. A scope document generated by the AI from "add guest checkout" is the same problem one level up: the AI is making decisions — in this case, about what constraints the feature operates under — without the information needed to make them correctly. Structure documents must be written by engineers who have spoken to the stakeholders, who understand the operational constraints, and who can evaluate which architectural decisions need to be made before generation begins. AI can assist in drafting templates and formatting. The content must come from the team.


Key takeaway

Structure is the prompt. The scope document, the requirements file, and the ADR together constrain AI generation more completely than any prompt, because they capture decisions made by multiple people over multiple sessions and make those decisions visible to every future generation step. Prompt engineering is still useful — it guides interpretation within a session. But it cannot substitute for structured documents that persist across sessions and teams.

The next article in this series covers the first phase of the ANN AI-SDLC in detail: Phase I: Why Blueprint Before Build, including how scope documents, requirements, and ADRs are produced and what makes each one effective.

Comments

No comments yet. Be the first!

Sign in to leave a comment.