Skip to content

/refine-specs

Synced verbatim from the repo on every site build. Edit the source file on GitHub (link in the page footer); do not edit the rendered copy here.

Description

Refines an existing business spec into a detailed technical spec ready for implementation. Reads the codebase in depth to understand the technical context and asks the developer technical and business questions if needed to fill any gaps.

Once the spec is complete, generates an execution plan specifying which agents must intervene and in what order, and which service each part of the code belongs to.

Invoked by

Developer

Agent

Spec Analyzer

Input

The business spec file created by the create-specs command: {project-name}-docs/specs/{Aggregate}/{feature-name}-specs.md

Steps

  1. Read the existing business spec file

  2. Read {project-name}-docs/services.md to understand the available services

  3. Read {project-name}-docs/decisions.md to understand existing architectural decisions

  4. Read {project-name}-docs/specs/INDEX.md to identify related specs; deep-read only specs with overlapping aggregates or services — do not re-read the full spec list

  5. Read the relevant codebase in depth to understand the technical context

  6. If the feature has a frontend component, read design-decisions.md — ensure the Frontend Architecture section is consistent with established patterns. If a contradiction is needed, flag it to the developer before writing the spec

  7. Ask the developer technical or business questions if information is missing or ambiguous. All multi-option questions MUST be delivered via the AskUserQuestion tool (UI dropdown) — never as inline Choose: a/b/c chat prose. Same rule applies to every architectural decision point in Step 7b, the ADR contradiction protocol in Step 9, and the aggregate verification in Step 9b. Free-form clarifications (open-ended “how do you want X to behave?”) use chat. 7b. Detect architectural decision points and ask explicitly. For every Command/Query handler the spec introduces or modifies, scan for these patterns and, when present, ask the developer before writing the spec:

    • Aggregate lookup by id → confirm a {Aggregate}FinderService exists (or plan it in the spec) and the handler calls it for throw-on-miss lookups. Repositories stay nullable-only (findById(Id): ?Entity). Never propose an inline find + null + throw or a getById on the repository
    • Multi-repository orchestration (cascade delete, cross-aggregate update) → ask: new domain service or reuse existing one?
    • Authorization / ownership checks → ask: inline this once, or delegate to a shared {Aggregate}AccessAuthorizationService (preferred when the same check repeats in 2+ handlers)
    • Branching business logic (“if exists reactivate else create”, state transitions with 2+ branches) → ask: extract to service
    • Read-model composition across 3+ projections → ask: extract to an application read service

    Reference rule: backend.md → “When to extract logic from a handler to a service”. If a pattern already exists in the codebase, flag it as a reuse opportunity before proposing a new service. When proposing a new service, remember that services MAY compose other services — prefer reusing an existing service (e.g. authorization, aggregate finder) over duplicating logic.

    Hard enforcement — one-public-method rule. Every service you propose MUST expose exactly ONE public method (execute) plus the constructor, per backend.md §Application Services. Before writing the spec, verify:

    • The proposed service does not name a second public method (no authorize + authorizeBoard, no findById + findByEmail on the same class, no “twin signatures for composition efficiency”).
    • Any helper method is private and called from execute.
    • If the feature genuinely needs two public entry points, SPLIT into two services (e.g. UserFinderService + UserFinderByEmailService) — never collapse them. A spec that embeds a multi-public service is rejected at review; catch it here instead.

    Do NOT guess silently — if in doubt, ASK. Record every decision taken here in the refined spec under a ## Architectural Decisions subsection so the Developer agent follows it.

  8. Refine the spec with technical details — architecture decisions, affected aggregates, services involved

    Refinement history protocol (load-bearing). If the spec already has a non-empty ## Technical Details section (i.e. a previous /refine-specs ran), do NOT silently overwrite. Capture the diff in ## Refinement history (per templates/feature-specs-template.md § “Refinement history”) with timestamp, iteration counter, one-line rationale, section-level changes, and any ADR conflicts surfaced. The first refine has no history entry.

