aw-spec-cli 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/assets/.agents/skills/appweaver/SKILL.md +7 -47
  2. package/assets/.appweaver/ORCH-DIALECT.md +13 -9
  3. package/assets/.appweaver/RULE-PARTITION.md +11 -12
  4. package/assets/.appweaver/STACK-PROFILES.md +260 -108
  5. package/assets/.appweaver/domain.json +1 -1
  6. package/assets/.appweaver/interpreter/run-skill.py +28 -7
  7. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
  8. package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
  9. package/assets/.appweaver/orchestrator/README.md +120 -53
  10. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
  11. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +17 -7
  12. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
  13. package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
  14. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +392 -0
  15. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +548 -0
  16. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
  17. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
  18. package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
  19. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +5 -4
  20. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +3 -1
  21. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
  22. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  23. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +21 -13
  24. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
  25. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +28 -31
  26. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
  27. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  28. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
  29. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +4 -1
  30. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
  31. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +17 -16
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +7 -1
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +7 -1
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
  37. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
  38. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  39. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
  40. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
  41. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  42. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
  43. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +253 -44
  44. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +72 -71
  45. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  46. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +38 -14
  47. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
  48. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
  49. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
  50. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
  51. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +3 -3
  52. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
  53. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
  54. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +371 -131
  55. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +293 -76
  56. package/assets/.appweaver/scripts/python/aw-foundation.py +885 -20
  57. package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
  58. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
  59. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
  60. package/assets/.appweaver/scripts/python/aw-stack.py +676 -99
  61. package/assets/.appweaver/stack-profiles/angular.json +2 -1
  62. package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
  63. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +18 -3
  64. package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
  65. package/assets/.appweaver/stack-profiles/java-spring.json +14 -5
  66. package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
  67. package/assets/.appweaver/stack-profiles/node-express.json +8 -2
  68. package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
  69. package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
  70. package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
  71. package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
  72. package/assets/.appweaver/stacks.json +40 -1
  73. package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
  74. package/assets/.appweaver/templates/delta-design-template.md +7 -5
  75. package/assets/.appweaver/templates/design-template.md +3 -0
  76. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  77. package/assets/.appweaver/templates/ui-design-template.md +6 -4
  78. package/assets/.claude/skills/appweaver/SKILL.md +7 -46
  79. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
  80. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.lane.json +6 -0
  81. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
  82. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.lane.json +6 -0
  83. package/assets/foundations/foundation.spec.template.txt +98 -0
  84. package/assets/foundations/java/Hexagonal/Hexagonal.lane.json +6 -0
  85. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +8 -1
  86. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
  87. package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
  88. package/assets/guardrails/README.md +31 -17
  89. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +25 -13
  90. package/assets/guardrails/project-specific/tech-rule-bindings.md +296 -0
  91. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
  92. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  93. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  94. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  95. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  96. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
  97. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  98. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  99. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
  100. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  101. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  102. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
  103. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  104. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  105. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  106. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  107. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  108. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  109. package/assets/guardrails/technology/nextjs/api-client.md +1 -1
  110. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  111. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  112. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  113. package/assets/guardrails/technology/nextjs/client-security.md +1 -1
  114. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  115. package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
  116. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  117. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  118. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  119. package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
  120. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  121. package/assets/guardrails/technology/nextjs/observability.md +1 -1
  122. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  123. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  124. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  125. package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
  126. package/package.json +1 -1
  127. package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
  128. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
  129. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
  130. package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
  131. package/assets/.kilocode/agent.json +0 -28
  132. package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
  133. package/assets/.kilocode/workflows/appweaver.md +0 -55
  134. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +0 -271
  135. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
  136. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
  137. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/service/technical-requirements.md +0 -0
@@ -17,11 +17,14 @@
17
17
  # against no declared stack invents its own.
18
18
  #
19
19
  # ONE COMMAND, TWO LANES, TWO RULE SETS. The lanes take their rules from different
20
- # headings of tech-rule-bindings (`## /aw-spec-plan` for the service, `## /aw-spec-plan-ui`
21
- # for the frontend), and the frontend set is loaded ONLY when that lane is declared — so
22
- # a backend-only project sees exactly the rules it did before. In a two-lane project both
23
- # sets are sticky for the whole run; the lane boundary is held by the prompts instead,
24
- # and §5 Contract Binding is where it is stated.
20
+ # headings of tech-rule-bindings (`## /aw-spec-plan-backend` for the service,
21
+ # `## /aw-spec-plan-frontend` for the frontend), and each set is loaded only when its lane
22
+ # is declared. The two are never loaded together: the service set loads at step 1, before
23
+ # the backend sections, and the frontend set REPLACES it at the lane swap before the
24
+ # frontend sections — tech_select_ui_master on the master path, the delta-plan module's
25
+ # own swap on the change path. Each plan is therefore authored with only its own lane's
26
+ # rule set in its envelope. Where the two plans meet is stated in the frontend plan's
27
+ # §5 Contract Binding, which binds to the service's published surface only.
25
28
  #
26
29
  # RENAMED FROM `design`. design.md → backend-plan.md, design.ui.md → frontend-plan.md,
27
30
  # and the former separate `design-ui` command is FOLDED IN here. The scaffold MIGRATES a
@@ -105,7 +108,7 @@ scripts:
105
108
 
106
109
  # Sticky standards seed = the UNIVERSAL always-on rule only (ai-rules). The TECHNICAL/
107
110
  # architecture rule files are CONFIGURATION, loaded per-command from
108
- # guardrails/projects/<project>/tech-rule-bindings.md by the tech-select module (see the
111
+ # guardrails/<project>/tech-rule-bindings.md by the tech-select module (see the
109
112
  # tech_select steps below), exactly as the DOMAIN rule files are loaded by domain-select.
110
113
  # Per the rule-partition this phase loads NO domain rule file — the domain reaches the
111
114
  # plan as spec ids (BR-/CN-/DC-/IC-) and as the context's domain model. The technology
@@ -179,7 +182,7 @@ vars:
179
182
  workflow:
