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
@@ -0,0 +1,548 @@
1
+ # =============================================================================
2
+ # foundation-spec (orchestrator) — build ONE lane's project from a spec
3
+ #
4
+ # Included by foundation-lane when the operator picks a `[spec]` entry (a bundle's
5
+ # *.spec.txt) or `[manual spec]` (a file path or text they give at the prompt). Where a
6
+ # pack is a verified project unpacked byte-for-byte, a spec DESCRIBES the project and an
7
+ # agent builds it in the lane — so the three things a pack guarantees by construction are
8
+ # made explicit here instead:
9
+ #
10
+ # WHERE the whole project — build files, source and tests — goes inside the lane
11
+ # root folder, the way a pack holds it, and the agent may write nothing outside it.
12
+ # That is checked, not trusted: the repo is recorded before the build and
13
+ # compared after it, and a build that touched anything outside the lane root
14
+ # folder is not accepted, with what it created there removed again.
15
+ # foundation-lane only gets here for a lane that runs its commands in that
16
+ # folder and keeps its tests there, so the project builds where it is created.
17
+ # HOW the technical rules mapped for this command (`## /aw-spec-foundation-backend`
18
+ # or `## /aw-spec-foundation-frontend` in the active project's
19
+ # tech-rule-bindings.md) load as standards through tech-select, so the scaffold
20
+ # agrees with the rules plan and implement apply to the same lane later.
21
+ # PROOF the lane must hold a project of its ecosystem afterwards (the check implement
22
+ # gates on), and its own build command can be run on it.
23
+ #
24
+ # The spec actually used is copied to .appweaver/foundation/<lane>.spec.md — the record of
25
+ # what the project was built from. The API-contract settings its header gives — or the
26
+ # operator types when it gives none — are recorded on the lane once the project is built.
27
+ #
28
+ # Every refusal RETURNS rather than stops, with the reason in fl_status, so the run
29
+ # carries on with the next lane.
30
+ #
31
+ # Inputs (shared vars, set by foundation-lane):
32
+ # fl_route (spec | manual), fl_spec_file (the bundle spec, route spec), fl_overwrite,
33
+ # fl_files_summary, app, fl_kind, fl_lane_id, fl_title, fl_language, fl_profile,
34
+ # fl_ecosystem, fl_source_path, fl_test_path, fl_workdir, fl_build
35
+ # Produces: fl_status, fl_spec_path, fl_files, and the fs_* details.
36
+ # =============================================================================
37
+
38
+ name: foundation-spec
39
+ dialect: aw-spec.orchestrator/v1
40
+
41
+ scripts:
42
+ actions:
43
+ sh: .appweaver/scripts/bash/aw-spec-actions.sh
44
+ ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
45
+
46
+ workflow:
47
+
48
+ # 0. Shared vars: the second lane must not read the first lane's answers.
49
+ - id: fs_reset
50
+ action: set
51
+ vars:
52
+ fs_spec_input: ""
53
+ fs_overwrite_how: ""
54
+ fs_existing_note: "The lane root folder is empty."
55
+ fs_ok: ""
56
+ fs_spec_path: ""
57
+ fs_source: ""
58
+ fs_title: ""
59
+ fs_rules_ack: ""
60
+ fs_rules_why: ""
61
+ fs_rules_line: "none"
62
+ fs_proceed: ""
63
+ fs_snapshot_path: ""
64
+ fs_files: []
65
+ fs_summary: ""
66
+ fs_inside_only: ""
67
+ fs_outside_summary: ""
68
+ fs_found: ""
69
+ fs_build_ack: ""
70
+ fs_build_ok: ""
71
+ fs_build_note: "build not run — /appweaver build compiles it and repairs compile errors"
72
+ fs_hdr_contract_run: ""
73
+ fs_hdr_contract: ""
74
+ fs_hdr_client: ""
75
+ fs_settings_text: "none"
76
+ fs_placeholder: ""
77
+ fs_is_backend: "false"
78
+ fs_is_frontend: "false"
79
+ fs_need_run: "false"
80
+ fs_need_url: "false"
81
+ fs_need_client: "false"
82
+ fs_ans_contract_run: ""
83
+ fs_ans_contract: ""
84
+ fs_ans_client: ""
85
+ fs_set_run: ""
86
+ fs_set_url: ""
87
+ fs_set_client: ""
88
+ fs_cur_contract_run: ""
89
+ fs_cur_contract: ""
90
+ fs_cur_client: ""
91
+ fs_cur_run_shown: "none — the export is skipped until one is set"
92
+ fs_cur_url_shown: "none — the export is skipped until one is set"
93
+ fs_cur_client_shown: "none — implement asks for one before it generates the frontend"
94
+ fs_lane_written: ""
95
+ fs_lane_note: ""
96
+
97
+ # 1. A lane that already had files reaches this module only when the operator agreed, in
98
+ # foundation-lane, to overwrite them. The agent is told so, with what that means for
99
+ # the lane's kind: a backend generator needs its overwrite flag; a frontend generator
100
+ # refuses a non-empty folder outright and leaves node_modules out of step with the new
101
+ # package.json. The engine has no AND, so the kind's text is chosen first and only
102
+ # used when the lane is being overwritten.
103
+ - id: fs_overwrite_backend
104
+ action: set
105
+ condition: "{{fl_kind}} == backend"
106
+ vars:
107
+ fs_overwrite_how: >-
108
+ If a generator refuses to write over existing files (for example `dotnet new`
109
+ without `--force`), use that generator's own overwrite flag.
110
+
111
+ - id: fs_overwrite_frontend
112
+ action: set
113
+ condition: "{{fl_kind}} == frontend"
114
+ vars:
115
+ fs_overwrite_how: >-
116
+ Scaffolding tools that refuse a non-empty directory (create-next-app, npm create
117
+ vite, ng new) must run in a temporary directory OUTSIDE the repository — the only
118
+ place outside the lane root folder you may write — with the result copied into
119
+ {{fl_source_path}} and the temporary directory removed afterwards; or write the
120
+ files directly. Then reinstall the dependencies, so node_modules matches the new
121
+ package.json.
122
+
123
+ - id: fs_overwrite_noted
124
+ action: set
125
+ condition: "{{fl_overwrite}} == yes"
126
+ vars:
127
+ fs_existing_note: >-
128
+ THE LANE ALREADY HOLDS FILES ({{fl_files_summary}}) and the operator agreed to
129
+ overwrite them. Replace a file only where the project you build needs that path;
130
+ leave every other file where it is, and delete nothing. {{fs_overwrite_how}}
131
+
132
+ # 2. The spec. A bundle spec is already named; a manual one is asked for here.
133
+ - id: fs_ask_spec
134
+ action: ask
135
+ condition: "{{fl_route}} == manual"
136
+ prompt: >
137
+ Give the spec for the {{fl_kind}} project in lane `{{fl_lane_id}}` ({{fl_title}}):
138
+ either the path of a file that holds it (e.g. docs/{{fl_kind}}-foundation.md), or the
139
+ spec text itself — what to create, with which tools and packages, the folder layout,
140
+ and the starter files. foundations/foundation.spec.template.txt shows the shape.
141
+ answer_var: fs_spec_input
142
+
143
+ - id: fs_capture_bundle
144
+ action: execute_script
145
+ condition: "{{fl_route}} == spec"
146
+ script: { ref: actions }
147
+ subcommand: foundation-spec-capture
148
+ args: ["--lane", "{{fl_lane_id}}", "--kind", "{{fl_kind}}", "--file", "{{fl_spec_file}}", "--app", "{{app}}"]
149
+ outputs:
150
+ - { name: fs_ok, from: "$.ok" }
151
+ - { name: fs_spec_path, from: "$.spec_path" }
152
+ - { name: fs_source, from: "$.source" }
153
+ - { name: fs_title, from: "$.title" }
154
+ - { name: fs_reason, from: "$.reason" }
155
+ - { name: fs_hdr_contract_run, from: "$.contract_run" }
156
+ - { name: fs_hdr_contract, from: "$.contract" }
157
+ - { name: fs_hdr_client, from: "$.client" }
158
+ - { name: fs_settings_text, from: "$.settings_text" }
159
+ - { name: fs_placeholder, from: "$.placeholder" }
160
+
161
+ - id: fs_capture_manual
162
+ action: execute_script
163
+ condition: "{{fl_route}} == manual"
164
+ script: { ref: actions }
165
+ subcommand: foundation-spec-capture
166
+ args: ["--lane", "{{fl_lane_id}}", "--kind", "{{fl_kind}}", "--input", "{{fs_spec_input}}", "--app", "{{app}}"]
167
+ outputs:
168
+ - { name: fs_ok, from: "$.ok" }
169
+ - { name: fs_spec_path, from: "$.spec_path" }
170
+ - { name: fs_source, from: "$.source" }
171
+ - { name: fs_title, from: "$.title" }
172
+ - { name: fs_reason, from: "$.reason" }
173
+ - { name: fs_hdr_contract_run, from: "$.contract_run" }
174
+ - { name: fs_hdr_contract, from: "$.contract" }
175
+ - { name: fs_hdr_client, from: "$.client" }
176
+ - { name: fs_settings_text, from: "$.settings_text" }
177
+ - { name: fs_placeholder, from: "$.placeholder" }
178
+
179
+ - id: fs_capture_gate
180
+ action: verify_context
181
+ require_true: fs_ok
182
+ on_false: return
183
+ message_var: fl_status
184
+ on_false_message: "not built — {{fs_reason}}"
185
+
186
+ # 3. The technical rules mapped for this command, loaded as standards. `replace` resets
187
+ # the set to the workflow's seed first, so the frontend lane is never handed the
188
+ # backend lane's rules. tg_mode/tg_subset are cleared because tech-select only asks
189
+ # when the map has candidates — a stale answer from the other lane would otherwise
190
+ # load that lane's subset here.
191
+ - id: fs_rules
192
+ action: include
193
+ module: .appweaver/orchestrator/modules/tech-select.orch.yaml
194
+ with:
195
+ command: "aw-spec-foundation-{{fl_kind}}"
196
+ replace: "true"
197
+ tg_mode: ""
198
+ tg_subset: []
199
+
200
+ - id: fs_rules_why_project
201
+ action: set
202
+ condition: "{{tech_domain}} == "
203
+ vars: { fs_rules_why: "no project is named in .appweaver/domain.json — run /appweaver select-domain, or set 'domain' to a folder under guardrails/ (project-specific by default)" }
204
+
205
+ - id: fs_rules_why_heading
206
+ action: set
207
+ condition: "{{tech_domain}} != "
208
+ vars: { fs_rules_why: "guardrails/{{tech_domain}}/tech-rule-bindings.md maps no file that exists under `## /aw-spec-foundation-{{fl_kind}}`" }
209
+
210
+ - id: fs_no_rules_ask
211
+ action: ask
212
+ condition: "{{tg_candidates}} == []"
213
+ prompt: "No technical rules apply to this build: {{fs_rules_why}}. Without them the agent builds from the spec alone, and the project may not follow the rules plan and implement apply to this lane later. Continue?"
214
+ options: ["continue without them", "stop — leave this lane"]
215
+ answer_var: fs_rules_ack
216
+
217
+ - id: fs_no_rules_gate
218
+ action: verify_context
219
+ condition: "{{tg_candidates}} == []"
220
+ require_value: fs_rules_ack
221
+ equals: "continue without them"
222
+ on_mismatch: return
223
+ message_var: fl_status
224
+ on_mismatch_message: "not built — no technical rules apply ({{fs_rules_why}}); spec kept at {{fs_spec_path}}"
225
+
226
+ - id: fs_rules_line_none
227
+ action: set
228
+ condition: "{{tg_candidates}} == []"
229
+ vars: { fs_rules_line: "none — {{fs_rules_why}}" }
230
+
231
+ - id: fs_rules_line_all
232
+ action: set
233
+ condition: "{{tg_mode}} == all"
234
+ vars: { fs_rules_line: "{{tg_candidates}}" }
235
+
236
+ - id: fs_rules_line_subset
237
+ action: set
238
+ condition: "{{tg_mode}} == subset"
239
+ vars: { fs_rules_line: "{{tg_subset}}" }
240
+
241
+ - id: fs_rules_line_declined
242
+ action: set
243
+ condition: "{{tg_mode}} == none"
244
+ vars: { fs_rules_line: "none — declined at the selection" }
245
+
246
+ # 4. Confirm the build plan.
247
+ - id: fs_confirm
248
+ action: ask
249
+ prompt: |
250
+ Build the {{fl_kind}} lane from a spec
251
+ Spec: {{fs_spec_path}} (from {{fs_source}}: {{fs_title}})
252
+ App name: {{app}}
253
+ Lane: {{fl_lane_id}} — {{fl_title}}, {{fl_language}}
254
+ Folder: {{fl_source_path}} <- the whole project: build files, source and tests
255
+ Tests: {{fl_test_path}}
256
+ Commands: `{{fl_build}}` runs in {{fl_workdir}}
257
+ Rules: {{fs_rules_line}}
258
+ The agent follows the spec with the stack's own tooling, and writes nothing outside
259
+ these paths. Proceed?
260
+ options: ["yes", "no"]
261
+ answer_var: fs_proceed
262
+
263
+ - id: fs_confirm_gate
264
+ action: verify_context
265
+ require_value: fs_proceed
266
+ equals: "yes"
267
+ on_mismatch: return
268
+ message_var: fl_status
269
+ on_mismatch_message: "not built — declined at the confirmation; the spec is kept at {{fs_spec_path}}"
270
+
271
+ # 5. Build it. agent_generate: the agent has write tools and Bash, so it can run the
272
+ # stack's scaffolding CLI. The spec reaches it as context; the mapped rules are
273
+ # already in the standards. The repo is recorded first, so what the build does outside
274
+ # the lane root folder can be found afterwards (6).
275
+ - id: fs_snapshot
276
+ action: execute_script
277
+ script: { ref: actions }
278
+ subcommand: foundation-snapshot
279
+ args: ["--out", ".appweaver/orchestrator/.state/foundation-{{fl_lane_id}}.snapshot.json"]
280
+ outputs:
281
+ - { name: fs_snapshot_path, from: "$.snapshot" }
282
+
283
+ - id: fs_generate
284
+ action: agent_generate
285
+ context: ["{{fs_spec_path}}"]
286
+ task: |
287
+ Create the base project for the {{fl_kind}} lane `{{fl_lane_id}}` — {{fl_title}}
288
+ ({{fl_language}}, stack profile `{{fl_profile}}`) — exactly as the spec in
289
+ {{fs_spec_path}} (in your context) describes. Name it after `{{app}}`, in the form
290
+ this stack uses for a project name.
291
+
292
+ WHERE YOU MAY WRITE — {{fl_source_path}}, the lane root folder, and nothing else, ever.
293
+ The WHOLE project goes inside it, complete: its build files (solution, workspace or
294
+ package manifest, build props, wrapper scripts), its source, and its tests — the
295
+ tests at {{fl_test_path}}, inside the same folder. Create the folder if absent. The
296
+ lane's commands run in that folder (`{{fl_build}}` runs in {{fl_workdir}}), so
297
+ nothing the build needs may sit outside it. Never write under .appweaver/,
298
+ guardrails/, foundations/ or specs/, at the repository root, or into another lane
299
+ root folder. This is checked when you finish: if anything outside the lane root
300
+ folder was created, changed or deleted, the lane is not accepted and what you
301
+ created there is removed.
302
+
303
+ WHAT IS THERE ALREADY: {{fs_existing_note}}
304
+
305
+ HOW:
306
+ - Follow the spec. Where it is silent, follow the technical rules in your standards;
307
+ where the spec and a rule disagree, follow the spec and name the conflict in your
308
+ summary.
309
+ - Where the spec names a scaffolding tool (dotnet new, npm create, mvn archetype,
310
+ …), run it so its output lands in the lane root folder itself — not a new folder
311
+ inside or beside it.
312
+ - This is the lane's BASE project. Business features are generated later by
313
+ /appweaver implement from the plans, so add none the spec does not ask for.
314
+ - The project must build with `{{fl_build}}` run in {{fl_workdir}}. Restore or
315
+ install what that needs; run the build once if you can and fix what it reports.
316
+ - THE API CONTRACT SETTINGS the spec's header gives: {{fs_settings_text}}. They are
317
+ recorded on the lane, and /appweaver implement uses them before it generates the
318
+ frontend, so the project you build has to honour them exactly:
319
+ · a START COMMAND (backend) — the API starts with exactly that command, run in
320
+ {{fl_workdir}}, ON ITS OWN: no orchestration host, and nothing it needs that
321
+ is not on this machine. Name the project so the path the command names exists.
322
+ · a DOCUMENT URL (backend) — the running API serves its OpenAPI document at
323
+ exactly that URL, over http, on the port it names.
324
+ · a CLIENT COMMAND (frontend) — that command can run in {{fl_workdir}}: install
325
+ its tool as a development dependency. Do not run it; the service's document
326
+ does not exist yet.
327
+ A backend built without them still serves an OpenAPI document; say at what URL,
328
+ and how the API starts on its own, in your summary.
329
+ - Do not commit, push, or change git configuration.
330
+
331
+ List every file you created or changed in `files` (paths relative to the repository
332
+ root; for a tool that generated many files, list the manifest and entry points).
333
+ outputs:
334
+ - { name: fs_files, from: "$.files" }
335
+ - { name: fs_summary, from: "$.summary" }
336
+
337
+ # 6. Did the build stay inside its lane root folder? Compared with the snapshot: anything
338
+ # created, changed or deleted elsewhere — the repository root, another lane, the kit's
339
+ # own folders — and the lane is not accepted. What the build created out there is
340
+ # removed again; what it changed or deleted is listed, since there is no copy to put
341
+ # back. Checked before anything else, so a build that wrote nothing in the lane still
342
+ # has its stray files found.
343
+ - id: fs_outside
344
+ action: execute_script
345
+ script: { ref: actions }
346
+ subcommand: foundation-outside
347
+ args: ["--snapshot", "{{fs_snapshot_path}}", "--lane", "{{fl_source_path}}", "--undo"]
348
+ outputs:
349
+ - { name: fs_inside_only, from: "$.clean" }
350
+ - { name: fs_outside_summary, from: "$.summary" }
351
+
352
+ - id: fs_outside_gate
353
+ action: verify_context
354
+ require_true: fs_inside_only
355
+ on_false: return
356
+ message_var: fl_status
357
+ on_false_message: "NOT accepted — the spec build wrote outside its lane root folder {{fl_source_path}}: {{fs_outside_summary}}. The spec is kept at {{fs_spec_path}}"
358
+
359
+ - id: fs_files_gate
360
+ action: verify_context
361
+ require_non_empty: fs_files
362
+ on_empty: return
363
+ message_var: fl_status
364
+ on_empty_message: "NOT built — the spec build reported no file that exists on disk; the spec is kept at {{fs_spec_path}}"
365
+
366
+ # 6. Proof: a project of this lane's ecosystem now sits INSIDE the lane — the same
367
+ # check implement gates on. A repo-scope hit (another lane's manifest) does not count.
368
+ - id: fs_detect
369
+ action: execute_script
370
+ script: { ref: actions }
371
+ subcommand: detect-project
372
+ args: ["--root", "{{fl_source_path}}", "--ecosystem", "{{fl_ecosystem}}"]
373
+ outputs:
374
+ - { name: fs_scope, from: "$.scope" }
375
+ - { name: fs_eco_match, from: "$.ecosystem_match" }
376
+ - { name: fs_markers, from: "$.markers" }
377
+
378
+ - id: fs_found_in_lane
379
+ action: set
380
+ condition: "{{fs_scope}} == lane"
381
+ vars: { fs_found: "true" }
382
+
383
+ - id: fs_found_wrong_eco
384
+ action: set
385
+ condition: "{{fs_eco_match}} == false"
386
+ vars: { fs_found: "" }
387
+
388
+ - id: fs_found_gate
389
+ action: verify_context
390
+ require_true: fs_found
391
+ on_false: return
392
+ message_var: fl_status
393
+ on_false_message: "NOT usable — the spec build ran ({{fs_summary}}) but no {{fl_ecosystem}} project manifest is under {{fl_source_path}} (searched at scope `{{fs_scope}}`, found {{fs_markers}}); implement will skip this lane until one is there. The spec is kept at {{fs_spec_path}}"
394
+
395
+ # 7. Optionally run the lane's own build on it. It may need the network (restore /
396
+ # install), which is why it is asked rather than assumed.
397
+ - id: fs_ask_build
398
+ action: ask
399
+ prompt: "Run this lane's build now to confirm the project compiles — `{{fl_build}}` in {{fl_workdir}}? It may download packages."
400
+ options: ["yes — build it now", "no — I'll build later"]
401
+ answer_var: fs_build_ack
402
+
403
+ - id: fs_build
404
+ action: execute_script
405
+ condition: "{{fs_build_ack}} == yes — build it now"
406
+ on_error: continue
407
+ script: { ref: actions }
408
+ subcommand: build-compile
409
+ args: ["--kind", "{{fl_kind}}"]
410
+ outputs:
411
+ - { name: fs_build_ok, from: "$.ok" }
412
+ - { name: fs_build_tail, from: "$.failing_excerpt" }
413
+
414
+ - id: fs_build_passed
415
+ action: set
416
+ condition: "{{fs_build_ok}} == true"
417
+ vars: { fs_build_note: "build passed (`{{fl_build}}`)" }
418
+
419
+ - id: fs_build_failed
420
+ action: set
421
+ condition: "{{fs_build_ok}} == false"
422
+ vars: { fs_build_note: "build FAILED — run /appweaver build, which repairs compile errors: {{fs_build_tail}}" }
423
+
424
+ # 8. THE API CONTRACT SETTINGS — what implement uses between the lanes to export the
425
+ # service's OpenAPI document and generate the frontend's client from it
426
+ # (STACK-PROFILES.md §4.5). A backend lane needs its start command and document URL,
427
+ # a frontend lane its client command. Each comes from the spec's header
428
+ # (`# contract-run:`, `# contract:`, `# client:`, read at capture); one the header
429
+ # does not give is asked for, and an empty answer keeps the lane's current value —
430
+ # the stack profile's, unless something set it already. What there is, is recorded
431
+ # on the lane with lane-set, as the pack route records a pack's .lane.json.
432
+ - id: fs_kind_backend
433
+ action: set
434
+ condition: "{{fl_kind}} == backend"
435
+ vars: { fs_is_backend: "true" }
436
+ - id: fs_kind_frontend
437
+ action: set
438
+ condition: "{{fl_kind}} == frontend"
439
+ vars: { fs_is_frontend: "true" }
440
+ - id: fs_need_run_arm
441
+ action: set
442
+ condition: "{{fs_hdr_contract_run}} == "
443
+ vars: { fs_need_run: "{{fs_is_backend}}" }
444
+ - id: fs_need_url_arm
445
+ action: set
446
+ condition: "{{fs_hdr_contract}} == "
447
+ vars: { fs_need_url: "{{fs_is_backend}}" }
448
+ - id: fs_need_client_arm
449
+ action: set
450
+ condition: "{{fs_hdr_client}} == "
451
+ vars: { fs_need_client: "{{fs_is_frontend}}" }
452
+
453
+ # The lane's current values, shown as what an empty answer keeps.
454
+ - id: fs_current
455
+ action: execute_script
456
+ on_error: continue
457
+ script: { ref: actions }
458
+ subcommand: lane-resolve
459
+ args: ["--id", "{{fl_lane_id}}"]
460
+ outputs:
461
+ - { name: fs_cur_contract_run, from: "$.backend_contract_run" }
462
+ - { name: fs_cur_contract, from: "$.backend_contract" }
463
+ - { name: fs_cur_client, from: "$.frontend_client" }
464
+ - id: fs_cur_run_known
465
+ action: set
466
+ condition: "{{fs_cur_contract_run}} != "
467
+ vars: { fs_cur_run_shown: "{{fs_cur_contract_run}}" }
468
+ - id: fs_cur_url_known
469
+ action: set
470
+ condition: "{{fs_cur_contract}} != "
471
+ vars: { fs_cur_url_shown: "{{fs_cur_contract}}" }
472
+ - id: fs_cur_client_known
473
+ action: set
474
+ condition: "{{fs_cur_client}} != "
475
+ vars: { fs_cur_client_shown: "{{fs_cur_client}}" }
476
+
477
+ - id: fs_ask_contract_run
478
+ action: ask
479
+ condition: "{{fs_need_run}} == true"
480
+ prompt: |
481
+ How does the API in lane `{{fl_lane_id}}` start ON ITS OWN? /appweaver implement starts
482
+ it with this command to fetch its OpenAPI document before it generates the frontend.
483
+ The spec's header gives no `# contract-run:`.
484
+ Type the command — it runs in {{fl_workdir}} — with no orchestration host and nothing
485
+ the API cannot reach on this machine.
486
+ Leave it empty to keep the current one: {{fs_cur_run_shown}}
487
+ answer_var: fs_ans_contract_run
488
+ - id: fs_ask_contract
489
+ action: ask
490
+ condition: "{{fs_need_url}} == true"
491
+ prompt: |
492
+ At what URL does that running API serve its OpenAPI document? The spec's header gives
493
+ no `# contract:`.
494
+ Leave it empty to keep the current one: {{fs_cur_url_shown}}
495
+ answer_var: fs_ans_contract
496
+ - id: fs_ask_client
497
+ action: ask
498
+ condition: "{{fs_need_client}} == true"
499
+ prompt: |
500
+ Which command generates this frontend's API client from the service's OpenAPI
501
+ document? The spec's header gives no `# client:`.
502
+ It runs in {{fl_workdir}}, and {{fs_placeholder}} in it stands for the document's path —
503
+ for example: npx openapi-typescript {{fs_placeholder}} -o lib/api/schema.d.ts
504
+ Leave it empty to keep the current one: {{fs_cur_client_shown}}
505
+ answer_var: fs_ans_client
506
+
507
+ # What to record: the header's value for this lane's kind, or the answer where it gave
508
+ # none. An empty value is left out by lane-set, so the lane keeps what it has.
509
+ - id: fs_set_backend
510
+ action: set
511
+ condition: "{{fs_is_backend}} == true"
512
+ vars: { fs_set_run: "{{fs_hdr_contract_run}}", fs_set_url: "{{fs_hdr_contract}}" }
513
+ - id: fs_set_run_answer
514
+ action: set
515
+ condition: "{{fs_need_run}} == true"
516
+ vars: { fs_set_run: "{{fs_ans_contract_run}}" }
517
+ - id: fs_set_url_answer
518
+ action: set
519
+ condition: "{{fs_need_url}} == true"
520
+ vars: { fs_set_url: "{{fs_ans_contract}}" }
521
+ - id: fs_set_frontend
522
+ action: set
523
+ condition: "{{fs_is_frontend}} == true"
524
+ vars: { fs_set_client: "{{fs_hdr_client}}" }
525
+ - id: fs_set_client_answer
526
+ action: set
527
+ condition: "{{fs_need_client}} == true"
528
+ vars: { fs_set_client: "{{fs_ans_client}}" }
529
+
530
+ - id: fs_lane_record
531
+ action: execute_script
532
+ on_error: continue
533
+ script: { ref: actions }
534
+ subcommand: lane-set
535
+ args: ["--id", "{{fl_lane_id}}", "--set", "contract_run={{fs_set_run}}", "--set", "contract={{fs_set_url}}", "--set", "client={{fs_set_client}}"]
536
+ outputs:
537
+ - { name: fs_lane_written, from: "$.written" }
538
+ - id: fs_lane_noted
539
+ action: set
540
+ condition: "{{fs_lane_written}} == true"
541
+ vars: { fs_lane_note: "; API-contract settings recorded on the {{fl_lane_id}} lane" }
542
+
543
+ - id: fs_done
544
+ action: set
545
+ vars:
546
+ fl_spec_path: "{{fs_spec_path}}"
547
+ fl_files: "{{fs_files}}"
548
+ fl_status: "built from the spec in {{fs_spec_path}} (from {{fs_source}}) into {{fl_source_path}} — {{fs_summary}}; {{fs_build_note}}{{fs_lane_note}}"
@@ -1,12 +1,12 @@
1
1
  # =============================================================================
