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.
- package/assets/.agents/skills/appweaver/SKILL.md +7 -47
- package/assets/.appweaver/ORCH-DIALECT.md +13 -9
- package/assets/.appweaver/RULE-PARTITION.md +3 -3
- package/assets/.appweaver/STACK-PROFILES.md +188 -101
- package/assets/.appweaver/domain.json +1 -1
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
- package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
- package/assets/.appweaver/orchestrator/README.md +120 -53
- package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
- package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +349 -0
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +381 -0
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
- package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +14 -14
- package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
- package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +13 -13
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +29 -28
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +53 -53
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +284 -128
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +224 -70
- package/assets/.appweaver/scripts/python/aw-foundation.py +809 -20
- package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
- package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
- package/assets/.appweaver/scripts/python/aw-stack.py +195 -89
- package/assets/.appweaver/stack-profiles/angular.json +2 -1
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +16 -3
- package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
- package/assets/.appweaver/stack-profiles/java-spring.json +12 -5
- package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
- package/assets/.appweaver/stack-profiles/node-express.json +8 -2
- package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
- package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
- package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
- package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
- package/assets/.appweaver/stacks.json +37 -1
- package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
- package/assets/.claude/skills/appweaver/SKILL.md +7 -46
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
- package/assets/foundations/foundation.spec.template.txt +73 -0
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +1 -1
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
- package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
- package/assets/guardrails/README.md +31 -17
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +5 -5
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/tech-rule-bindings.md +151 -114
- package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
- package/assets/guardrails/technology/nextjs/api-client.md +1 -1
- package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
- package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
- package/assets/guardrails/technology/nextjs/design-system.md +1 -1
- package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
- package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
- package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
- package/package.json +1 -1
- package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
- package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.kilocode/agent.json +0 -28
- package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
- package/assets/.kilocode/workflows/appweaver.md +0 -55
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
- /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
|
|
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
|
|
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
|
|
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
|
-
#
|
|
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
|
|
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
|
|
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
|
|
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
|
|
70
|
-
# lane by definition, and run-migrate searches that lane
|
|
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.
|
|
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
|
-
|
|
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/
|
|
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:
|
|
21
|
-
version: 1.
|
|
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/
|
|
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 =
|
|
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
|
|
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
|
|
52
|
-
guardrails
|
|
53
|
-
|
|
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
|
|
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
|
|
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/
|
|
83
|
-
# constitution
|
|
84
|
-
#
|
|
85
|
-
next: "
|
|
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
|
|
18
|
-
# stack-list --suggest frontend → select stack → stack-list --profile → ask
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}} —
|
|
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}} —
|
|
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
|
|
320
|
-
next: "GREENFIELD: /appweaver foundation —
|
|
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
|
|
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
|
|
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/
|
|
119
|
-
- { path: "guardrails/
|
|
120
|
-
- { path: "guardrails/
|
|
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/
|
|
145
|
-
- { path: "guardrails/
|
|
146
|
-
- { path: "guardrails/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|