180
183
 
181
184
  # 0. WHICH LANES EXIST. lane-resolve reads the declaration only — it does NOT check the
182
- # source path on disk, unlike the lane-gate module, because a plan is authored BEFORE
185
+ # lane root folder on disk, unlike the lane-gate module, because a plan is authored BEFORE
183
186
  # the code exists. That is the point of planning.
184
187
  - id: lane_resolve
185
188
  action: execute_script
@@ -201,18 +204,18 @@ workflow:
201
204
  action: verify_context
202
205
  require_true: lanes_declared
203
206
  on_false: stop
204
- on_false_message: "No lane is declared in .appweaver/stacks.json, so there is nothing to plan. Run /appweaver select-stack and declare the backend stack, the frontend stack, or both — plus each one's source path — then re-run plan. The declaration is what tells this phase which documents to write; a plan written against no declared stack invents its own."
207
+ on_false_message: "No lane is declared in .appweaver/stacks.json, so there is nothing to plan. Run /appweaver select-stack and declare the backend stack, the frontend stack, or both — plus each one's lane root folder — then re-run plan. The declaration is what tells this phase which documents to write; a plan written against no declared stack invents its own."
205
208
 
206
209
  # 1. TECHNICAL rule files → sticky standards (configuration, not hardcoded).
207
- # The service lane's set is loaded under `## /aw-spec-plan`; the frontend lane's under
208
- # `## /aw-spec-plan-ui`, and ONLY when that lane is declared — so a backend-only
210
+ # The service lane's set is loaded under `## /aw-spec-plan-backend`; the frontend lane's
211
+ # under `## /aw-spec-plan-frontend`, and ONLY when that lane is declared — so a backend-only
209
212
  # project's standards are exactly what they were before the two commands merged.
210
213
  # No blocking gate: an unconfigured project soft-continues (the constitutions still
211
214
  # carry each lane's ratified base).
212
215
  #
213
216
  # ONLY THE BACKEND'S RULES LOAD HERE. The frontend's used to load alongside them,
214
217
  # before either lane authored anything, and sticky standards only accumulate — so the
215
- # service plan was authored with `## /aw-spec-plan-ui` in its envelope and the
218
+ # service plan was authored with `## /aw-spec-plan-frontend` in its envelope and the
216
219
  # experience plan with the service set. Each prompt names its lane, but it said so
217
220
  # inside an envelope that contradicted it. The UI set now loads at the frontend
218
221
  # boundary instead, with `replace`, in both places a frontend document is authored:
@@ -222,7 +225,7 @@ workflow:
222
225
  condition: "{{be_declared}} == true"
223
226
  action: include
224
227
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
225
- with: { command: aw-spec-plan }
228
+ with: { command: aw-spec-plan-backend }
226
229
 
227
230
  # 2. Resolve the current feature and require its spec.
228
231
  - id: feature_paths
@@ -617,6 +620,10 @@ workflow:
617
620
  as field shapes. That section is the ONLY part of this document the frontend plan
618
621
  may read; keep it complete and self-contained, because a contract the UI needs and
619
622
  this document never states becomes a client-side workaround.
623
+ - NAME EVERY ENDPOINT. Each §3 endpoint carries an **Operation id** — its name in the
624
+ service's published API document (e.g. `CreatePatient`), unique across the
625
+ service and never reused. The frontend plan cites it, and implement gives the
626
+ endpoint exactly this id, so the two lanes meet on it.
620
627
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
621
628
  the spec): a NON-NEGOTIABLE technical principle you must apply that has NO
622
629
  per-feature spec id. APPLY it (it is non-negotiable), and because it is not
@@ -704,6 +711,10 @@ workflow:
704
711
  - PUBLISH THE SURFACE THE FRONTEND LANE BINDS TO: the section carrying this feature's
705
712
  endpoints states each contract as field shapes, completely, because it is the only
706
713
  part of this document the frontend plan may read.
714
+ - NAME EVERY ENDPOINT with its route, verb and operation id — its name in the
715
+ service's published API document, unique across the service. Where the code
716
+ already gives the endpoint one, record THAT id exactly as the code spells it; the
717
+ frontend plan cites it and implement finds the endpoint by it.
707
718
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
708
719
  the spec): a NON-NEGOTIABLE technical principle with no per-feature spec id —
709
720
  APPLY it, and LOG it as a §5 DA-n whose basis cites the mandating principle
@@ -773,6 +784,9 @@ workflow:
773
784
  workarounds are DECISIONS THIS TEAM MADE, not derivations from the spec — keep
774
785
  every one, with its id and its basis, unless the thing it decided about is gone.
775
786
  Never renumber a surviving entry: its id is cited elsewhere.
787
+ - OPERATION IDS ARE STABLE. Every endpoint keeps the operation id it already has —
788
+ the frontend plan and the built code both use it. A new endpoint gets one, unique
789
+ across the service; an endpoint without one gets one now.
776
790
  - THE CODE THAT EXISTS IS THE WHAT-IS AUTHORITY. {{source_count}} source file(s)
777
791
  realise this feature: {{source_files}}. READ them, and where the plan and the code
778
792
  disagree about STRUCTURE, the code is what is actually there — conform to it and
@@ -788,7 +802,7 @@ workflow:
788
802
  # ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
789
803
  # Both tech-select includes used to run up at step 4, before either lane authored
790
804
  # anything, and sticky standards only accumulate — so on a full-stack run the backend
791
- # plan was authored with `## /aw-spec-plan-ui` in its envelope and the frontend plan with
805
+ # plan was authored with `## /aw-spec-plan-frontend` in its envelope and the frontend plan with
792
806
  # the service set. Each prompt names its lane, but it did so inside an envelope that
793
807
  # contradicted it, and the envelope is the half the model cannot argue with.
794
808
  #
@@ -800,7 +814,7 @@ workflow:
800
814
  condition: "{{fe_mode}} != skip"
801
815
  action: include
802
816
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
803
- with: { command: aw-spec-plan-ui, replace: "true" }
817
+ with: { command: aw-spec-plan-frontend, replace: "true" }
804
818
 