2
- # lane-gate (orchestrator) — shared LANE + SOURCE PATH gate
2
+ # lane-gate (orchestrator) — shared LANE + LANE ROOT FOLDER gate
3
3
  #
4
4
  # Included by every phase that reads or writes a lane's subtree. It answers one
5
5
  # question before that phase starts doing work:
6
6
  #
7
- # is there a lane of the kind I need, and is its source path really there?
7
+ # is there a lane of the kind I need, and is its lane root folder really there?
8
8
  #
9
- # WHY A GATE AND NOT A FALLBACK. A phase that cannot find a source path has two
9
+ # WHY A GATE AND NOT A FALLBACK. A phase that cannot find a lane root folder has two
10
10
  # options: guess, or stop. Guessing is what the kit did before the lane model —
11
11
  # `build` sniffed for a .sln, `run-migrate` hardcoded `src/`, and `implement` let
12
12
  # the model decide where files should go. Each of those is right on the layout the
@@ -27,7 +27,7 @@
27
27
  # needs a declaration to work from but no particular kind of one — `build`
28
28
  # compiles every declared lane, so a frontend-only project is as buildable
29
29
  # as a backend-only one. It narrows nothing else: no lane declared at all, a
30
- # lane with no source path, a source path that is not on disk and two lanes
30
+ # lane with no lane root folder, a lane root folder that is not on disk and two lanes
31
31
  # claiming overlapping subtrees all still stop the run. The required kind's
