跪拜 Guibai
← Back to the summary

Turn Specs into Sub-Agent Tasks Without Guessing: The AI-SDLC Design Phase

The requirements phase hands over a spec, a decision record, and a fixed code baseline. The design phase takes these three things and does two things: write a technical plan, then break the plan into a set of development tasks.

The development phase has multiple sub-agents executing these tasks in parallel. Each sub-agent only sees the task assigned to it, not the design-phase conversations or other tasks. So the goal of the design phase is one thing: no guessing during development.

This post covers six items:

One place where we stepped on a pitfall: early on, we ran independent reviews and multiple self-reviews inside the design phase. As soon as a loop appeared inside the phase, it became very time-consuming. Later we changed to: generate the plan only once and have a human review it.

What the design phase reads, who does it, and what it delivers

Design phase overview: read the requirements-phase handoff, main agent does four things, developer confirms once, then hands to sub-agents

The design phase's input all comes from the requirements phase handoff: spec, decision record, repository and code baseline, plus deferred items still being aligned.

The main agent still does the work. It loads the design phase's main skill, then calls a dedicated skill for writing the plan and breaking down tasks as needed, and reads the coding standards for the selected platform.

This phase does not do three things: it does not redo requirements, does not write production code, and does not run builds or tests.

It must deliver seven files:

Several other files are generated on condition. When acceptance requires simulating interface states, record which local data to use. For complex targets with many architectural constraints, additionally freeze an architecture agreement stating roles, owners, public signatures, and dependency direction, which the development phase uses directly without re-deriving.

Architectural questions follow the requirements phase's clarification method

The design phase also has questions to ask humans, and the way to ask is the same as in post 03: search first, then ask; for dependent questions ask one at a time; for independent ones combine into a round, at most 3; each question includes evidence and a recommendation.

The difference is in what is asked. The requirements phase asks about conflicts between various sources; the design phase asks about architectural judgment. Only six types go to a human: ones that change the business result, change architectural boundaries, change repository scope, involve compatibility strategies, require accepting risk, or require writing to external systems.

One category is easy to miss. Some internal implementations look like mere technical details, but they change the order of request waiting, completion, or notification, change the effect of cancellation, or determine whether the result is handed to the user. These are also design decisions and must be asked.

File paths, type names, and check commands are not asked; they are derived from code and standards.

After asking, write the decision record. The design phase's decision record specifically records things that constrain code shape:

Each entry writes the decision, rationale, affected conventions, which old decision it supersedes, and which repositories and evidence are involved. Write only after the developer confirms; after writing, only append, never modify.

Things the agent wants to do beyond its scope: pause and ask separately

When writing the plan, content beyond the requirements may be brought in: reserving capabilities for future use, extracting a common base class, adding a layer of compatibility, refactoring along the way, optimizing performance, adding monitoring, upgrading components.

These may all make sense, but they are not in this requirement. The design phase rule is: when such content appears, pause that branch first, explain to the developer what is being added, the benefit, cost, risk, and the impact on this delivery, and separately ask whether to include it. Before confirmation, record it only as "out-of-scope candidate," not into the plan, tasks, or write scope.

New things in the plan must also be traceable to evidence:

If what is found is a larger change, such as a change to the repositories, interfaces, or acceptance criteria, the design phase does not expand on its own; it returns to the requirements phase to reconfirm.

What the technical design document contains: five parts, four diagrams, and for each acceptance criterion, where it is implemented and how it is tested

Technical design document: five parts, four diagrams, one acceptance mapping table

The technical design document is the plan reviewed by the developer; write one per module. Content follows the team's fixed template in five parts:

The document also includes four Mermaid diagrams, two about structure and two about flow:

The participants and calls in the diagrams must come from existing code or confirmed design; do not add mechanisms just to make the diagram complete. For simple changes where a particular diagram really is not applicable, write the reason and basis; insufficient materials do not count as not applicable.

The document ends with an acceptance mapping table that lists each acceptance criterion from the spec one by one, and states three things: which part of the design implements it, which test verifies it, and its current status. Since tests have not run in the design phase, the status can only be "pending verification." This table guarantees that every acceptance criterion has a matching design and test, so none is missed when breaking down tasks.