805
819
  # ═══════════ FRONTEND LANE — bootstrap, greenfield experience template ═══════
806
820
  # The experience twin of the service plan, and the MEDIATOR between spec.md and the
@@ -867,6 +881,10 @@ workflow:
867
881
  DELTA raised back to the service lane under "Contract deltas needed" — never a
868
882
  workaround in the client. Where no service plan is in context, bind from the
869
883
  spec's IC- surface and record that as a §8 DA-n.
884
+ - EVERY §5 ROW CITES ITS OPERATION ID, copied exactly from the endpoint's
885
+ **Operation id** in the backend plan's §3 — implement looks the endpoint up by it
886
+ in the service's exported API document. Where no service plan names one, write
887
+ `—` and record it in the same §8 DA-n.
870
888
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded UI constitution, NOT the
871
889
  spec): a NON-NEGOTIABLE UX principle you must apply that has no per-feature spec
872
890
  id. APPLY it, and because it is not spec-derived, LOG it as a §8 DA-n whose
@@ -952,6 +970,9 @@ workflow:
952
970
  states. Cite them; do not restate, re-derive or contradict them, and introduce no
953
971
  server-side behaviour. What the experience needs and the surface lacks is a
954
972
  contract delta raised back to the service lane, never a client workaround.
973
+ - EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan —
974
+ implement looks the endpoint up by it in the service's exported API document.
975
+ Where no service plan names one, write `—` and record it as a DA-n.
955
976
  - CONSTITUTION-MANDATED CROSS-CUTTING with no per-feature spec id: apply it, and