32
32
  # fields below then bind from the backend block, which an empty-require
33
33
  # caller reads none of.
@@ -2,10 +2,10 @@
2
2
  # tech-select (orchestrator) — shared TECHNICAL rule-file selection module
3
3
  #
4
4
  # The technical counterpart of domain-select. Where domain-select loads the
5
- # per-command DOMAIN rule files from guardrails/projects/<project>/domain-rule-bindings.md,
5
+ # per-command DOMAIN rule files from guardrails/<project>/domain-rule-bindings.md,
6
6
  # this module loads the per-command TECHNICAL rule files — the project's mapped technical rules and
7
7
  # the worked examples/ samples that go with them — from
8
- # guardrails/projects/<project>/tech-rule-bindings.md
8
+ # guardrails/<project>/tech-rule-bindings.md
9
9
  # Included (via `action: include`) by every technical-rule consumer so the set is
10
10
  # CONFIGURATION, not code — tune the map, not the workflow.
11
11
  #
@@ -87,7 +87,7 @@ workflow:
87
87
  on_mismatch_message: >
88
88
  Stopped before loading technical rules from {{tg_mismatched}} into a
89
89
  {{tg_declared_stacks}} repository. Point the `## /` headings in
90
- guardrails/projects/{{tech_domain}}/tech-rule-bindings.md at a corpus for this
90
+ guardrails/{{tech_domain}}/tech-rule-bindings.md at a corpus for this
91
91
  stack, or write the corpus segment of the path as a stack PLACEHOLDER (see the
92
92
  header of resolve-tech) so one map resolves from .appweaver/stacks.json and serves
93
93
  every stack this project declares. A corpus