8b. Mid-feature refine guard. If the spec’s ## Status is In progress (build-plan already started) or any of the affected service repos is on a non-master branch named feature/{aggregate}/{feature-name}, ABORT and tell the developer via AskUserQuestion: - (a) Finish the in-flight build-plan first — do not refine until the feature lands or aborts. - (b) Run /update-specs to checkpoint the current state, then re-run /refine-specs from a clean Status. - (c) Force the refine — accept that the in-flight build-plan handoffs may diverge from the spec. The developer assumes responsibility. Never silently overwrite a spec whose build-plan is in flight — the in-flight handoffs reference the previous Technical Details and a silent change desyncs the pipeline. 9. If this feature introduces a new architectural decision or changes an existing one, update decisions.md accordingly.

**ADR contradiction protocol (load-bearing).** Before writing a refinement that diverges from any `accepted` ADR in `decisions.md`, surface the conflict explicitly via `AskUserQuestion`:
- **(a) Supersede ADR-NNN** — write a new ADR with `status: accepted`, mark ADR-NNN `status: superseded` with a `supersededBy:` link per `standards/adr.md` § "Status lifecycle". Document the superseding rationale.
- **(b) Revise the refinement** to honor ADR-NNN — pick an alternative implementation path that does not contradict the existing decision.
- **(c) Abort the refinement** — surface to the developer with `## Status: blocked` and `## Open Questions` citing ADR-NNN.
The agent NEVER silently regresses an accepted ADR. Examples: if the project has an "Repository nullable-only" ADR, the agent must not silently propose `findOrFail()` on a repository — it must surface the conflict. If the project has a "memory-only access token" ADR (per SE-021 + ADR-001), the agent must not propose `localStorage` for the auth frontend.

9b. Aggregate / service verification (load-bearing). Cross-reference every aggregate listed in the spec’s ## Affected Aggregate(s) against services.md and the existing Domain/{Aggregate}/ folders in code. For every aggregate NOT in services.md and NOT yet present in code:

Ask the developer via `AskUserQuestion`:
- **(a) Land the new aggregate in service `X`** (the agent's best guess based on bounded-context heuristics).
- **(b) Warrant a NEW service** for this aggregate — per the project's service-granularity preference (microservices per bounded context for fault isolation).
- **(c) Rename the aggregate** to match an existing one (the developer realizes the name was wrong).
The selected option lands in the plan's `## New Aggregates` section with the owning service. A spec referencing an aggregate that is in neither services.md nor `## New Aggregates` is rejected by the self-validation gate at Step 14.

10. Classify the feature complexity (see Complexity Classification below) and include it in the plan 11. Generate the execution plan following ../templates/feature-plan-template.md. The template lists the mandatory sections in the order build-plan consumes them; key fields below are load-bearing for downstream routing: - ## Status (the agent’s own run status — complete when the self-validation gate at Step 14 passes) - ## Abstract (5 structured fields the build-plan orchestrator reads in Step 0 instead of the full plan) - The Complexity classification + Complexity Rationale citing the concrete criteria - ## Feature Kinds (subset of the closed set in standards/critical-paths/README.md) and ## Critical Paths Declared pointing at the matching files — the reviewer’s coverage-aware loader uses this as the iter-1 PRIMARY set - ## Applicable Rule Prefixes (subset of the 23-prefix set in CLAUDE.md § “Rule IDs”) with one trigger sentence per prefix — the bundle generator uses this list to extract checklist sections deterministically - Which agents must intervene and in what order (## Phases) - Which service each part of the code belongs to (## Affected Services) - Dependencies between steps - A Standards Scope section — this controls which files each subagent reads on demand 12. Create the task file with required tests and Definition of Done. Partition the DoD correctly: every test-related row goes under ### Tester scope; every architecture / wiring / scaffold / config row goes under ### Backend (Developer scope) / ### Frontend (Developer scope) / ### Shared. The self-validation gate at Step 14 enforces this partition. 13. Update {project-name}-docs/specs/INDEX.md if the spec’s status or summary changed — per the schema declared in templates/feature-specs-template.md § Status. The closed enum is the single source of truth for the Status column. Status value after a successful refine is Pending build (the spec + plan + task are ready, build-plan can run). 14. Self-validation gate — before declaring complete, run the validations declared in ../agents/spec-analyzer-agent.md § “Self-validation gate”: 1. DoD partition validity (no test rows under Backend / Frontend / Shared; no architecture rows under Tester scope). 2. Plan structural shape (Status, Abstract, Complexity, Complexity Rationale, Affected Services, Affected Aggregates, Feature Kinds, Critical Paths Declared, Applicable Rule Prefixes, Standards Scope, Phases all present and well-formed). 3. Spec structural shape (Status from the lifecycle enum, Abstract with 5 fields, PII Inventory present when Abstract.has_pii: true). 4. Cross-file coherence (aggregates / services declared once, plan Abstract == spec Abstract on the shared fields, complexity revisions cited in ## Architectural Decisions). 5. AskUserQuestion enforcement on architectural decisions (Step 7b above).

Any failure exits with `## Status: blocked` in the plan file and the specific gap in `## Status reason` — the developer resolves and re-runs `/refine-specs`. Build-plan Step 0 catches the blocked plan and refuses to proceed.

Complexity Classification

The plan file must include a ## Complexity section. This tells the build-plan orchestrator how to execute the plan — specifically, whether to use separate agents or consolidate them.

Evaluate the feature against these criteria:

ComplexityCriteriaAgent strategy
simpleSingle service, no API/DB changes, < 5 files, no new dependencies1 agent: Developer implements + writes tests. Reviewer optional (run only if the developer’s handoff flags uncertainty).
standardSingle service with API/DB changes, OR 2 services with straightforward integrationStandard flow: Dev → Reviewer (loop) → Tester
complexMultiple services, async messaging, new infrastructure, or > 3 aggregatesFull flow: DevOps → BE Dev ‖ FE Dev → Reviewers → Tester

Write it in the plan file as:

## Complexity: simple

When complexity is simple, the plan must consolidate the Developer and Tester phases into a single phase. The plan should have 1-2 phases total instead of 3-4.


Standards Scope

The plan file must include a Standards Scope section that tells the build-plan orchestrator which standards each agent needs. This prevents agents from reading irrelevant standards and reduces token consumption.

Analyze the feature and determine which of these apply:

ConditionInclude
Feature uses async messaging (RabbitMQ, domain events cross-service)backend-reference.md (async sections)
Feature scaffolds a new backend servicebackend-reference.md + new-service-checklist.md
First controller, AppController, or ApiExceptionSubscriber in a servicebackend-reference.md (scaffold sections)
First composable, store, or page pattern in a frontend servicefrontend-reference.md
Feature adds a new frontend that calls existing backendsnew-service-checklist.md (CORS section)

Write the section in this format in the plan file:

## Standards Scope
| Agent | Extra reads (beyond context bundle) |
|---|---|
| Backend Developer | `backend-reference.md` (async messaging) |
| Frontend Developer | `frontend-reference.md` (composable pattern) |
| Tester | `backend-reference.md` (PHPUnit config, test examples) |
| DevOps | `backend-reference.md` (consumer worker), `new-service-checklist.md` |

If no extra reads are needed for an agent, write none — the agent will still read the context bundle (which contains the distilled standard rules relevant to this feature).

Output

  • The refined technical spec file updated in place: {project-name}-docs/specs/{Aggregate}/{feature-name}-specs.md
  • A plan file: {project-name}-docs/specs/{Aggregate}/{feature-name}-plan.md — follow templates/feature-plan-template.md. Mandatory sections: ## Status, ## Abstract, ## Complexity, ## Complexity Rationale, ## Affected Services, ## Affected Aggregates, ## Feature Kinds, ## Critical Paths Declared, ## Applicable Rule Prefixes, ## Standards Scope, ## Phases, ## Architectural Decisions, ## Open Questions.
  • A task file: {project-name}-docs/specs/{Aggregate}/{feature-name}-task.md — follow templates/feature-task-template.md.

Token Usage Report

After completing, list the files you read and display: Estimated input tokens: ~{lines_read × 8}

Context Checkpoint

After completing this command, evaluate whether the conversation context is getting heavy (many specs refined, large codebase exploration, multiple features in one session). If so, suggest to the developer:

“The spec is refined and ready to build. To keep context fresh and avoid token waste, I recommend opening a new session and running: /build-plan for {plan-file-path}

If context is still light (e.g. single feature refined in a short conversation), it’s fine to continue in the same session.

If the developer asked to refine multiple specs in one session, suggest a new session before starting the /build-plan for ANY of them — the build-plan subagents benefit most from a clean orchestrator context.