aw-spec-cli 0.1.26 → 0.1.27

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 (98) 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 +3 -3
  4. package/assets/.appweaver/STACK-PROFILES.md +188 -101
  5. package/assets/.appweaver/domain.json +1 -1
  6. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
  7. package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
  8. package/assets/.appweaver/orchestrator/README.md +120 -53
  9. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
  10. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
  11. package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
  12. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +349 -0
  13. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +381 -0
  14. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
  15. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
  16. package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
  17. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
  18. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  19. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +5 -5
  20. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
  21. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +14 -14
  22. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
  23. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  24. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
  25. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +13 -13
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  31. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +29 -28
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +53 -53
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  37. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +3 -3
  38. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
  39. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
  40. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
  41. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
  42. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +2 -2
  43. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
  44. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
  45. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +284 -128
  46. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +224 -70
  47. package/assets/.appweaver/scripts/python/aw-foundation.py +809 -20
  48. package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
  49. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
  50. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
  51. package/assets/.appweaver/scripts/python/aw-stack.py +195 -89
  52. package/assets/.appweaver/stack-profiles/angular.json +2 -1
  53. package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
  54. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +16 -3
  55. package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
  56. package/assets/.appweaver/stack-profiles/java-spring.json +12 -5
  57. package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
  58. package/assets/.appweaver/stack-profiles/node-express.json +8 -2
  59. package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
  60. package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
  61. package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
  62. package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
  63. package/assets/.appweaver/stacks.json +37 -1
  64. package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
  65. package/assets/.claude/skills/appweaver/SKILL.md +7 -46
  66. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
  67. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
  68. package/assets/foundations/foundation.spec.template.txt +73 -0
  69. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +1 -1
  70. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
  71. package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
  72. package/assets/guardrails/README.md +31 -17
  73. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +5 -5
  74. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/tech-rule-bindings.md +151 -114
  75. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
  76. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
  77. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
  78. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  79. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
  80. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  81. package/assets/guardrails/technology/nextjs/api-client.md +1 -1
  82. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  83. package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
  84. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  85. package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
  86. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  87. package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
  88. package/package.json +1 -1
  89. package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
  90. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
  91. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
  92. package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
  93. package/assets/.kilocode/agent.json +0 -28
  94. package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
  95. package/assets/.kilocode/workflows/appweaver.md +0 -55
  96. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
  97. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
  98. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/service/technical-requirements.md +0 -0
@@ -53,7 +53,7 @@ scripts:
53
53
 
54
54
  # Sticky standards seed = the UNIVERSAL always-on rule only (ai-rules). The code-generation
55
55
  # set (triage may fix the CANDIDATE code to match legacy) is no longer hardcoded here — it is
56
- # now CONFIGURATION, loaded per-command from guardrails/projects/<project>/tech-rule-bindings.md
56
+ # now CONFIGURATION, loaded per-command from guardrails/<project>/tech-rule-bindings.md
57
57
  # under "## /aw-spec-parity" by the tech-select module (see the tech_select step below). No
58
58
  # domain files: the target behaviour is defined by the running legacy system, not domain rules —
59
59
  # the tech map lists only technical files. (parity does not reference constitution.technical.md.)
@@ -68,7 +68,7 @@ vars:
68
68
  workflow:
69
69
 
70
70
  # 0. TECHNICAL rule files → sticky standards (configuration, not hardcoded). tech-select
71
- # reads guardrails/projects/<project>/tech-rule-bindings.md under "## /aw-spec-parity" and
71
+ # reads guardrails/<project>/tech-rule-bindings.md under "## /aw-spec-parity" and
72
72
  # loads that code-generation set into the sticky standards the agent_generate triage step
73
73
  # ALWAYS prepends. No domain rule file is loaded here — the tech map lists only technical
74
74
  # files. No blocking gate: an unconfigured project soft-continues (the target behaviour is
@@ -105,7 +105,7 @@ scripts:
105
105
 
106
106
  # Sticky standards seed = the UNIVERSAL always-on rule only (ai-rules). The TECHNICAL/
107
107
  # architecture rule files are CONFIGURATION, loaded per-command from
108
- # guardrails/projects/<project>/tech-rule-bindings.md by the tech-select module (see the
108
+ # guardrails/<project>/tech-rule-bindings.md by the tech-select module (see the
109
109
  # tech_select steps below), exactly as the DOMAIN rule files are loaded by domain-select.
110
110
  # Per the rule-partition this phase loads NO domain rule file — the domain reaches the
111
111
  # plan as spec ids (BR-/CN-/DC-/IC-) and as the context's domain model. The technology
@@ -179,7 +179,7 @@ vars:
179
179
  workflow:
180
180
 
181
181
  # 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
182
+ # lane root folder on disk, unlike the lane-gate module, because a plan is authored BEFORE
183
183
  # the code exists. That is the point of planning.
184
184
  - id: lane_resolve
185
185
  action: execute_script
@@ -201,7 +201,7 @@ workflow:
201
201
  action: verify_context
202
202
  require_true: lanes_declared
203
203
  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."
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 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
205
 
206
206
  # 1. TECHNICAL rule files → sticky standards (configuration, not hardcoded).
207
207
  # The service lane's set is loaded under `## /aw-spec-plan`; the frontend lane's under
@@ -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.
@@ -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