956
977
  log it as a DA-n citing the mandating principle ("per constitution.ui.md
957
978
  UX-<n>"). Do not fabricate a spec id for it and do not leave it uncited.
@@ -1010,6 +1031,9 @@ workflow:
1010
1031
  — the spec's IC- ids and, where the backend plan is in context, the API contracts
1011
1032
  it states. What the experience needs and the surface lacks is a contract delta
1012
1033
  raised back to the service lane, never a client workaround.
1034
+ - EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan; a
1035
+ row that has none yet gets it now, and a row whose id the backend plan no longer
1036
+ has is re-bound. Where no service plan names one, write `—` with a DA-n.
1013
1037
  - TECHNOLOGY-AGNOSTIC: no framework, router, state library, component library or
1014
1038
  styling approach — responsibilities, field shapes, events and states only.
1015
1039
  - ADD ONE Change History row for this re-derivation, describing what MOVED and why.
@@ -32,7 +32,7 @@ scripts:
32
32
  # operating rules, which is where "never run a migration against a shared environment"
33
33
  # lives. The technical rule file
34
34
  # the migration step works against (persistence) is now CONFIGURATION, loaded per-command from
35
- # guardrails/projects/<project>/tech-rule-bindings.md under "## /aw-spec-run" by the tech-select
35
+ # guardrails/<project>/tech-rule-bindings.md under "## /aw-spec-run" by the tech-select
36
36
  # module (see the tech_select step below). No domain files; run does not reference
37
37
  # constitution.technical.md. (missing files skipped at assembly time)
38
38
  standards:
@@ -44,7 +44,7 @@ vars:
44
44
  workflow:
45
45
 
46
46
  # 0. TECHNICAL rule files → sticky standards (configuration, not hardcoded). tech-select
47
- # reads guardrails/projects/<project>/tech-rule-bindings.md under "## /aw-spec-run" and loads
47
+ # reads guardrails/<project>/tech-rule-bindings.md under "## /aw-spec-run" and loads
48
48
  # that set (persistence) into the sticky standards the agent_generate migration step ALWAYS
49
49
  # prepends. No domain rule file here. No blocking gate: an unconfigured project soft-continues.
50
50
  - id: tech_select
@@ -66,8 +66,8 @@ workflow:
66
66
  on_empty: stop
67
67
  on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run run."
68
68
 
69
- # Require the SERVICE LANE and its source path. Migrations belong to the backend
70
- # lane by definition, and run-migrate searches that lane's root for the project
69
+ # Require the SERVICE LANE and its lane root folder. Migrations belong to the backend
70
+ # lane by definition, and run-migrate searches that lane root folder for the project
71
71
  # instead of assuming `src/` — which is what lets a repo whose service code sits
72
72
  # in `Legacy/App/` or `backend/` find its own migrations.
73
73
  - id: lane_gate
@@ -24,6 +24,9 @@
24
24
  # list-contexts → user_select (existing | "+ create new") → [ask name] → set-context
25
25
  #
26
26
  # Persists .appweaver/context.json {"context":"<Name>","context_directory":"specs/<Name>"}.
27
+ # When the chosen context does not contain the active feature, set-context also clears
28
+ # .appweaver/feature.json, so specify and every later stage stop until select-feature
29
+ # picks a feature inside the new context.
27
30
  #
28
31
  # Launch:
29
32
  # /appweaver select-bounded-context # interactive: list + add-new
@@ -32,7 +35,7 @@
32
35
 
33
36
  name: aw-spec-select-bounded-context
34
37
  description: Pick an existing bounded context or create a new one, and store it in .appweaver/context.json so select-feature nests its features inside it and every spec in the context shares one domain-model.md. Zero LLM — scripts + one selection only.
35
- version: 1.0.0
38
+ version: 1.1.0
36
39
  agent_agnostic: true
37
40
  dialect: aw-spec.orchestrator/v1
38
41
 
@@ -51,6 +54,8 @@ vars:
51
54
  new_sentinel: "+ Create a new bounded context" # source of truth is list-contexts $.sentinel; overwritten below
52
55
  typed_name: ""
53
56
  target_name: ""
57
+ feature_cleared: "false"
58
+ cleared_feature: ""
54
59
 
55
60
  workflow:
56
61
 
@@ -120,6 +125,23 @@ workflow:
120
125
  - { name: existed, from: "$.existed" }
121
126
  - { name: created, from: "$.created" }
122
127
  - { name: domain_model_exists, from: "$.domain_model_exists" }
128
+ - { name: feature_cleared, from: "$.feature_cleared" }
129
+ - { name: cleared_feature, from: "$.cleared_feature" }
130
+
131
+ # 6. Say when the active feature was cleared: every feature-scoped stage stops until
132
+ # select-feature runs. The never-satisfiable `equals` is the engine's announce-only
133
+ # idiom: the step is entered only when a feature was cleared, and the comparison
134
+ # always misses, so the message is emitted and the run continues.
135
+ - id: feature_cleared_notice
136
+ action: verify_context
137
+ condition: "{{feature_cleared}} == true"
138
+ require_value: feature_cleared
139
+ equals: "never"
140
+ on_mismatch: continue
141
+ on_mismatch_message: >
142
+ The previously active feature {{cleared_feature}} is not in {{context}}, so it is
143
+ no longer active. Run /appweaver select-feature to pick or create a feature in
144
+ {{context_dir}}/ before specify or any later stage.
123
145
 
124
146
  outputs:
125
147
  context: "{{context}}"
@@ -128,5 +150,7 @@ outputs:
128
150
  domain_model_exists: "{{domain_model_exists}}"
129
151
  created: "{{created}}"
130
152
  legacy_features: "{{legacy_features}}"
131
- note: "Active bounded context set in .appweaver/context.json. select-feature now creates and lists features inside {{context_dir}}/, and every spec there shares {{domain_model}} as its domain model. Features already sitting flat under specs/ are listed as legacy_features — they keep working exactly as before and are not moved; re-run select-feature after selecting a context to place new work inside it."
153
+ feature_cleared: "{{feature_cleared}}"
154
+ cleared_feature: "{{cleared_feature}}"
155
+ note: "Active bounded context set in .appweaver/context.json. select-feature now creates and lists features inside {{context_dir}}/, and every spec there shares {{domain_model}} as its domain model. When the previously active feature is not in this context, .appweaver/feature.json is cleared (feature_cleared true, cleared_feature names it) and specify and every later stage stop until select-feature runs. Features already sitting flat under specs/ are listed as legacy_features — they are not moved; re-run select-feature after selecting a context to place new work inside it."
132
156
  next: "/appweaver select-feature (creates {{context_dir}}/<Feature>/, then specify)"
@@ -1,9 +1,14 @@
1
1
  # =============================================================================
2
- # aw-spec-select-domain (orchestrator) — select the active PROJECT under guardrails/projects/
2
+ # aw-spec-select-domain (orchestrator) — select the active PROJECT folder under guardrails/
3
3
  #
4
4
  # The command name and .appweaver/domain.json are historical: what is selected is a
5
5
  # project folder, and a project is bound to rules by its two maps, not by an industry.
6
6
  #
7
+ # OPTIONAL: no sequence runs it. domain.json ships naming guardrails/project-specific/ and
8
+ # onboard points it at the guardrails/brf-<domain>/ it creates; this command switches to
9
+ # any other project folder that already exists (e.g. a copy of project-specific). It never
10
+ # creates one — a name with no folder is not offered, and the user picks from the list.
11
+ #
7
12
  # Pure orchestration/governance, NO generation: scripts + one gate + one HITL select.
8
13
  # Exercises the D1 interaction channel: under ANY strategy the `user_select`
9
14
  # step suspends via --checkpoint (kind 'select') so the LAUNCHING agent asks
@@ -17,14 +22,14 @@
17
22
  # =============================================================================
18
23
 
19
24
  name: aw-spec-select-domain
20
- description: Select the active project under guardrails/projects/ and store it in .appweaver/domain.json, binding both of that project's rule maps — domain-rule-bindings.md and tech-rule-bindings.md — so every AW-Spec command loads the right domain AND technical rule files.
21
- version: 1.0.0
25
+ description: Switch the active project — a folder under guardrails/ that holds the rule maps — by storing its name in .appweaver/domain.json, binding both of that project's rule maps (domain-rule-bindings.md and tech-rule-bindings.md) so every AW-Spec command loads that project's domain AND technical rule files. Optional; domain.json names guardrails/project-specific/ by default.
26
+ version: 1.1.0
22
27
  agent_agnostic: true
23
28
  dialect: aw-spec.orchestrator/v1
24
29
 
25
30
  inputs:
26
31
  user_input:
27
- description: Optional project folder name under guardrails/projects/ to set directly (e.g. dotnet-default-project). An industry name is not a valid value — an industry is a corpus a project's map points at, never a selection.
32
+ description: Optional project folder name under guardrails/ to set directly (e.g. project-specific). The folder must already exist and hold a rule map; any other name shows the list of projects instead. An industry name is not a valid value — an industry is a corpus a project's map points at, never a selection.
28
33
  required: false
29
34
  bind: USER_INPUT
30
35
 
@@ -35,7 +40,7 @@ scripts:
35
40
 
36
41
  workflow:
37
42
 
38
- # 1. Discover candidate projects = subdirs of guardrails/projects/ carrying a rule map.
43
+ # 1. Discover candidate projects = top-level folders of guardrails/ carrying a rule map.
39
44
  - id: list_domains
40
45
  action: execute_script
41
46
  script: { ref: actions }
@@ -43,21 +48,22 @@ workflow:
43
48
  outputs:
44
49
  - { name: domains, from: "$.domains" }
45
50
 
46
- # 2. Stop early if there are no domains to choose from.
51
+ # 2. Stop early if there are no projects to choose from.
47
52
  - id: guard_no_domains
48
53
  action: verify_context
49
54
  require_non_empty: domains
50
55
  on_empty_message: >
51
- No governed projects found. Copy guardrails/projects/dotnet-default-project/ to
52
- guardrails/projects/<name>/ and repoint its two maps at the technology and domain
53
- corpora this project uses, then re-run.
56
+ No project folders found under guardrails/. Copy guardrails/project-specific/ to
57
+ guardrails/<name>/, change the guardrails/project-specific/ paths inside its two maps
58
+ to guardrails/<name>/, repoint the maps at the technology and domain corpora this
59
+ project uses, then re-run.
54
60
  on_empty: stop
55
61
 
56
- # 3. Choose the domain. If USER_INPUT names a valid domain it is used directly;
62
+ # 3. Choose the project. If USER_INPUT names a listed project it is used directly;
57
63
  # otherwise the launcher relays the choice to the user. One option => confirm.
58
64
  - id: select_domain
59
65
  action: user_select
60
- prompt: "Select the active domain:"
66
+ prompt: "Select the active project:"
61
67
  options_from_variable: domains
62
68
  preselect_from: USER_INPUT # direct-argument fast path
63
69
  single_option_confirm: true
@@ -79,7 +85,7 @@ outputs:
79
85
  domain: "{{domain}}"
80
86
  domain_rule_bindings: "{{map_path}}"
81
87
  domain_rule_bindings_exists: "{{map_exists}}"
82
- note: "Active project '{{domain}}' persisted to .appweaver/domain.json. It selects TWO rule maps under guardrails/projects/{{domain}}/ — domain-rule-bindings.md (DOMAIN rules; read by constitution + specify only, because the spec is the pivot) and tech-rule-bindings.md (TECHNICAL rules; read by 10 workflows incl. design, implement, build and run). The rule FILES themselves live in shared corpora — guardrails/technology/<stack>/ and guardrails/domain/<industry>/ — and the maps are what bind this project to them, so two projects can share a corpus and differ only in their maps and their own three requirements files. domain_rule_bindings_exists reports the domain half only. A map that is absent, or a command with no heading in one, loads nothing for that class and SOFT-CONTINUES — an absent heading is a valid state, never a failure."
83
- # constitution comes BEFORE select-feature: it reads the domain rule map this
84
- # workflow just bound, and specify declares its domain half as REQUIRED context.
85
- next: "/appweaver constitution → select-feature → specify. /appweaver constitution authors the constitution halves from the domain rule map this run just bound — specify declares constitution.domain.md as REQUIRED context, and plan and implement read constitution.technical.md (plus constitution.ui.md on a frontend lane), so it runs before the first feature rather than after. /appweaver select-feature then picks the feature to build; every stage from specify onward reads that active feature and stops without it. Re-run /appweaver select-domain any time to switch projects; it rebinds both maps at once, and /appweaver constitution picks the new bindings up on its next run."
88
+ note: "Active project '{{domain}}' persisted to .appweaver/domain.json. It selects TWO rule maps under guardrails/{{domain}}/ — domain-rule-bindings.md (DOMAIN rules; read by constitution + specify only, because the spec is the pivot) and tech-rule-bindings.md (TECHNICAL rules; read by the HOW phases incl. foundation's spec builds, plan, implement, build and run). The rule FILES themselves live in shared corpora — guardrails/technology/<stack>/ and guardrails/domain/<industry>/ — and the maps are what bind this project to them, so two projects can share a corpus and differ only in their maps and their own three requirements files. domain_rule_bindings_exists reports the domain half only. A map that is absent, or a command with no heading in one, loads nothing for that class and SOFT-CONTINUES — an absent heading is a valid state, never a failure."
89
+ # constitution reads the domain rule map this workflow just bound; the halves it
90
+ # already wrote stay as they are until it runs again.
91
+ next: "Switching the project changes which rule files later commands load; it does not rewrite anything already written. Re-run /appweaver constitution so constitution.domain.md, constitution.technical.md and constitution.ui.md are authored from the new project's rules — specify declares constitution.domain.md as REQUIRED context, and plan and implement read constitution.technical.md (plus constitution.ui.md on a frontend lane). Specs and plans already written keep the rules they were written under. GREENFIELD with no project scaffolded yet: /appweaver foundation first — a lane built from a spec follows the technical rules this run just bound (`## /aw-spec-foundation-backend` / `## /aw-spec-foundation-frontend`) — then /appweaver constitution → specify. To add another project, copy guardrails/project-specific/ to guardrails/<name>/, change the guardrails/project-specific/ paths inside its two maps to guardrails/<name>/, and run /appweaver select-domain <name>. Re-run /appweaver select-domain any time to switch back; it rebinds both maps at once."
@@ -14,12 +14,12 @@
14
14
  # evidence sits in, and both are only ever proposals — an operator selects from the
15
15
  # list or types a path the kit has never seen.
16
16
  #
17
- # stack-list --suggest backend → select stack → stack-list --profile → ask source path → lane-declare
18
- # stack-list --suggest frontend → select stack → stack-list --profile → ask source path → lane-declare
17
+ # stack-list --suggest backend → select stack → stack-list --profile → ask lane root folder → lane-declare
18
+ # stack-list --suggest frontend → select stack → stack-list --profile → ask lane root folder → lane-declare
19
19
  #
20
20
  # THE SOURCE-PATH OPTIONS ARE BUILT AFTER THE STACK IS CHOSEN. Most profiles of a kind
21
- # share a default root (six frontend stacks default to web/), so a list built before the
22
- # choice cannot say which stack an option belongs to. The second stack-list call answers
21
+ # share a default root (every backend stack defaults to backend/, every frontend stack to
22
+ # frontend/), so a list built before the choice cannot say which stack an option belongs to. The second stack-list call answers
23
23
  # for the chosen stack alone.
24
24
  #
25
25
  # (none) IS A REAL ANSWER FOR EITHER LANE, and it is how a project says "I do not
@@ -34,7 +34,7 @@
34
34
  # lane a person already declared. Every other workflow calls `lane-resolve` to read
35
35
  # and `lane-verify` to gate, and neither can write.
36
36
  #
37
- # WHY THE SOURCE PATH IS ASKED AND NOT INHERITED. A lane's root is the subtree it
37
+ # WHY THE LANE ROOT FOLDER IS ASKED AND NOT INHERITED. A lane root folder is the subtree its lane
38
38
  # OWNS: the only place implement's lane for it may write, the directory its build and
39
39
  # run commands act on, and in brownfield the code onboard reads. A profile's default
40
40
  # root describes how a NEW project of that stack is usually laid out, which is a
@@ -60,7 +60,7 @@
60
60
  # =============================================================================
61
61
 
62
62
  name: aw-spec-select-stack
63
- description: Declare the project's lanes — each lane's STACK and its SOURCE PATH — and persist them to .appweaver/stacks.json, the single channel every later workflow resolves and gates on. The first command of both the greenfield and the brownfield sequence, and the sole writer of the lane model.
63
+ description: Declare the project's lanes — each lane's STACK and its LANE ROOT FOLDER — and persist them to .appweaver/stacks.json, the single channel every later workflow resolves and gates on. The first command of both the greenfield and the brownfield sequence, and the sole writer of the lane model.
64
64
  version: 2.3.0
65
65
  agent_agnostic: true
66
66
  dialect: aw-spec.orchestrator/v1
@@ -139,7 +139,7 @@ workflow:
139
139
  # 5. WHERE the service lane's source lives. Offered best-first for the CHOSEN stack —
140
140
  # where its evidence sits, then its own default, then where another stack's
141
141
  # evidence sits — and free text is accepted, because a repo that matches no
142
- # profile still has a source path. The label after the path says why it is
142
+ # profile still has a lane root folder. The label after the path says why it is
143
143
  # offered and is stripped on the way in.
144
144
  - id: list_api_roots
145
145
  action: execute_script
@@ -153,7 +153,7 @@ workflow:
153
153
  - id: ask_api_source_path
154
154
  action: ask
155
155
  condition: "{{api_selected}}"
156
- prompt: "Service lane SOURCE PATH — the subtree this lane owns, where implement writes its code, and the directory build/test/run act on. Its tests go to the stack's test path beside it (tests/ next to src/ for .NET), shown in the summary. Pick one or type your own:"
156
+ prompt: "Service LANE ROOT FOLDER — the subtree this lane owns, where implement writes its code, and the directory build/test/run act on. Its tests go to the stack's test path — inside it for a new project (backend/tests/ for .NET), beside it in a classic layout (tests/ next to src/) — shown in the summary. Pick one or type your own:"
157
157
  options_from_variable: api_root_options
158
158
  answer_var: api_source_path
159
159
 
@@ -224,7 +224,7 @@ workflow:
224
224
  - id: ask_ui_source_path
225
225
  action: ask
226
226
  condition: "{{ui_selected}}"
227
- prompt: "UI lane SOURCE PATH — the subtree this lane owns, the only place implement's frontend lane may write. It must not overlap the service lane's. Pick one or type your own:"
227
+ prompt: "UI LANE ROOT FOLDER — the subtree this lane owns, the only place implement's frontend lane may write. It must not overlap the service lane's. Pick one or type your own:"
228
228
  options_from_variable: ui_root_options
229
229
  answer_var: ui_source_path
230
230
 
@@ -243,7 +243,7 @@ workflow:
243
243
 
244
244
  # ═══════════════ CHECK + REPORT ═════════════════════════════════════════════
245
245
 
246
- # 10. Is what was just written sound? --allow-missing-root because a source path
246
+ # 10. Is what was just written sound? --allow-missing-root because a lane root folder
247
247
  # declared here legitimately does not exist yet; what this catches is a lane
248
248
  # declared with NO path at all, which no later phase could act on. The on-disk
249
249
  # check belongs to the phases that read the subtree, and runs there.
@@ -279,7 +279,7 @@ workflow:
279
279
  - id: api_summary_lane
280
280
  action: set
281
281
  condition: "{{api_declared}}"
282
- vars: { api_summary: "{{api_lane_id}} ({{api_profile}}) at {{api_root}}, tests at {{api_test_path}} — source path exists: {{api_root_exists}}" }
282
+ vars: { api_summary: "{{api_lane_id}} ({{api_profile}}) at {{api_root}}, tests at {{api_test_path}} — lane root folder exists: {{api_root_exists}}" }
283
283
 
284
284
  - id: ui_summary_none
285
285
  action: set
@@ -287,7 +287,7 @@ workflow:
287
287
  - id: ui_summary_lane
288
288
  action: set
289
289
  condition: "{{ui_declared}}"
290
- vars: { ui_summary: "{{ui_lane_id}} ({{ui_profile}}) at {{ui_root}}, tests at {{ui_test_path}} — source path exists: {{ui_root_exists}}" }
290
+ vars: { ui_summary: "{{ui_lane_id}} ({{ui_profile}}) at {{ui_root}}, tests at {{ui_test_path}} — lane root folder exists: {{ui_root_exists}}" }
291
291
 
292
292
  # 12. Read the finished declaration back through the reader every later workflow
293
293
  # uses, so what this run reports is what they will resolve.
@@ -316,5 +316,5 @@ outputs:
316
316
  api_detected: "{{api_detected}}"
317
317
  ui_detected: "{{ui_detected}}"
318
318
  prototype: "{{prototype}}"
319
- note: "Lanes persisted to .appweaver/stacks.json. Each lane carries a STACK and a SOURCE PATH, and both are load-bearing. The SOURCE PATH is ownership: implement's service lane writes its code only under the service lane's and its frontend lane only under the UI lane's, build/test/run act on it, and onboard reverse-engineers out of it. Each lane also owns a TEST PATH, taken from its stack profile — tests/ beside a .NET src/, the source path itself for a stack that keeps its tests inside — and implement writes the lane's tests there. Overlapping paths of either kind are refused here rather than discovered later as two generators writing one file. The build/test/run commands are project-supplied strings the engine shells out to, which is how it stays stdlib-only and stack-ignorant. api_detected / ui_detected report what this repo's own files pointed at, whether or not it was chosen, as "<stack> at <path>" — or "nothing detected" on a greenfield repo with nothing to detect. A source path that does not exist yet is NORMAL here and reported rather than refused: greenfield declares src/ before implement creates it. The on-disk check runs in the phases that read the subtree — implement, build, run and onboard all call lane-verify and STOP with the fix named. Declining a lane with (none) is a real declaration and removes any lane of that kind a previous run left behind; it is also what stops that lane's constitution half and rule files being authored. `prototype` is not a lane — it has a root and a run command so an operator can open it, and nothing else. Re-run this workflow any time to re-stack a lane, move a source path, or drop a lane with (none); it is the only workflow that may write this file."
320
- next: "GREENFIELD: /appweaver foundation — once per lane, to scaffold a compiling project into each source path declared here (skip it for a lane whose code already exists, or scaffold with the stack's own tooling) — then /appweaver select-domain → constitution → select-feature → specify. BROWNFIELD: /appweaver inventory — it scans the source paths declared here and proposes the bounded contexts and features as specs/proposed-inventory.md; edit that map, run /appweaver inventory apply, then /appweaver onboard <Context> once per bounded context, which reverse-engineers the governance out of the same source paths and activates it (no select-domain; onboard derives it from the code). Run this workflow FIRST in either sequence: foundation unpacks into the source paths declared here, constitution reads the declaration to decide which halves to author, and inventory and onboard read it to decide what to scan."
319
+ note: "Lanes persisted to .appweaver/stacks.json. Each lane carries a STACK and a LANE ROOT FOLDER, and both are load-bearing. The LANE ROOT FOLDER is ownership: implement's service lane writes its code only under the service lane's and its frontend lane only under the UI lane's, build/test/run act on it, and onboard reverse-engineers out of it. Each lane also owns a TEST PATH, taken from its stack profile — tests/ beside a .NET src/, the lane root folder itself for a stack that keeps its tests inside — and implement writes the lane's tests there. Overlapping paths of either kind are refused here rather than discovered later as two generators writing one file. The build/test/run commands are project-supplied strings the engine shells out to, which is how it stays stdlib-only and stack-ignorant. api_detected / ui_detected report what this repo's own files pointed at, whether or not it was chosen, as '<stack> at <path>' — or 'nothing detected' on a greenfield repo with nothing to detect. A lane root folder that does not exist yet is NORMAL here and reported rather than refused: greenfield declares src/ before implement creates it. The on-disk check runs in the phases that read the subtree — implement, build, run and onboard all call lane-verify and STOP with the fix named. Declining a lane with (none) is a real declaration and removes any lane of that kind a previous run left behind; it is also what stops that lane's constitution half and rule files being authored. `prototype` is not a lane — it has a root and a run command so an operator can open it, and nothing else. Re-run this workflow any time to re-stack a lane, move a lane root folder, or drop a lane with (none); it is the only workflow that may write this file."
320
+ next: "GREENFIELD: /appweaver foundation → constitution → specify. The project rules live in guardrails/project-specific/, which .appweaver/domain.json names by default — fill in its rule files and its two maps; /appweaver select-domain switches to another project folder under guardrails/ when you keep more than one. On a project with no specs yet, constitution creates the default bounded context MainContext and its feature CoreFeature and makes both active; to use your own names, run /appweaver select-bounded-context <Name> and then /appweaver select-feature <Name> before specify. Once any bounded context exists, select-feature refuses to run until one is selected. foundation scaffolds every lane declared here in one run, backend then frontend — from a verified pack, from a spec the agent builds the project from, or skipped for a lane whose code already exists — and a spec build follows the technical rules the active project maps under `## /aw-spec-foundation-backend` and `## /aw-spec-foundation-frontend`. BROWNFIELD: /appweaver inventory — it scans the lane root folders declared here and proposes the bounded contexts and features as specs/proposed-inventory.md; edit that map, run /appweaver inventory apply, then /appweaver onboard <Context> once per bounded context, which reverse-engineers the governance out of the same lane root folders and activates it: onboard creates guardrails/brf-<domain>/ from the code and names it in .appweaver/domain.json. Run this workflow FIRST in either sequence: foundation scaffolds into the lane root folders declared here, constitution reads the declaration to decide which halves to author, and inventory and onboard read it to decide what to scan."
@@ -93,7 +93,7 @@ scripts:
93
93
  # Sticky standards seed = the UNIVERSAL always-on rule only (ai-rules). Specify's ONE
94
94
  # technical input — the MODELLING METHODOLOGY (DDD tactical patterns) — is no longer
95
95
  # hardcoded here: it is now CONFIGURATION, loaded per-command from
96
- # guardrails/projects/<project>/tech-rule-bindings.md by the tech-select module (see the
96
+ # guardrails/<project>/tech-rule-bindings.md by the tech-select module (see the
97
97
  # tech_select step below), exactly as the DOMAIN rule files are loaded by domain-select.
98
98
  # Per the rule-partition that heading may carry a modelling methodology ONLY — never an
99
99
  # architecture / persistence / codegen file; those belong to design + implement, and
@@ -193,7 +193,7 @@ workflow:
193
193
  - { name: next_wave, from: "$.next_wave" }
194
194
 
195
195
  # 2. TECHNICAL rule files → sticky standards (configuration, not hardcoded).
196
- # tech-select reads guardrails/projects/<project>/tech-rule-bindings.md under
196
+ # tech-select reads guardrails/<project>/tech-rule-bindings.md under
197
197
  # "## /aw-spec-specify" and loads that set. Per the rule-partition that heading is
198
198
  # the MODELLING-METHODOLOGY slot only (DDD tactical patterns) — it must never list an
199
199
  # architecture / persistence / codegen file, which would break specify's domain purity.
@@ -643,7 +643,7 @@ workflow:
643
643
  action: verify_context
644
644
  require_true: nn_compliant
645
645
  on_false: stop
646
- on_false_message: "The answer to \"{{c.question}}\" departs from NON-NEGOTIABLE principle {{nn_principle}}: {{nn_why}}. That principle is ratified in .appweaver/memory/ and this answer has no approver — it was settled in this run, not by a domain owner, and the constitution's Governance section holds that a deviation with no named approver is a defect rather than a decision. Re-run specify and answer in a way the principle allows; if the project genuinely intends to depart from it, amend the constitution through its own amendment process FIRST (which names the approver the departure needs) and re-run. Nothing was written to {{quality_target}} for this clarification."
646
+ on_false_message: "The answer to '{{c.question}}' departs from NON-NEGOTIABLE principle {{nn_principle}}: {{nn_why}}. That principle is ratified in .appweaver/memory/ and this answer has no approver — it was settled in this run, not by a domain owner, and the constitution's Governance section holds that a deviation with no named approver is a defect rather than a decision. Re-run specify and answer in a way the principle allows; if the project genuinely intends to depart from it, amend the constitution through its own amendment process FIRST (which names the approver the departure needs) and re-run. Nothing was written to {{quality_target}} for this clarification."
647
647
 
648
648
  - id: resolve_clar
649
649
  action: agent_author
@@ -115,9 +115,9 @@ workflow:
115
115
  context:
116
116
  - "{{feature_dir}}/ui/workflow-model.md"
117
117
  - "{{spec_file}}"
118
- - { path: "guardrails/projects/{{domain}}/frontend/design.md", optional: true }
119
- - { path: "guardrails/projects/{{domain}}/frontend/DESIGN.md", optional: true }
120
- - { path: "guardrails/projects/{{domain}}/frontend/ui-requirements.md", optional: true }
118
+ - { path: "guardrails/{{domain}}/frontend/design.md", optional: true }
119
+ - { path: "guardrails/{{domain}}/frontend/DESIGN.md", optional: true }
120
+ - { path: "guardrails/{{domain}}/frontend/ui-requirements.md", optional: true }
121
121
  - { path: ".appweaver/templates/ui-model-template.md", optional: true }
122
122
  - { path: ".appweaver/memory/constitution.ui.md", optional: true }
123
123
 
@@ -141,9 +141,9 @@ workflow:
141
141
  - { path: "{{domain_model}}", optional: true }
142
142
  - { path: "{{feature_dir}}/ui/workflow-model.md", optional: true }
143
143
  - { path: "{{feature_dir}}/ui/ui-model.md", optional: true }
144
- - { path: "guardrails/projects/{{domain}}/frontend/design.md", optional: true }
145
- - { path: "guardrails/projects/{{domain}}/frontend/DESIGN.md", optional: true }
146
- - { path: "guardrails/projects/{{domain}}/frontend/ui-requirements.md", optional: true }
144
+ - { path: "guardrails/{{domain}}/frontend/design.md", optional: true }
145
+ - { path: "guardrails/{{domain}}/frontend/DESIGN.md", optional: true }
146
+ - { path: "guardrails/{{domain}}/frontend/ui-requirements.md", optional: true }
147
147
  - { path: ".appweaver/memory/constitution.domain.md", optional: true }
148
148
  - { path: ".appweaver/memory/constitution.ui.md", optional: true }
149
149
  - { path: "{{feature_dir}}/changes/{{active_change}}/delta-spec.md", optional: true }
@@ -254,7 +254,7 @@ workflow:
254
254
  The feature specification is taken directly from the bounded context directory and feature path defined in `.appweaver/feature.json`:
255
255
  `{{spec_file}}` (Bounded Context: `{{context_name}}`, Feature: `{{feature_name}}`).
256
256
  Read this specification strictly from `{{spec_file}}`, along with the bounded context's canonical domain model (`{{domain_model}}`),
257
- the project Design System if present (`guardrails/projects/{{domain}}/frontend/design.md` or `DESIGN.md`, or `{{feature_dir}}/ui/design.md`),
257
+ the project Design System if present (`guardrails/{{domain}}/frontend/design.md` or `DESIGN.md`, or `{{feature_dir}}/ui/design.md`),
258
258
  and when available, the Workflow Model (`{{feature_dir}}/ui/workflow-model.md`) and UI Model (`{{feature_dir}}/ui/ui-model.md`), plus `{{prototype_root}}/lib/screens-registry.ts` / `screens.json`.
259
259
  If `workflow-model.md` and `ui-model.md` are not provided, derive all UI surfaces, workflows, and interaction states directly from `{{spec_file}}`.
260
260
 
@@ -342,7 +342,7 @@ workflow:
342
342
  Tailwind/CSS config from the shell is intact. If it's missing or broken, fix it
343
343
  as part of this run and note that in your final summary; don't build a styled-looking
344
344
  screen on top of a broken/absent styling pipeline.
345
- - If a project visual design system is present in context (`guardrails/projects/{{domain}}/frontend/design.md` or `DESIGN.md`),
345
+ - If a project visual design system is present in context (`guardrails/{{domain}}/frontend/design.md` or `DESIGN.md`),
346
346
  apply its visual design tokens (colors, accent, surface, border, typography, card elevation, and status states)
347
347
  consistently across all cards, badges, buttons, forms, and headers on this screen.
348
348
  - Use the shell's existing design tokens and Tailwind utility classes (or whatever
@@ -386,7 +386,7 @@ workflow:
386
386
  - Generate or update `{{feature_dir}}/ui/ui-spec.md` alongside the prototype code.
387
387
  - Format as a markdown document with a brief title and capture intro, followed by a SINGLE fenced `json` code block adhering strictly to the JSON schema defined in `skill/references/output-ui-spec.md`:
388
388
  - `screen`: user-facing screen name and route
389
- - `captureNotes`: viewport width, CSS px, DPR, and design system token origin (`guardrails/projects/{{domain}}/frontend/DESIGN.md` or `design.md`)
389
+ - `captureNotes`: viewport width, CSS px, DPR, and design system token origin (`guardrails/{{domain}}/frontend/DESIGN.md` or `design.md`)
390
390
  - `regions`: ordered list of UI regions (nav-bar, header, step-card, content, dialogs, drawers) with `layout` (`position`, `wrap`, `direction`) and `elements` array
391
391
  - `elements`: each element detailing `id`, `kind` (`text`, `button`, `badge`, `avatar`, `card`, `input`, etc.), verbatim `content`, `style` (`shape`, `colorToken`, `typographyToken`, `spacingPx`), `state` (`default`, `active`, `hover`), and `fields`
392
392
  - `navigation`: ordered nav items, activeItem, activeStyle