After writing, the agent self-checks against a checklist: only one level-1 title, no unreplaced placeholders, all four diagrams present, and the acceptance mapping table lists every acceptance criterion with no empty cells. If missing, it fixes them and re-checks, and does not ask humans about these.

After the developer confirms the plan, the technical design document is by default posted to the team's documentation platform, and a link is returned to the developer.

The plan is generated only once, then reviewed by a human

The previous in-phase review loop has been removed; now one-shot generation, checklist self-check, human review

The pitfall: in-phase review loops

In the early design phase there was an independent review and multiple self-reviews: the agent generated a plan, a review agent picked out problems, the agent revised, and it was reviewed again.

The problem was that it was too slow: once a loop appeared inside the phase, it became very time-consuming. We later removed it and tried to have humans review as much as possible.

Current approach:

The checklist from the previous section is not a review loop. It only checks mechanical issues: missing diagrams, broken table formatting, an acceptance mapping table missing a criterion. These can be fixed against the checklist; if there is progress, continue, with no fixed number of rounds, and it does not judge whether the plan itself is good.

Automatic check passing, agent self-review, or the developer not replying does not count as plan confirmation. Confirmation comes only from an explicit developer answer, as described in the last section.

How the problems found by human review are fed back and make the next generation better is deferred to post 11.

Break down tasks by business behavior

Three ways to break down the same dual-platform requirement: by platform, by layer, by business behavior

The plan answers how; the task answers who does it and in what order.

First, some background. We do mobile development; a requirement usually changes both Android and iOS, and the two platforms have different technology stacks. So the most convenient breakdown is by platform: one Android task, one iOS task. More finely, each platform can be broken down by layer: data, logic, UI, one task each.

Both of these breakdowns have the same problem in verification:

The design phase breakdown method is: first list the observable business behaviors to be implemented in this requirement: what the user does, what result the system gives, including normal cases, exception cases, and existing behaviors that need protection. Then determine which behaviors can be implemented and verified independently, and only then map to platforms, code layers, and files.

A task still belongs to only one repository and one platform, but it implements a specific behavior, such as "cancel orders not paid within timeout on Android," rather than "all Android changes." Inside a task, follow the existing code layering; do not copy a separate set of data, logic, and UI for each behavior. Joint verification that can only be done after both platforms are complete is placed in a separate verification step, not as a precondition for starting each task.

Each task must be able to determine whether it is done. Descriptions like "implement module," "complete entire platform UI," "improve exception handling" cannot be judged and are not allowed.

A qualified task description, using a generic example:

Cancel orders not paid within timeout. Only modify order-status-related files and corresponding tests; depend on the confirmed timeout event format; when the same event is received twice, process it only once. Cover four scenarios: already timed out, not yet timed out, duplicate event, already paid. Verify with order-related targeted tests; the task is done when the four scenarios pass and the original payment behavior is unaffected.

Merging tasks has explicit conditions: two behaviors jointly maintain a state that cannot be split, or it is a destructive interface migration, or splitting them gives no separate verification value. Merging must state a reason in the plan. The same page, same file, or same owner does not automatically make them one task.

Dependencies also require a reason: what artifact from the upstream task this task uses, which behavior it is used in, and why it must be done first. Same layer, same page, or scheduling convenience do not count as dependencies.

Each task is written clearly: the development sub-agent only sees the task itself

A development sub-agent's context window contains only role description, project instructions, and the task assigned to it

In addition to the text description, each task has a machine-readable YAML block:

id: T003
title: Cancel orders not paid within timeout
repository: <repository>
depends_on: [T001]
owner: coder                  # implementation role
read_refs:                    # files to read before starting
  - <corresponding acceptance criterion from spec>
  - <corresponding section from plan>
  - <rule file applicable to target directory>
write_scope:                  # existing files allowed to modify
  - <order status file>
  - <corresponding test file>
create_scope: []              # files allowed to create; write empty list if none
done_when:
  - Four scenarios behave as expected, original payment behavior unchanged
verify:
  - <command that runs only tests for this task>
case_ids: [<corresponding test intent IDs>]

This is written in such detail because the development sub-agent does not get the design-phase context.

Claude Code's sub-agents start in an independent context window; they cannot see the main conversation history, nor the skills the main agent called or the files it read. What they mainly get is: their own role description, the task message written by the main agent, the CLAUDE.md at each level and the AGENTS.md loaded as project instructions, the repository's git status, and the skills preloaded from the role definition. The exception is fork: a forked sub-agent starts with the entire conversation. When we dispatch to custom roles such as implementer, reviewer, and tester, we use ordinary dispatch, not fork.

