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
|
@@ -9,7 +9,7 @@ makes) and `.appweaver/stack-profiles/*.json` (the candidates it chooses from).
|
|
|
9
9
|
|
|
10
10
|
## 1. What a lane is
|
|
11
11
|
|
|
12
|
-
A **lane** is a technology target that owns
|
|
12
|
+
A **lane** is a technology target that owns its own lane root folder, compiles and tests
|
|
13
13
|
independently, and carries its own technical rules and constitution half — while
|
|
14
14
|
*sharing* the feature, the spec, the domain, the version, and the knowledge bundle with
|
|
15
15
|
every other lane.
|
|
@@ -33,9 +33,10 @@ no heading to key on. Where the two lanes are folded into one command, as `plan`
|
|
|
33
33
|
```jsonc
|
|
34
34
|
{
|
|
35
35
|
"lanes": [
|
|
36
|
-
{ "id": "service", "kind": "backend", "profile": "dotnet-webapi", "root": "
|
|
37
|
-
"
|
|
38
|
-
|
|
36
|
+
{ "id": "service", "kind": "backend", "profile": "dotnet-webapi", "root": "backend/",
|
|
37
|
+
"run_from": "root",
|
|
38
|
+
"build": "dotnet build", "test": "dotnet test", "run": "dotnet run --project {{host}}" },
|
|
39
|
+
{ "id": "web", "kind": "frontend", "profile": "react-vite", "root": "frontend/",
|
|
39
40
|
"run_from": "root",
|
|
40
41
|
"build": "npm run build", "test": "npm test", "run": "npm run dev" }
|
|
41
42
|
],
|
|
@@ -50,16 +51,16 @@ no heading to key on. Where the two lanes are folded into one command, as `plan`
|
|
|
50
51
|
| `profile` | the stack profile the lane was declared from. Records the technology, so re-stacking a lane never renames the lane. `detected` where the kit ships no profile for what the code is |
|
|
51
52
|
| `stack` | *(optional)* what the code was found to be, when `profile` is `detected` — e.g. `asp.net-webforms`. The honest record for a legacy lane |
|
|
52
53
|
| `origin` | *(optional)* `reverse-engineered` on a lane `onboard` derived from an existing codebase. Absent means a person declared it, which is the greenfield shape and the historical one |
|
|
53
|
-
| `root` | the lane
|
|
54
|
+
| `root` | the **lane root folder** — the subtree the lane owns (see §3). `--source-path` and `--root` are two spellings of this one field |
|
|
54
55
|
| `test_root` | *(optional)* the lane's **test path**, written by hand only when the profile's answer does not fit this layout. Absent, `lane-resolve` / `lane-verify` work it out from the profile at read time (§4.3), so no lane has to be re-declared for it |
|
|
55
|
-
| `run_from` | *(optional)* **where the commands run**: `repo` (the default, and the shape of every lane written before this key existed) at the repository root, or `root` inside the lane's
|
|
56
|
-
| `build` / `test` / `run` | project-supplied command strings the engine shells out to. These are the matched **profile's** defaults and may not fit a legacy layout — reviewing them is what `select-stack` is for. `{{root}}` in a command resolves to this lane's `root
|
|
56
|
+
| `run_from` | *(optional)* **where the commands run**: `repo` (the default, and the shape of every lane written before this key existed) at the repository root, or `root` inside the lane root folder. `select-stack` decides it from where the stack's build file sits — see §3.1 |
|
|
57
|
+
| `build` / `test` / `run` | project-supplied command strings the engine shells out to. These are the matched **profile's** defaults and may not fit a legacy layout — reviewing them is what `select-stack` is for. `{{root}}` in a command resolves to this lane's `root`, as seen from where the command runs (§4.2) |
|
|
57
58
|
| `migrate` | *(optional)* the lane's schema-migration command, recorded only when the profile declares one. Absent, `run-migrate` falls back to `dotnet ef` and otherwise reports that nothing ran (§4.2) |
|
|
58
59
|
|
|
59
60
|
### Three properties matter more than the schema
|
|
60
61
|
|
|
61
|
-
1. **`root` is ownership, and it is the
|
|
62
|
-
code only under
|
|
62
|
+
1. **`root` is ownership, and it is the lane root folder.** `implement`'s service lane writes its
|
|
63
|
+
code only under the backend lane root folder and its frontend lane only under the frontend one,
|
|
63
64
|
`build`/`test`/`run` act on it, and `onboard` reverse-engineers out of it. The lane's
|
|
64
65
|
**test path** (§4.3) is owned the same way, and is where `implement` writes the lane's tests.
|
|
65
66
|
2. **The commands are project-supplied strings.** The engine stays stdlib-only and
|
|
@@ -71,33 +72,39 @@ no heading to key on. Where the two lanes are folded into one command, as `plan`
|
|
|
71
72
|
|
|
72
73
|
### 3.1 `root` is where the code is; `run_from` is where the commands run
|
|
73
74
|
|
|
74
|
-
These are two questions and
|
|
75
|
-
solution file at the top while the lane owns `src
|
|
76
|
-
while the lane owns `internal/`.
|
|
77
|
-
the repository root.
|
|
78
|
-
|
|
79
|
-
A
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
These are two questions, and an existing repository can give them two answers: a classic
|
|
76
|
+
.NET repository keeps its solution file at the top while the lane owns `src/`, and a classic
|
|
77
|
+
Go repository keeps `go.mod` there while the lane owns `internal/`. Their commands have to run
|
|
78
|
+
at the repository root.
|
|
79
|
+
|
|
80
|
+
**A new project is one self-contained folder per lane.** Every backend profile defaults to
|
|
81
|
+
`backend/` and every frontend profile to `frontend/`, with `run_from: "root"`: the lane's
|
|
82
|
+
build files, source and tests all live inside its lane root folder, and its commands run there.
|
|
83
|
+
`foundation` builds exactly that — a pack unpacks into the lane root folder as packed, a spec build
|
|
84
|
+
creates the whole project inside it — and reports a lane that does not run its commands in its
|
|
85
|
+
own folder or keeps its tests outside it, rather than scaffolding a project its own build
|
|
86
|
+
cannot find.
|
|
87
|
+
|
|
88
|
+
**`select-stack` answers `run_from` from the disk.** Each backend profile lists the files its
|
|
89
|
+
commands need (`build_files`: `*.sln`, `pom.xml`, `go.mod`, `package.json`, …). When a lane is
|
|
90
|
+
declared, `lane-declare` looks for them: directly inside the lane root folder ⇒ `root`; only at the
|
|
91
|
+
repository root ⇒ `repo`; nowhere yet — a greenfield lane — ⇒ the profile's own answer, which is
|
|
92
|
+
inside the lane. So a classic repository keeps the shape it has, a Maven module whose `mvnw`
|
|
93
|
+
sits in the lane root folder runs there, and a new project gets the self-contained layout, from
|
|
94
|
+
one profile. `--run-from` overrides it, and so does editing `stacks.json`.
|
|
85
95
|
|
|
86
96
|
Two consequences worth knowing:
|
|
87
97
|
|
|
88
|
-
- **Declare a
|
|
89
|
-
|
|
90
|
-
the *code* goes; detection proposes the directory `pom.xml` actually sits in, which is the
|
|
91
|
-
one to accept. A lane rooted at `src/main/java/` will fail loudly with `./mvnw: not found`
|
|
92
|
-
rather than silently.
|
|
98
|
+
- **Declare a lane at the directory holding its build file** when the code already exists and
|
|
99
|
+
should run there — a Maven lane at the folder with `pom.xml`, not at `src/main/java/`.
|
|
93
100
|
- **A single-module project declares `.`** — stored as `./`, the repository root. It owns
|
|
94
101
|
everything, so it overlaps every other lane by definition and cannot be combined with one.
|
|
95
102
|
|
|
96
|
-
### Where the
|
|
103
|
+
### Where the lane root folder is checked against the disk
|
|
97
104
|
|
|
98
105
|
`lane-declare` records a path; it does **not** require the path to exist. In a greenfield
|
|
99
|
-
project it does not exist yet — the whole point of declaring `
|
|
100
|
-
`implement` will create it.
|
|
106
|
+
project it does not exist yet — the whole point of declaring `backend/` on day one is that
|
|
107
|
+
`foundation` and `implement` will create it.
|
|
101
108
|
|
|
102
109
|
`lane-verify` is the check, and it runs where the path has to be real: before `implement`,
|
|
103
110
|
`build`, `run`, and before `onboard` reverse-engineers a codebase out of it. That split is what lets one file serve a project with no code yet and a project that is
|
|
@@ -108,7 +115,7 @@ Two failure classes, deliberately distinguished:
|
|
|
108
115
|
- **MISSING** — the phase needs a lane of this kind and none is declared. Reported only for
|
|
109
116
|
the kinds a caller names with `--require`, because "no frontend lane" is a correct and
|
|
110
117
|
common state that must never fail a backend build.
|
|
111
|
-
- **BROKEN** — a lane *is* declared and its
|
|
118
|
+
- **BROKEN** — a lane *is* declared and its lane root folder is empty, is not a directory, or
|
|
112
119
|
overlaps another lane's. Checked for **every** declared lane whether or not the caller
|
|
113
120
|
asked about it. A stack named against a path that is not there is a mistake in every
|
|
114
121
|
phase, and letting it through means discovering it as an empty build or a generator
|
|
@@ -118,11 +125,25 @@ Two failure classes, deliberately distinguished:
|
|
|
118
125
|
|
|
119
126
|
### The file ships empty, and may be filled in by hand
|
|
120
127
|
|
|
121
|
-
The kit installs `.appweaver/stacks.json`
|
|
128
|
+
The kit installs `.appweaver/stacks.json` with an empty `lanes` array, alongside `domain.json` and
|
|
122
129
|
`feature.json`. It is there so a project can open it and fill it in directly — the block at
|
|
123
130
|
the top of this section is the whole schema, and `select-stack` writes nothing a person
|
|
124
131
|
could not have typed.
|
|
125
132
|
|
|
133
|
+
**The shipped file carries a sample under `_lane_format`**: one backend and one frontend lane
|
|
134
|
+
with every field above filled in (.NET and Next.js), plus a `prototype` block. No command
|
|
135
|
+
reads that key, and `select-stack` leaves it in place, so it is safe to keep. To fill the file
|
|
136
|
+
by hand, copy the lanes you need into `lanes` and edit them. The samples' optional fields hold
|
|
137
|
+
values that change nothing when copied (`stack` is the profile's own title, `origin: "declared"`
|
|
138
|
+
is the default, `test_root` is the profile's own answer), except `migrate`, which is a real
|
|
139
|
+
command: keep it only if the lane has migrations to run. The frontend sample's `migrate` is
|
|
140
|
+
empty because a Next.js lane has none.
|
|
141
|
+
|
|
142
|
+
**Never leave an empty or half-filled entry in `lanes`.** Every entry there is a declared lane,
|
|
143
|
+
whatever its values: `select-stack` replaces a lane only when its `id` matches, so it adds its
|
|
144
|
+
lane beside a blank one instead of replacing it, and `lane-verify` then stops every phase on the
|
|
145
|
+
blank lane's missing lane root folder.
|
|
146
|
+
|
|
126
147
|
**An empty file and an absent one are the same state.** Shipping the file means its presence
|
|
127
148
|
no longer says anything about whether a lane was declared, so `declared` reports on the
|
|
128
149
|
`lanes` array and never on the file: `resolve` reports `exists: true, declared: false` for
|
|
@@ -131,7 +152,7 @@ the file is missing, naming which of the two it found.
|
|
|
131
152
|
|
|
132
153
|
Hand-editing and `select-stack` are the same file and the same schema, so they interleave
|
|
133
154
|
freely: fill in the service lane by hand and run `select-stack` later to add the UI one, or
|
|
134
|
-
run it first and correct a
|
|
155
|
+
run it first and correct a lane root folder in the editor. What hand-editing gives up is the
|
|
135
156
|
checking `select-stack` does on the way in — an unknown `profile`, a missing `root`, and two
|
|
136
157
|
lanes whose roots overlap are all refused there and merely written here. `lane-verify` still
|
|
137
158
|
catches the last two before any phase acts on them; a profile id that matches nothing
|
|
@@ -152,7 +173,7 @@ Declaring **`(none)`** for a lane is a real answer and the way a project says it
|
|
|
152
173
|
|
|
153
174
|
## 3. The ownership rule
|
|
154
175
|
|
|
155
|
-
**Lane
|
|
176
|
+
**Lane root folders own their subtree and must be disjoint.** Two generators must never be able
|
|
156
177
|
to write the same file. A lane owns its test path too, so the rule covers both: no source or
|
|
157
178
|
test path of one lane may overlap a source or test path of another.
|
|
158
179
|
|
|
@@ -182,12 +203,19 @@ workflow.**
|
|
|
182
203
|
"title": "React + Vite", // shown in the menu
|
|
183
204
|
"language": "TypeScript", // shown in the menu, parenthesised
|
|
184
205
|
"ecosystem": "node", // which stack-partitioned corpus this stack draws from
|
|
185
|
-
"root": "
|
|
206
|
+
"root": "frontend/", // the folder a NEW lane of this stack gets — see §3.1
|
|
186
207
|
"test_root": "", // optional — where tests go when not inside root — see §4.3
|
|
187
|
-
"run_from": "root", // where the commands run — see §3.1
|
|
208
|
+
"run_from": "root", // where the commands run for a new lane — see §3.1
|
|
209
|
+
"conventional_root": "web/", // optional — where this stack's code usually sits in an
|
|
210
|
+
// EXISTING repository; `detect` is written against it
|
|
211
|
+
"conventional_test_root": "", // optional — the test path that pairs with it — see §4.3
|
|
212
|
+
"build_files": [], // optional — the files its commands need (`*.sln`,
|
|
213
|
+
// `go.mod`); decides `run_from` at declare time — §3.1
|
|
188
214
|
"build": "npm run build",
|
|
189
215
|
"test": "npm test",
|
|
190
216
|
"run": "npm run dev",
|
|
217
|
+
"host_patterns": [], // optional — where the runnable project sits, for
|
|
218
|
+
// `{{host}}` in a command — see §4.2
|
|
191
219
|
"migrate": "", // optional — schema migration, if the stack has one
|
|
192
220
|
"prototype_run": "npm run dev --prefix prototype", // frontend only — fills the prototype block
|
|
193
221
|
"reserved_names": ["Event", "Request", "Response"], // optional — names this stack's AMBIENT
|
|
@@ -209,49 +237,96 @@ trees that are physically per-ecosystem:
|
|
|
209
237
|
|
|
210
238
|
| Tree | Keyed by | Read through |
|
|
211
239
|
|---|---|---|
|
|
212
|
-
| `foundations/<ecosystem>/<Name>/` | `ecosystem
|
|
240
|
+
| `foundations/<ecosystem>/<Name>/` | `ecosystem`, then each pack/spec's `# kind:` / `# profiles:` header | `foundation-list`, `foundation-locate` |
|
|
213
241
|
| `foundations/<ecosystem>/components/<C>/` | `ecosystem` | `list-components`, `add-component` |
|
|
214
242
|
|
|
215
243
|
**Why those two are filtered and the rule corpora are not.** A foundation bundle is a whole
|
|
216
244
|
compiling project and a component runbook edits a host project's build files — both are
|
|
217
245
|
executable artifacts in one toolchain, so offering a `dotnet` bundle to a Spring repo does not
|
|
218
246
|
produce a scaffold, it produces a second foreign project beside the real one. `foundation-list`
|
|
219
|
-
therefore narrows by ecosystem, and reports `all_foundations` alongside so the
|
|
220
|
-
*what exists and
|
|
247
|
+
therefore narrows by ecosystem, and reports `all_foundations` alongside so the pick list can say
|
|
248
|
+
*what exists and how much of it applies*. `--ecosystem` narrows to the ONE lane being
|
|
221
249
|
scaffolded, which is what `foundation` passes: a repo declaring a .NET service and a Node UI
|
|
222
250
|
must not be offered its .NET bundle while the UI lane is the target. Without that argument the
|
|
223
251
|
filter falls back to every declared lane's ecosystem, and a repo that has declared nothing yet
|
|
224
252
|
is not filtered — there is no answer to filter on.
|
|
225
253
|
|
|
226
|
-
**
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
`
|
|
254
|
+
**Ecosystem alone is not narrow enough for a lane**, because it is shared across kinds: the
|
|
255
|
+
five JavaScript frontends and `node-express` are all `node`, and `blazor-wasm` shares `dotnet`
|
|
256
|
+
with the service stacks. So each pack and spec may open with header lines that `foundation-list`
|
|
257
|
+
filters on as well — `# kind: backend|frontend` (absent = backend, the kind every pack shipped
|
|
258
|
+
before the key existed scaffolds) and `# profiles: <id>, …` (absent = any profile of that kind).
|
|
259
|
+
|
|
260
|
+
**Packs and specs.** A directory under `foundations/<ecosystem>/` may hold a pack
|
|
261
|
+
(`<Name>.pack.txt` — a verified project unpacked byte-for-byte), any number of specs
|
|
262
|
+
(`*.spec.txt` — a description an agent builds the project from), or both; each is its own
|
|
263
|
+
entry in the lane's pick list, after which come `[manual spec]` (a spec given at the prompt)
|
|
264
|
+
and `[skip]`. `foundations/foundation.spec.template.txt` is the shape of a spec. A spec build
|
|
265
|
+
loads the technical rules the active project maps under `## /aw-spec-foundation-backend` or
|
|
266
|
+
`## /aw-spec-foundation-frontend` (§7), and the spec it used is kept at
|
|
267
|
+
`.appweaver/foundation/<lane>.spec.md`.
|
|
268
|
+
|
|
269
|
+
**A scaffold lands in a lane.** `foundation` scaffolds into the FOLDER of each lane — its
|
|
270
|
+
lane root folder, never a directory named on the command line — and the lane is self-contained
|
|
271
|
+
(§3.1): a pack unpacks there exactly as packed, build files, source and tests together, and a
|
|
272
|
+
spec build creates the whole project there and may write nowhere else — checked, not trusted:
|
|
273
|
+
the repo is recorded before the build and compared after it, and a build that created, changed
|
|
274
|
+
or deleted anything outside the lane root folder is "NOT accepted", with what it created there
|
|
275
|
+
removed again and what it changed or deleted listed for the operator. One run covers every
|
|
276
|
+
declared lane, backend then frontend, and each lane gets its own pick. A lane that does not run
|
|
277
|
+
its commands in its lane root folder, or keeps its tests outside it, is reported and passed over. A
|
|
278
|
+
lane that already holds files — any file in its source or test path — is asked "Overwrite?"
|
|
279
|
+
before its pick list; "no" skips the lane, and "yes" replaces same-path files and deletes
|
|
280
|
+
nothing. A pack's reference sample goes on top of the base project the same way. The one
|
|
281
|
+
exception is a pack's **rule file** (`<pack name>.rules.json` beside the pack): the files and
|
|
282
|
+
folders it names with `merge` are combined with the file already there, by an agent following
|
|
283
|
+
the rule's own instruction, instead of being replaced — the .NET reference samples use it to
|
|
284
|
+
merge their DbContext into the base project's. The format is in
|
|
285
|
+
[PACKAGING.md](../guardrails/technology/dotnet-webapi/PACKAGING.md#the-rule-file-pack-namerulesjson).
|
|
286
|
+
This is what makes every phase's "write only into your lane" rule true of the scaffold
|
|
287
|
+
as well as of generated code: `implement`, `build`, `test` and `run` all resolve the same
|
|
288
|
+
paths. Lanes must therefore be declared before `foundation` runs, which is why `select-stack`
|
|
289
|
+
is the first command of both sequences.
|
|
235
290
|
|
|
236
291
|
The technical RULE corpora at `guardrails/technology/<stack>/` are keyed by **profile id**, not
|
|
237
292
|
ecosystem, because Spring and Quarkus are both `java` and do not share a persistence rule. They
|
|
238
293
|
are selected through the project's `tech-rule-bindings.md` rather than filtered here — see §7.
|
|
239
294
|
|
|
240
|
-
### 4.2 `run_from`, `{{root}}` and `migrate`
|
|
295
|
+
### 4.2 `run_from`, `{{root}}`, `{{host}}` and `migrate`
|
|
241
296
|
|
|
242
|
-
A profile command sometimes has to name the
|
|
297
|
+
A profile command sometimes has to name the lane root folder — `python -m compileall app`. Written
|
|
243
298
|
literally that is the profile's *default* root frozen into the command, and it stays frozen when
|
|
244
299
|
a lane declares a different one. Write **`{{root}}`** instead and it resolves to the lane's own
|
|
245
|
-
root, expanded at run time so a hand-edited `root` in
|
|
300
|
+
root as seen from where the command runs, expanded at run time so a hand-edited `root` in
|
|
301
|
+
`stacks.json` stays consistent with it:
|
|
246
302
|
|
|
247
303
|
```jsonc
|
|
248
|
-
"
|
|
249
|
-
|
|
304
|
+
"build": "python -m compileall {{root}}" // app/, run at the repo root ⇒ python -m compileall app
|
|
305
|
+
// a run_from: root lane ⇒ python -m compileall .
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Some commands need a *project* inside the lane root folder rather than the folder itself.
|
|
309
|
+
`dotnet run --project <folder>` needs exactly one project in that folder, and a solution has
|
|
310
|
+
several — a pack's runnable one is `src/<App>.AppHost`, the .NET Aspire host. Write
|
|
311
|
+
**`{{host}}`** and it resolves to that project's folder, from the profile's `host_patterns`:
|
|
312
|
+
paths relative to the lane root folder, best first, `**/` for any depth, case ignored. The
|
|
313
|
+
first pattern that matches exactly one file names the project; build output, dependency and
|
|
314
|
+
test folders are never searched. It is looked up when the command is read, so a project
|
|
315
|
+
scaffolded after the lane was declared is found, and with no single match `{{host}}` falls
|
|
316
|
+
back to `{{root}}`:
|
|
317
|
+
|
|
318
|
+
```jsonc
|
|
319
|
+
"run": "dotnet run --project {{host}}",
|
|
320
|
+
"host_patterns": ["**/*.AppHost.csproj", "**/*.Api.csproj", "**/*.Service.csproj"]
|
|
321
|
+
// backend/ holding src/Acme.AppHost/ and src/Acme.Service/ ⇒ dotnet run --project src/Acme.AppHost
|
|
322
|
+
// backend/ holding src/Acme.Api/ and src/Acme.Domain/ ⇒ dotnet run --project src/Acme.Api
|
|
250
323
|
```
|
|
251
324
|
|
|
252
325
|
A command with no placeholder is used verbatim, so every literal command already on disk is
|
|
253
|
-
unaffected.
|
|
254
|
-
|
|
326
|
+
unaffected. A lane keeps the command it was declared with: one declared before `{{host}}` was
|
|
327
|
+
in its profile picks it up when select-stack declares it again. `{{root}}` and `{{host}}` are
|
|
328
|
+
the answer when the command needs a *path*; `run_from: "root"` (§3.1) is the answer when it
|
|
329
|
+
needs the *working directory*.
|
|
255
330
|
|
|
256
331
|
`migrate` is an optional fourth phase command, alongside `build`/`test`/`run`. **No shipped
|
|
257
332
|
profile declares one**, deliberately: Flyway, Liquibase, Alembic, Prisma and golang-migrate all
|
|
@@ -263,17 +338,21 @@ elsewhere rather than implying a migration succeeded.
|
|
|
263
338
|
`detect` is an **ANY-of** list, not an all-of: `java-spring` names both `pom.xml` and
|
|
264
339
|
`build.gradle` because a project has one or the other, and requiring both would make it
|
|
265
340
|
undetectable. `stack-detect` scores a profile by how many of its patterns hit. Patterns are
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
341
|
+
written against the layout an EXISTING repository of the stack usually has — the profile's
|
|
342
|
+
`conventional_root` (`web/package.json`, `src/**/*.csproj`) — and matched first as written
|
|
343
|
+
(repo-root-relative, with `**` spanning separators), then relocated under any directory prefix,
|
|
344
|
+
with that root segment substituted — so a profile shipping `web/package.json` still recognises
|
|
345
|
+
the same stack in `client/` or `apps/portal/`, which a brownfield repo that never saw our
|
|
269
346
|
profiles will need. An anchored hit outranks a relocated one.
|
|
270
347
|
|
|
271
348
|
`detect` and `root` are independent, and deliberately so: `go-chi` detects on `go.mod` at the
|
|
272
|
-
repo root
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
349
|
+
repo root, keeps its code under `internal/` in an existing repository, and gives a new lane
|
|
350
|
+
`backend/`. Detection reports the shallowest directory its evidence actually sits in; evidence
|
|
351
|
+
only at the repository root (`App.sln`, `go.mod`) defers to the `conventional_root` when that
|
|
352
|
+
directory is there, then to `root`. That directory is what `select-stack` offers first when it
|
|
353
|
+
asks for the lane root folder — ahead of the profile's own default, because a repo that
|
|
354
|
+
already exists did not choose its layout from our profiles. The operator picks from the list or
|
|
355
|
+
types a path the kit has never seen.
|
|
277
356
|
|
|
278
357
|
**Detection leads the menu; it never fills `preselect`.** The engine treats `preselect_from`
|
|
279
358
|
as the answer, ahead of a headless `--select`, so filling it from a scan would let a repo's
|
|
@@ -323,34 +402,37 @@ Absent, nothing is reported and generation is unchanged.
|
|
|
323
402
|
|
|
324
403
|
### 4.3 `test_root` — where a lane's tests go
|
|
325
404
|
|
|
326
|
-
|
|
327
|
-
to `src/`, Maven's `src/test/java/` next to `src/main/java/`,
|
|
328
|
-
|
|
329
|
-
**test path**, and `implement` writes the lane's
|
|
405
|
+
In an existing repository most backend stacks keep their tests **beside** the source, not
|
|
406
|
+
inside it: .NET's `tests/` next to `src/`, Maven's `src/test/java/` next to `src/main/java/`,
|
|
407
|
+
pytest's `tests/` next to `app/`. A new, self-contained lane keeps them inside its lane root folder
|
|
408
|
+
(`backend/tests/`). Either way each lane owns a **test path**, and `implement` writes the lane's
|
|
409
|
+
paired tests there.
|
|
330
410
|
|
|
331
|
-
A profile's `test_root` is the test path that pairs with its default `root
|
|
411
|
+
A profile's `test_root` is the test path that pairs with its default `root`, and its
|
|
412
|
+
`conventional_test_root` the one that pairs with its `conventional_root`. `lane-resolve` and
|
|
332
413
|
`lane-verify` report it per kind as `backend_test_path` / `frontend_test_path`, worked out at
|
|
333
414
|
read time:
|
|
334
415
|
|
|
335
416
|
| The lane | Its test path |
|
|
336
417
|
|---|---|
|
|
337
418
|
| declares `test_root` itself | that value |
|
|
338
|
-
| sits at the profile's default root (`
|
|
339
|
-
| sits at a path ending in the default root (`backend
|
|
340
|
-
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
`
|
|
345
|
-
fixed by writing `test_root` on the lane in `stacks.json`.
|
|
346
|
-
|
|
347
|
-
| Profile | `root` | `test_root` |
|
|
348
|
-
|
|
349
|
-
| `dotnet-webapi` | `src/` | `tests/` |
|
|
350
|
-
| `java-spring` | `src/main/java/` | `src/test/java/` |
|
|
351
|
-
| `python-fastapi` | `app/` | `tests/` |
|
|
352
|
-
| `node-express` | `src/` | `tests/` |
|
|
353
|
-
| `go-chi`
|
|
419
|
+
| sits at the profile's default root (`backend/`) | the profile's `test_root` (`backend/tests/`) |
|
|
420
|
+
| sits at a path ending in the default root (`apps/backend/`) | the profile's `test_root` under the same prefix (`apps/backend/tests/`) |
|
|
421
|
+
| sits at — or at a path ending in — the conventional root (`src/`, `svc/src/main/java/`) | the `conventional_test_root`, the same way (`tests/`, `svc/src/test/java/`) |
|
|
422
|
+
| anything else, or the profile declares neither | the lane root folder itself |
|
|
423
|
+
|
|
424
|
+
The last row is right for every shipped frontend (tests under `frontend/tests/`), for Go's
|
|
425
|
+
colocated `_test.go` files, and for a lane at any other folder name, whose tests are inside it.
|
|
426
|
+
A layout the table gets wrong is fixed by writing `test_root` on the lane in `stacks.json`.
|
|
427
|
+
|
|
428
|
+
| Profile | `root` | `test_root` | `conventional_root` | `conventional_test_root` |
|
|
429
|
+
|---|---|---|---|---|
|
|
430
|
+
| `dotnet-webapi` | `backend/` | `backend/tests/` | `src/` | `tests/` |
|
|
431
|
+
| `java-spring` | `backend/` | `backend/src/test/java/` | `src/main/java/` | `src/test/java/` |
|
|
432
|
+
| `python-fastapi` | `backend/` | `backend/tests/` | `app/` | `tests/` |
|
|
433
|
+
| `node-express` | `backend/` | `backend/tests/` | `src/` | `tests/` |
|
|
434
|
+
| `go-chi` | `backend/` | *(inside the lane root folder)* | `internal/` | — |
|
|
435
|
+
| every frontend | `frontend/` | *(inside the lane root folder)* | `web/` | — |
|
|
354
436
|
|
|
355
437
|
---
|
|
356
438
|
|
|
@@ -390,11 +472,12 @@ re-runs the roots-disjoint one on every read (see §2).
|
|
|
390
472
|
|
|
391
473
|
Consequences worth stating, because they are the reason for the design:
|
|
392
474
|
|
|
393
|
-
- **`foundation`
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
475
|
+
- **`foundation` scaffolds *into* a declared lane** and never rewrites the declaration to
|
|
476
|
+
fit what it produced. Each lane is scaffolded into its own source and test paths, and a
|
|
477
|
+
spec build must leave a project of the lane's own stack inside the lane — otherwise that
|
|
478
|
+
lane is reported "NOT usable" and the run moves on to the next one. A wrong declaration
|
|
479
|
+
surfaces at the scaffold instead of being absorbed by it, and the lane a project *chose*
|
|
480
|
+
stays the authority over the lane a generator *happened to produce*.
|
|
398
481
|
- **`build` runs every declared lane's own build command**, in declaration order, and
|
|
399
482
|
fails if any lane fails. Without a declaration it falls back to the historic
|
|
400
483
|
first-match-wins sniffer, which is right for one lane and silently skips the second —
|
|
@@ -411,7 +494,7 @@ follows from it:
|
|
|
411
494
|
| Which rule sets does `onboard` generate? | the same, per lane — `service/` and `frontend/` under the project folder |
|
|
412
495
|
| Which subtree does `implement` write into? | that lane's `root` |
|
|
413
496
|
| What does `build` compile, and `run` migrate? | every declared lane's own command, against its own root |
|
|
414
|
-
| What does `onboard` scan? | the declared
|
|
497
|
+
| What does `onboard` scan? | the declared lane root folders — backend signals from outside the UI subtree, frontend signals from inside it |
|
|
415
498
|
|
|
416
499
|
This is a change of authority, and worth being explicit about. The question "does this
|
|
417
500
|
project have a UI lane" used to be answered by OR-ing three heuristics: a
|
|
@@ -441,13 +524,15 @@ constraint where it previously had none. That is a deliberate trade: what it buy
|
|
|
441
524
|
every later phase can ask this file a question and get an answer, instead of inferring one.
|
|
442
525
|
|
|
443
526
|
```
|
|
444
|
-
GREENFIELD select-stack →
|
|
527
|
+
GREENFIELD select-stack → constitution → [select-feature] → specify → …
|
|
445
528
|
BROWNFIELD select-stack → onboard → select-feature → adopt → …
|
|
446
529
|
```
|
|
447
530
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
531
|
+
Neither sequence selects a project. Greenfield uses `guardrails/project-specific/`, which
|
|
532
|
+
`.appweaver/domain.json` names as shipped; `onboard` creates `guardrails/brf-<domain>/` from
|
|
533
|
+
the code and points `domain.json` at it. The optional `select-domain` switches `domain.json` to
|
|
534
|
+
another project folder under `guardrails/` that already exists. On an existing codebase `select-stack` is mostly confirmation — it detects the
|
|
535
|
+
stack and the lane root folder from the repo's own files and leads the menu with them — but it is
|
|
451
536
|
a person's confirmation, which is what detection on a legacy repo needs.
|
|
452
537
|
|
|
453
538
|
## 6. Subcommands
|
|
@@ -460,7 +545,7 @@ implementation and the twins cannot drift.
|
|
|
460
545
|
|---|---|
|
|
461
546
|
| `stack-list [--kind k] [--preselect text] [--include-none] [--suggest]` | enumerate the installed profiles; returns `select_options[]`, and `preselect` when the text names one of *this kind's* ids. `--suggest` also runs detection, so the menu **leads with** the stack this repo's files point at and `root_options[]` leads with the directory the evidence sits in |
|
|
462
547
|
| `stack-detect [--kind k] [--exclude-root p]…` | match the repo's OWN files against the installed profiles — the brownfield candidate list, since an existing repo already answered the question. Writes nothing. `--exclude-root` keeps a service profile from relocating onto a subtree another lane owns |
|
|
463
|
-
| `lane-declare --profile <id\|label\|none\|detected> [--kind k] [--id lane] [--source-path\|--root p] [--stack label] [--origin declared\|reverse-engineered] [--build/--test/--run/--migrate c] [--run-from repo\|root] [--no-prototype] [--require-existing-root]` | upsert a lane — **the sole writer**. `detected` declares a stack the kit ships no profile for (needs `--stack` and a
|
|
548
|
+
| `lane-declare --profile <id\|label\|none\|detected> [--kind k] [--id lane] [--source-path\|--root p] [--stack label] [--origin declared\|reverse-engineered] [--build/--test/--run/--migrate c] [--run-from repo\|root] [--no-prototype] [--require-existing-root]` | upsert a lane — **the sole writer**. `detected` declares a stack the kit ships no profile for (needs `--stack` and a lane root folder), which is how a legacy WebForms, JSP or ERB lane gets recorded at all |
|
|
464
549
|
| `lane-resolve [--kind k] [--id lane]` | read; exit 0 always. `exists` reports the file, `declared` reports the lanes — the shipped-but-unfilled seed is `exists:true, declared:false`. Returns the matched lane **and** both kinds flattened — `backend_source_path`, `frontend_root_exists`, `backend_build` … — so a workflow binds one variable instead of calling twice |
|
|
465
550
|
| `lane-verify [--require backend\|frontend]… [--allow-missing-root] [--command phase]` | **the gate**: is the declaration usable for the phase about to run. Never writes, and **always exits 0** — the calling workflow's `verify_context` owns the stop, so the reason arrives as text |
|
|
466
551
|
| `lane-probe [--kind k] [--hint text]` | read; the **file** signals for "does this lane exist" — a declared lane, and a stack named in free prose. Retained for callers that want a soft hint; the authoritative answer is the declaration, read through `lane-resolve` or `lane-verify` |
|
|
@@ -474,10 +559,11 @@ set**, so a caller binds outputs without knowing which branch ran.
|
|
|
474
559
|
|---|---|---|
|
|
475
560
|
| `build-compile` | every declared lane's own `build`, via `run-phase` | the historic first-match-wins ladder |
|
|
476
561
|
| `test-run` | every declared lane's own `test`, via `run-phase` — **except** `--scope slice` on a repo where a .NET toolchain is present, which keeps the VSTest `--filter` path | the historic ladder |
|
|
477
|
-
| `run-migrate` | a lane's declared `migrate` (§4.2) when there is one; otherwise `dotnet ef` searched under the **service lane
|
|
478
|
-
| `find-host-project` | searches the service lane
|
|
479
|
-
| `foundation-list`, `list-components` | narrowed to the `ecosystem` of the lane being scaffolded, else of every declared lane (§4.1) | unfiltered / `dotnet` |
|
|
480
|
-
| `foundation-unpack` | unpacks into the lane
|
|
562
|
+
| `run-migrate` | a lane's declared `migrate` (§4.2) when there is one; otherwise `dotnet ef` searched under the **service lane root folder** rather than an assumed `src/` | `dotnet ef` under `src/` |
|
|
563
|
+
| `find-host-project` | searches the service lane root folder, and reports the lane's `ecosystem` | searches `src/` |
|
|
564
|
+
| `foundation-list`, `list-components` | narrowed to the `ecosystem` of the lane being scaffolded, else of every declared lane; `foundation-list` also by each entry's `# kind:` / `# profiles:` (§4.1) | unfiltered / `dotnet` |
|
|
565
|
+
| `foundation-unpack` | unpacks into the **lane root folder**, and lifts a packed test tree onto its **test path** (§4.1, §4.3) | cannot run — `foundation` stops until a lane is declared |
|
|
566
|
+
| `build-compile --kind` | that one lane's own `build` — what `foundation` runs after a spec build | the ladder; `--kind` is ignored |
|
|
481
567
|
| `resolve-tech` | expands stack placeholders and flags a corpus mismatch (§7a) | no placeholders resolve; nothing is flagged |
|
|
482
568
|
|
|
483
569
|
**Why `--scope slice` is the one exception.** VSTest's `--filter FullyQualifiedName~` is the
|
|
@@ -498,16 +584,17 @@ No workflow or script changes. If adding a stack ever requires touching a workfl
|
|
|
498
584
|
model is wrong and that is the bug to fix.
|
|
499
585
|
|
|
500
586
|
That gives the new stack every phase that is driven by a **command** — build, test, run,
|
|
501
|
-
migrate — plus the correct
|
|
587
|
+
migrate — plus the correct lane root folder everywhere, immediately. Two things are opt-in because
|
|
502
588
|
they are content the kit cannot invent:
|
|
503
589
|
|
|
504
590
|
- **Technical rules** — a corpus at `guardrails/technology/<id>/`, mapped from the project's
|
|
505
591
|
`tech-rule-bindings.md` (§7a). Until one exists the stack runs with the universal
|
|
506
592
|
`ai-rules.md` and the technical constitution, which is the greenfield-safe default, not an
|
|
507
593
|
error.
|
|
508
|
-
- **A foundation
|
|
509
|
-
foundation` to
|
|
510
|
-
|
|
594
|
+
- **A foundation pack or spec** — `foundations/<ecosystem>/<Name>/`, only if you want
|
|
595
|
+
`/appweaver foundation` to offer one for this stack (give it `# kind:` / `# profiles:`
|
|
596
|
+
header lines). Without one, `foundation` still offers `[manual spec]` for the lane, and
|
|
597
|
+
scaffolding with the stack's own tooling is fully supported: `implement` generates INTO a
|
|
511
598
|
project tree and does not require that the kit created it.
|
|
512
599
|
|
|
513
600
|
## 7a. Mapping rules to a stack without pinning the map to one
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"domain":""}
|
|
1
|
+
{"domain":"project-specific"}
|
|
@@ -9,11 +9,27 @@ for that agent; the engine that consumes it is the *general* file in `.appweaver
|
|
|
9
9
|
```
|
|
10
10
|
.appweaver/orchestrator/orchestrator.py ← general engine (reads a profile)
|
|
11
11
|
.appweaver/orchestrator/adapters/*.py ← shared SDK adapters (one per SDK, not per agent)
|
|
12
|
-
.claude/agent.json ← Claude Code profile
|
|
13
|
-
.agents/agent.json ← Antigravity profile
|
|
14
|
-
.
|
|
12
|
+
.claude/agent.json ← Claude Code profile (claude -p / claude-agent-sdk)
|
|
13
|
+
.agents/agent.json ← Antigravity profile (agy -p / google-antigravity)
|
|
14
|
+
.kilo/agent.json ← Kilo Code profile (kilo run / claude-agent-sdk)
|
|
15
|
+
.cursor/agent.json ← Cursor profile (cursor-agent -p)
|
|
16
|
+
.copilot/agent.json ← GitHub Copilot profile (copilot -p)
|
|
17
|
+
.devin/agent.json ← Devin profile (devin -p)
|
|
18
|
+
.cline/agent.json ← Cline profile (cline)
|
|
19
|
+
.roo/agent.json ← Roo Code profile (roo --print)
|
|
20
|
+
.opencode/agent.json ← opencode profile (opencode run)
|
|
21
|
+
.factory/agent.json ← Factory Droid profile (droid exec)
|
|
22
|
+
.augment/agent.json ← Augment profile (auggie --print)
|
|
23
|
+
.continue/agent.json ← Continue profile (cn -p)
|
|
24
|
+
.kiro/agent.json ← Kiro profile (kiro-cli chat)
|
|
25
|
+
.codex/agent.json ← OpenAI Codex profile (codex exec)
|
|
26
|
+
.gemini/agent.json ← Gemini CLI profile (gemini -p)
|
|
27
|
+
.amp/agent.json ← Amp profile (amp -x)
|
|
15
28
|
```
|
|
16
29
|
|
|
30
|
+
Only the first three have an `sdk` block; the rest support the `agent` and
|
|
31
|
+
`spawn` strategies.
|
|
32
|
+
|
|
17
33
|
The launcher passes its profile with `--agent-profile <path>` (which implies
|
|
18
34
|
`--transport real`).
|
|
19
35
|
|
|
@@ -60,7 +76,7 @@ options). Adapters are keyed by SDK, not by agent:
|
|
|
60
76
|
`adapters/google_antigravity.py` maps the neutral permission modes onto
|
|
61
77
|
Antigravity policies and drives `Agent` / `LocalAgentConfig` (used by
|
|
62
78
|
`.agents`), while `adapters/claude_agent_sdk.py` drives `query` /
|
|
63
|
-
`ClaudeAgentOptions` (shared by `.claude` and `.
|
|
79
|
+
`ClaudeAgentOptions` (shared by `.claude` and `.kilo`, whose SDK is the
|
|
64
80
|
same) — none of which the engine knows about; it only follows the profile's
|
|
65
81
|
`sdk.adapter` pointer.
|
|
66
82
|
|
|
@@ -87,11 +103,23 @@ When `system` is `"prepend"`, the system block is folded into the prompt
|
|
|
87
103
|
## Adding a new agent
|
|
88
104
|
|
|
89
105
|
1. Drop an `agent.json` at that agent's root (`.<agent>/agent.json`) describing its CLI.
|
|
90
|
-
2. Add
|
|
91
|
-
|
|
92
|
-
|
|
106
|
+
2. Add the agent's row to the profile table in `.appweaver/orchestrator/LAUNCHER.md`.
|
|
107
|
+
The launchers in folders several agents read (`.claude/skills/`, `.agents/skills/`)
|
|
108
|
+
name no agent; an agent loading one of them finds its profile in that table.
|
|
109
|
+
3. Add a launcher in that agent's native format that points at `LAUNCHER.md` and
|
|
110
|
+
names `.<agent>/agent.json` as the agent's profile — `.cursor/commands/appweaver.md`
|
|
111
|
+
is the shortest example.
|
|
112
|
+
4. For the `sdk`/`sdk-apply` strategies, add an `sdk` block and point
|
|
93
113
|
`sdk.adapter` at the matching adapter in `.appweaver/orchestrator/adapters/`
|
|
94
114
|
— or drop a new adapter there first if that SDK has none yet.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
5. Add the agent's folder (and its launcher folder, if different) to `KIT_AGENT_DIRS`
|
|
116
|
+
in `.appweaver/scripts/python/aw-inventory.py`, so a brownfield inventory does not
|
|
117
|
+
read the kit's files as the project's own. When the launcher sits in a folder the
|
|
118
|
+
project also uses (as `.github/` holds its CI), add the launcher's exact path to
|
|
119
|
+
`KIT_AGENT_FILES` instead.
|
|
120
|
+
|
|
121
|
+
No engine change required. Verify with `--dry-run` on `_smoke.orch.yaml`
|
|
122
|
+
(`--non-interactive --strategy spawn --agent-profile .<agent>/agent.json --dry-run`):
|
|
123
|
+
it prints the exact command the profile builds for every model step — the
|
|
124
|
+
read-only `agent_query`, `agent_author` and `agent_review`, and the `agent_generate`
|
|
125
|
+
edit step — without executing any of them.
|