AI Coding: Align Requirements Before Writing Code
This article explains why AI coding assistants often fail in real projects: requirements lose fidelity as they move from human intent to prompts and generated code. It introduces spec-driven development, an approach that treats requirements as first-class engineering artifacts. You’ll learn how to organize specs by change, write proposals with goals, scope, design, and testable acceptance criteria, use workflows, validate specs, archive changes, and align across teams and AI tools.
1. The Real Bottleneck in AI Coding: Requirements Lose Fidelity as They Travel
Many teams see the same gap after introducing AI coding assistants: the demo looks impressive, but daily development frequently ends in rewrites. The problem is usually not model capability; it is how requirements are passed along.
A requirement travels through a chain:
human mental model → natural-language description → model understanding → code generation
Each step can lose or distort information, and those distortions eventually surface as rework.
Adding a few precise constraints, such as “use session management for login state, implement password login first, and do not introduce new dependencies,” can immediately narrow the model’s behavior. In other words, AI does not necessarily fail to understand requirements. The requirements are often never fully expressed.
1. Three Typical Forms of Vague Requirements
- Vague goal: “Make the query page faster and easier to use” cannot be converted into concrete changes. The model has to guess what optimization means.
- Vague scope: Without a clear definition of what is in scope and what is out of scope, the model may refactor unrelated modules or introduce new dependencies.
- Vague constraints: If technology-stack versions, compatibility requirements, security baselines, or performance limits are not stated, the model may follow generic practices that conflict with the existing architecture.
2. The Vaguer the Requirement, the Higher the Rework Cost
In long conversations, important decisions made early are gradually diluted by later discussion. Every adjustment forces the background to be explained again, and much of the time is spent re-aligning requirements.
There is also a more hidden cost. Code produced from guesses may look reasonable but drift away from the original intent. This drift is often discovered only during testing or release, when fixing it becomes much more expensive.
3. Requirement Distortion Is Not Unique to the AI Era
The same problem appears in traditional waterfall development as “scope creep.” Whenever there is no written, checkable basis for alignment, more communication participants and longer timelines tend to create larger misunderstandings.
Conversational collaboration also has an inherent information gap. Changes made in parallel and files generated by other tools are often not present in the context of a single conversation. AI can only answer based on what it can see. Chat alone cannot solve context synchronization.
Therefore, instead of repeatedly tuning prompts, it is better to turn requirements into a clear, traceable, verifiable engineering artifact. This is the problem that spec-driven development aims to solve.
2. Spec-Driven Development: Make Alignment an Upfront Engineering Task
The core idea of spec-driven development is simple:
Specs are first-class deliverables; code is the implementation of those specs.
Before writing code, a structured document should answer four questions:
- Why are we doing this? — the goal
- What are we doing and what are we not doing? — the scope
- How will we do it? — the technical approach
- What must be true for this to be considered complete? — the acceptance criteria
This is different from traditional “write requirements documents first.” Traditional documents are written mainly for human readers and often drift away from the code over time. In spec-driven development, specs are written for both AI systems and automated workflows. They must be consistent in format, verifiable, and traceable.
This approach brings three shifts:
- From “chat while changing” to “define before writing”: Requirements that drift in conversation become stabilized in a written spec after review.
- From “conversational memory” to “file persistence”: Context that depends on sessions that will expire becomes content stored in version-controlled files.
- From “verbal acceptance” to “executable acceptance”: Acceptance that depends on ad hoc discussion becomes a checklist of explicit, testable criteria.
Writing specs before code does not mean falling back to waterfall development. A proposal only needs enough detail to judge whether the direction is correct. More detailed technical design can be added during implementation. Specs constrain goals and boundaries, not every implementation detail.
3. Core Idea: One Change, One Directory
Specs often become abandoned documents because they are scattered across chat logs, document systems, and code comments. No one maintains them, and no one can trace them.
A practical solution is to organize by change: for each feature or modification, create a dedicated directory. All artifacts produced during that change’s lifecycle live in that directory.
my-project/├── .ai-context/ # Project-level context for AI tools│ ├── project.md # Technology stack, directory structure, and core module responsibilities│ └── conventions.md # Naming, exception handling, testing, and other coding conventions├── specs/ # Active capability specs (“living documents”)│ ├── authentication.md│ └── query-api.md├── changes/ # In-progress changes, one directory per change│ └── add-login-rate-limit/│ ├── proposal.md # Goals, scope, and acceptance criteria│ ├── design.md # Technical approach and key tradeoffs│ ├── tasks.md # Task list with independently verifiable tasks│ └── specs/│ └── authentication.md # Incremental changes to spec files in this change└── archive/ # Archived completed changes└── 2026-03/└── add-password-reset/
This organization provides three benefits:
- Clear boundaries: One directory corresponds to one requirement discussion. AI can read the relevant files without replaying the entire conversation history.
- Full traceability: Every “why did we do it this way” decision has a written record. Teams can use normal version-control tools to inspect history and diffs.
- Specs stay current:
specs/describes what the system is now,changes/describes what it is becoming, andarchive/records how it changed.
4. Making AI Understand Requirements: Four Required Parts of a Proposal
Regardless of which AI tool is used, the prerequisite for useful code output is a complete proposal as input.
Below is an example: adding rate limiting to the login API.
---id: add-login-rate-limitstatus: draft # draft → in-progress → done → archivedowners: [zhangsan]---# Add rate limiting to the login API## 1. Goal (Why)Recent monitoring shows that the same IP address is repeatedly attempting to log in to the same account at a high frequency. This creates a credential-stuffing risk, so rate limiting should be added.## 2. Scope- In Scope: Limit the request frequency of the login API by source IP. When the threshold is reached, reject the request and record an audit log.- Out of Scope: CAPTCHA, device fingerprinting, and rate limiting for user registration and password recovery APIs.## 3. How- Rate-limiting algorithm: sliding window- Threshold: up to 10 requests per minute per IP; the default value can be adjusted through the configuration center- Storage: reuse the existing cache service; key format: login:limit:{ip}- Over-limit response: HTTP 429, with the Retry-After response header## 4. Acceptance Criteria- [ ] The 11th request from the same IP within one minute receives HTTP 429, and Retry-After is no less than 1- [ ] Counters for different IPs do not affect each other- [ ] Every rate-limit event is written to the audit log, including IP, time, and request path- [ ] Unit tests cover window boundaries: the 10th request passes, the 11th is rejected, and the counter recovers after the window rolls- [ ] The additional latency introduced by rate limiting in the login path is below 5ms at P99
The four parts serve different purposes:
- The goal constrains direction.
- The scope defines boundaries.
- The technical approach records key decisions.
- The acceptance criteria turn “done” into a checklist that can be reviewed item by item.
The acceptance criteria are especially valuable from an engineering perspective. Each item should be observable and testable. “The response should be fast” is not an acceptance criterion. “95% of queries return within 300ms” is.
A proposal can also include an “Open Questions” section. For example: What rate-limit threshold will not affect normal users? Such questions involve business tradeoffs, and AI should not decide them unilaterally. Once the business side confirms, write the conclusion back into the proposal so the decision process is preserved.
5. Turn High-Frequency Actions into Workflows
In AI coding tools, teams can define custom commands in project context files. This turns “propose requirements, write design, split tasks, and verify against acceptance criteria” into reusable steps.
Compared with open-ended natural-language prompts, a fixed workflow keeps outputs consistent in format and granularity.
A simplified workflow looks like this. Command names are illustrative.
/propose add rate limiting to the login API→ Generate changes/add-login-rate-limit/proposal.md→ Produce an “understanding summary + ambiguity list” for human confirmation/plan add-login-rate-limit→ Generate design.md: technology choices, key tradeoffs, and risks/tasks add-login-rate-limit→ Generate tasks.md: split tasks at “independently verifiable” granularity/implement add-login-rate-limit→ Execute one task at a time; write back checked status after completion/verify add-login-rate-limit→ Check acceptance criteria one by one; output a list marked “met / not met / needs manual verification”
There are two key design points:
- Move human confirmation earlier: At the
/proposestage, a human confirms the understanding summary and ambiguity list. This reduces the cost of correction. - AI executes, humans decide: Decisions involving tradeoffs, such as technology choices or business thresholds, should be confirmed or decided by humans.
If the tool supports custom commands, the command definitions can standardize input formats, output templates, and prohibited actions. For example:
- “Do not modify files outside the declared scope list.”
- “If ambiguity appears, write it in Open Questions; do not make assumptions.”
A context file is not only a list of commands. It should also describe team conventions for “how to work.” For example:
# Working conventions (excerpt)- Read relevant files under specs/ before making changes, and follow existing specs.- Handle only one task at a time. If database schema changes are involved, provide a rollback plan first.- When adding or changing behavior, update the corresponding spec increment file under changes/.- Commit unit tests together with implementation code in the same change.
With these conventions in place, even team members who ask questions directly in chat can still follow the same rules.
6. Use Incremental Files to Manage Spec Evolution
After a feature is implemented, the code is not the only thing that must change. The corresponding files under specs/ must also be updated so they accurately describe current system capabilities.
A useful approach is to describe changes with incremental markers in the change directory. This makes it easier to record only the difference.
## ADDED Requirements### Requirement: Login API rate limitingThe system SHALL limit the request frequency of the login API by source IP. Requests that exceed the threshold MUST be rejected and MUST return HTTP 429.#### Scenario: Request limit exceeded within one minute- **WHEN** the same IP makes the 11th login request within one minute- **THEN** the system returns HTTP 429 with a Retry-After header- **AND** the event is written to the audit log#### Scenario: Counting window rolls- **WHEN** the IP sends a request again after the current window ends- **THEN** the counter resets to 1 and the request is processed normally## MODIFIED Requirements### Requirement: Login failure handling<!-- Describe only the changes relative to the existing spec. For example: requests rejected by rate limiting do not count toward failed-login attempts. -->
This style has two advantages:
- Lower maintenance cost: You do not need to rewrite the entire spec file for every change, reducing the risk of inconsistency.
- Clear history: Once merged into
specs/, the historical versions themselves become a complete record of each change.
Keywords such as SHALL and MUST come from requirements engineering. They make the boundary between “must” and “should” explicit and make it easier for tools to identify and validate requirements.
7. Validation and Archiving: Keep Specs from Rotting
Even well-written specs will decay without safeguards. Two checkpoints are usually needed.
Before implementation: structure and completeness validation.
Check that the proposal contains the four required parts, that In Scope and Out of Scope appear together, that acceptance criteria are testable, and that each task in the task list points to a specific acceptance item.
After task completion: acceptance item by item.
Acceptance results are classified into three categories: “met,” “not met,” and “needs manual verification.” For items that can only be confirmed through real testing, such as added latency or concurrency behavior, mark them as needing verification and add them to the test or release plan. Do not treat them as completed without evidence.
Validation rules can start as a local script and later become part of continuous integration. For example, a merge request pipeline can add a spec-check step that validates only the spec files changed in that request:
# Example: validate only spec files changed in this branchCHANGED=$(git diff --name-only --diff-filter=ACMR origin/main...HEAD -- specs/ | tr '\n' ' ')if [ -n "$CHANGED" ]; then./scripts/check-spec.sh $CHANGEDfi
After a change is completed and merged, move the entire change directory into archive/ and merge its spec increments into specs/. The archive makes it possible to answer “why was it designed this way” later. It can provide useful clues for refactoring or debugging months afterward.
8. Team Collaboration: Specs as a Tool-Agnostic Contract
In practice, team members may use different tools. Some prefer terminal-based agents, some prefer coding assistants integrated into editors, and some prefer web-based conversational tools. The tools differ, but the requirements must stay consistent.
Spec-driven development helps because specs are stored as plain text in the code repository and are independent of any specific tool.
- Unified context entry: The project context file describes the project and technical conventions, not any particular tool. Every team member can read the same guidance regardless of the tool they use.
- Specs become review objects: Proposals and code are reviewed in the same repository. Reviewers can judge whether the direction is correct before coding starts. Problems discovered earlier are cheaper to fix.
- Knowledge persists with the repository: When team members change, new members can read
specs/to understand the current system andarchive/to understand how it evolved.
When specs become the team’s common language, the choice of AI tool becomes a personal preference rather than a collaboration obstacle.
9. Adoption Advice and Common Pitfalls
Adoption Advice
- Start small: Pilot a small, well-bounded requirement that can be completed in one to three days. Run the full loop: propose → implement → verify → archive. Expand gradually.
- Keep templates simple first: Initially, goal, scope, and acceptance criteria are enough. Add design documents and risk analysis after the team gets used to the process.
- Assign clear owners: Specs need maintainers. Assign an owner for each change and review spec completeness during review.
- Measure improvement: Track metrics such as the number of requirement clarification rounds, rework count, and first-pass acceptance rate. Use data to judge whether the process is effective.
Common Pitfalls
- Specs become too long: Specs are not an encyclopedia of requirements. Focus on the goal and boundaries of the current change. If a document is dozens of pages long, neither AI nor humans can absorb it effectively.
- Specs and code drift apart: If code changes but specs do not,
specs/quickly loses value. Updating specs should be a required condition for completing a change. - Acceptance criteria become a feature list: “Implement rate limiting” is a task. “The 11th request returns HTTP 429” is an acceptance criterion.
- Specs are written and then ignored: Periodically review archived changes and turn recurring issues into context files and working conventions. This keeps specs becoming more accurate over time.
Conclusion
AI coding assistants do not automatically understand requirements we never spoke aloud. If requirements remain vague, repeated conversation can patch the gaps, but the cost is time and patience. If requirements are expressed through structured specs, the cost is one clear explanation that can be reused across people and tools.
Spec-driven development is not complicated: write clear goals and scope, define testable acceptance criteria, organize files by change, and use validation and archiving to keep specs usable over time.
Before letting AI write the next line of code, ask four questions:
- Why are we doing this?
- What are we doing?
- What are we not doing?
- What does “done” look like?
Write down the answers. The first line of code generated by AI will be much closer to what you actually want.