Codex's spawn_agent also has a corresponding switch. In the currently default-on v1 multi-agent, fork_context is off by default, and sub-agents do not carry parent session history. The v2 multi-agent is not enabled by default; when enabled, if fork_turns is not written, it will carry all parent session history, so you must explicitly write none. Our project uses v1.

Our dispatch rules align with these two defaults: executors only get their own task, write scope, necessary rules, files to read, and result requirements; they do not inherit the parent conversation or see other tasks. Files the parent agent has read are as if the sub-agent has not read them, so everything to read is listed in the task's read list and the sub-agent reads it itself.

Information not written in the task either makes the sub-agent come back to ask or guess on its own, so the design phase must write everything down.

Test intent is also written in the design phase, stored in a separate file, and referenced by number from tasks. Each test intent writes:

When acceptance requires a controllable interface state, first reuse existing local mock data. Creating or modifying a remote Mock is an external write and requires separate authorization.

Task descriptions compile into a task graph: the CLI only checks order

tasks.md compiles into a task graph; CLI only checks order; tasks are scheduled by dependency, write scope, and limit

The task descriptions tasks.md are for humans. The file has a task graph header block that writes repository, baseline, and the terminal tasks that must be completed; each task then has its own YAML block. The task graph is compiled by the CLI from this file, not handwritten, and tasks are not added from chat records.

The CLI only reports errors when the order is indeterminate, specifically in three cases:

Overlapping write scopes between two tasks only gives a warning, not an error, and the scheduler serializes those two tasks.

The development phase schedules according to the task graph. A task can start when three conditions are simultaneously met:

'The limit is 3 by default, written in the configuration. The responsible role for each task determines which sub-agent it dispatches to; role definitions are written only once and synchronized to both hosts, as described in post 01.',

'The CLI reads only the ID, title, dependency, repository, write and create scope, completion condition, and responsible role from the task graph; all other fields are not checked. Whether the task breakdown is correct, whether the description is clear enough, and whether the verify command is chosen correctly are written by the agent per the method and reviewed by the developer. This is consistent with the division of labor in post 02: the CLI manages structure and order, not semantics.'

When materials are incomplete: affected tasks pause, other tasks develop normally

The design phase may lack materials—for example, the interface protocol has not been given, a certain state's design draft is unavailable, or copy has not been decided.

Missing materials are recorded in a gap list; each entry states: what is missing, who is responsible for filling it, which tasks are affected, and what counts as complete. Affected tasks and tasks that depend on them are paused; other tasks proceed to development normally.

If a gap affects only part of a task's functionality, split the task first, and the unaffected part develops normally.

Two types of things must be distinguished:

A real example:

After materials are complete, the agent checks them, completes the affected tasks, recompiles the task graph, and then asks the developer to confirm the plan and development scope.

One confirmation of the plan and development scope

After the plan is written and the task graph compiles, the main agent presents once to the developer:

Then give three options: develop according to the plan, adjust the plan, or do not develop. The phrasing follows the host question tool from post 03.

Two rules:

In a real confirmation, the developer's answer was "confirmed, start development per this plan and complete local checks," and asked to preserve the confirmed requirements and fixed baseline. The recorded authorization scope was writes within the task graph, the isolated working copy, and declared local checks, with not a single external action authorized.

The exact wording of the answer is written into the decision record and handoff file. An already effective confirmation is not asked again; the agent fills gaps in the document without asking the same content again.

What is handed to the development phase

The design phase hands over: a human-reviewed technical plan, a compiled task graph, development authorization within the graph, and an owner and unblock condition for each gap.

Looking back at the whole phase, the agent is responsible for searching and writing: search code and standards, write the plan and tasks, and self-check format against a checklist. The human is responsible for judging: architectural decisions, whether out-of-scope things should be done, and whether the plan quality is good enough.

The next post covers development: how multiple sub-agents execute in parallel according to this task graph.

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

智测星球

The plan is generated only once, and I haven't seen this pitfall covered in your repository. If the testing intent isn't written into the task description, will the sub-agent still be able to see that acceptance criterion when it starts work?