@atlashub/smartstack-cli 3.32.0 → 3.34.0

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 (55) hide show
  1. package/.documentation/agents.html +5 -1
  2. package/.documentation/apex.html +644 -0
  3. package/.documentation/business-analyse.html +81 -1
  4. package/.documentation/cli-commands.html +5 -1
  5. package/.documentation/commands.html +5 -1
  6. package/.documentation/efcore.html +5 -1
  7. package/.documentation/gitflow.html +5 -1
  8. package/.documentation/hooks.html +5 -1
  9. package/.documentation/index.html +60 -2
  10. package/.documentation/init.html +5 -1
  11. package/.documentation/installation.html +5 -1
  12. package/.documentation/ralph-loop.html +365 -216
  13. package/.documentation/test-web.html +5 -1
  14. package/package.json +1 -1
  15. package/templates/agents/ba-writer.md +142 -15
  16. package/templates/skills/apex/SKILL.md +7 -1
  17. package/templates/skills/apex/_shared.md +49 -4
  18. package/templates/skills/{ralph-loop → apex}/references/core-seed-data.md +20 -11
  19. package/templates/skills/{ralph-loop → apex}/references/error-classification.md +2 -1
  20. package/templates/skills/apex/references/post-checks.md +238 -3
  21. package/templates/skills/apex/references/smartstack-api.md +47 -7
  22. package/templates/skills/apex/references/smartstack-frontend.md +47 -1
  23. package/templates/skills/apex/references/smartstack-layers.md +3 -1
  24. package/templates/skills/apex/steps/step-00-init.md +48 -1
  25. package/templates/skills/apex/steps/step-01-analyze.md +37 -0
  26. package/templates/skills/apex/steps/step-02-plan.md +36 -0
  27. package/templates/skills/apex/steps/step-03-execute.md +42 -2
  28. package/templates/skills/apex/steps/step-04-examine.md +110 -2
  29. package/templates/skills/business-analyse/SKILL.md +29 -19
  30. package/templates/skills/business-analyse/_module-loop.md +68 -9
  31. package/templates/skills/business-analyse/_shared.md +71 -21
  32. package/templates/skills/business-analyse/questionnaire/00-application.md +4 -2
  33. package/templates/skills/business-analyse/questionnaire/00b-project.md +85 -0
  34. package/templates/skills/business-analyse/references/deploy-modes.md +69 -0
  35. package/templates/skills/business-analyse/references/team-orchestration.md +158 -7
  36. package/templates/skills/business-analyse/schemas/application-schema.json +2 -1
  37. package/templates/skills/business-analyse/schemas/project-schema.json +490 -0
  38. package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -1
  39. package/templates/skills/business-analyse/steps/step-00-init.md +30 -4
  40. package/templates/skills/business-analyse/steps/step-01-cadrage.md +62 -2
  41. package/templates/skills/business-analyse/steps/step-01b-applications.md +252 -0
  42. package/templates/skills/business-analyse/steps/step-02-decomposition.md +23 -6
  43. package/templates/skills/business-analyse/steps/step-03d-validate.md +27 -6
  44. package/templates/skills/business-analyse/steps/step-04a-collect.md +111 -0
  45. package/templates/skills/business-analyse/steps/step-05a-handoff.md +296 -103
  46. package/templates/skills/business-analyse/steps/step-05b-deploy.md +46 -14
  47. package/templates/skills/documentation/SKILL.md +92 -2
  48. package/templates/skills/ralph-loop/SKILL.md +9 -17
  49. package/templates/skills/ralph-loop/references/category-rules.md +43 -692
  50. package/templates/skills/ralph-loop/references/compact-loop.md +104 -427
  51. package/templates/skills/ralph-loop/references/team-orchestration.md +13 -14
  52. package/templates/skills/ralph-loop/steps/step-02-execute.md +49 -704
  53. package/templates/skills/ralph-loop/steps/step-03-commit.md +38 -79
  54. package/templates/skills/ralph-loop/steps/step-04-check.md +39 -58
  55. package/templates/skills/ralph-loop/steps/step-05-report.md +12 -123
@@ -1,7 +1,7 @@
1
- # Compact Loop — Inline Execution
1
+ # Compact Loop — Delegate to /apex
2
2
 
3
3
  > **Loaded by:** step-04 section 5 (after first full iteration)
4
- > **Purpose:** Execute ALL remaining tasks autonomously without stopping.
4
+ > **Purpose:** Execute ALL remaining tasks autonomously by delegating to /apex.
5
5
  > **EXECUTION GUARANTEE:** This loop runs until ALL tasks are done, max iterations, or dead-end.
6
6
  > **ABSOLUTE RULES:**
7
7
  > - NEVER stop the loop
@@ -9,6 +9,7 @@
9
9
  > - NEVER ask for confirmation
10
10
  > - NEVER re-read step files
11
11
  > - NEVER pause between iterations
12
+ > - NEVER generate code directly — delegate to /apex
12
13
  > - Execute A → B → C → D → back to step-04 section 1 → repeat
13
14
 
14
15
  ---
@@ -26,8 +27,35 @@ Display compact progress:
26
27
 
27
28
  ```javascript
28
29
  const prd = readJSON('.ralph/prd.json');
30
+ const MAX_RETRIES = 3;
29
31
 
30
- // Block tasks whose dependencies failed
32
+ // RETRY: Reset failed tasks to pending if retries remain (max 3 attempts per task)
33
+ for (const task of prd.tasks) {
34
+ if (task.status !== 'failed') continue;
35
+ const retryCount = task._retryCount || 0;
36
+ if (retryCount < MAX_RETRIES) {
37
+ task.status = 'pending';
38
+ task._retryCount = retryCount + 1;
39
+ task.error = null;
40
+ console.log(`RETRY [${task.id}] attempt ${retryCount + 1}/${MAX_RETRIES}: ${task.description.substring(0, 60)}`);
41
+ }
42
+ }
43
+
44
+ // Unblock tasks whose dependencies are no longer failed (due to retries above)
45
+ for (const task of prd.tasks) {
46
+ if (task.status !== 'blocked') continue;
47
+ const stillBlocked = task.dependencies.some(depId => {
48
+ const dep = prd.tasks.find(t => t.id === depId);
49
+ return dep && (dep.status === 'failed' || dep.status === 'blocked');
50
+ });
51
+ if (!stillBlocked) {
52
+ task.status = 'pending';
53
+ task.error = null;
54
+ console.log(`UNBLOCKED [${task.id}]: dependencies resolved`);
55
+ }
56
+ }
57
+
58
+ // Block pending tasks whose dependencies are still failed/blocked
31
59
  for (const task of prd.tasks) {
32
60
  if (task.status !== 'pending') continue;
33
61
  const depsBlocked = task.dependencies.some(depId => {
@@ -37,6 +65,8 @@ for (const task of prd.tasks) {
37
65
  if (depsBlocked) { task.status = 'blocked'; task.error = 'Blocked by failed dependency'; }
38
66
  }
39
67
 
68
+ writeJSON('.ralph/prd.json', prd);
69
+
40
70
  // Find ALL eligible tasks (dependencies met)
41
71
  const eligible = prd.tasks.filter(task => {
42
72
  if (task.status !== 'pending') return false;
@@ -63,463 +93,110 @@ Batch: {batch.length} [{firstCategory}] → {batch.map(t => `[${t.id}] ${t.descr
63
93
 
64
94
  ---
65
95
 
66
- ## B. Execute Batch
67
-
68
- **For EACH task in batch:**
69
-
70
- 1. Mark `task.status = 'in_progress'`, `task.started_at = now`
71
- 2. **Read `references/category-rules.md`** for category-specific rules
72
- 2bis. **For frontend tasks:** Also read back the original **feature.json** (via `prd.source.featurePath`) to access wireframe `componentMapping`, `columnDefs`, `layout`, `emptyState`, `rowActions`, and `i18n` keys that the PRD does NOT carry forward. The PRD only has the file list — the behavioral spec is in feature.json.
73
- 3. Implement the task following SmartStack conventions
74
- 4. Track `files_created` and `files_modified`
75
-
76
- **Execution cycle per task:**
77
- 1. Generate code following category-rules.md
78
- 2. **BUILD verification (BLOCKING per task):**
79
- - Backend (domain/infra/app/api): `dotnet build --no-restore` → MUST exit 0
80
- - Frontend: `npm run typecheck` → MUST exit 0
81
- 3. If build fails → **CLASSIFY ERROR FIRST** (read `references/error-classification.md`):
82
- - **Category A/B (assembly/package):** Run `dotnet add package {Name}` → `dotnet restore` → rebuild. Do NOT edit source code.
83
- - **Category C (DI):** Edit DI registration file only → rebuild.
84
- - **Category D (migration):** Run migration commands → rebuild.
85
- - **Category E (config):** Edit config file → rebuild.
86
- - **Category F (code):** Fix source code → rebuild → loop until pass.
87
- - **If 2+ rebuild attempts fail on same error and Category F was chosen:** Re-classify — likely wrong category.
88
- 4. **ARTIFACT verification (BLOCKING per task):**
89
- - `files_created` MUST NOT be empty for code-generating tasks
90
- - Category-specific checks (see below)
91
- - IF no artifacts produced → task.status = 'failed', task.error = 'No artifacts created'
92
- 5. Verify acceptance criteria from task description
93
- 6. If failed after 3 attempts: `task.status = 'failed'`, `task.error = reason`, continue to next in batch
94
-
95
- **Category-specific artifact checks (step 4 above):**
96
-
97
- | Category | Artifact Check | FAIL if |
98
- |----------|---------------|---------|
99
- | `domain` | Entity .cs files exist in Domain/ | 0 files created |
100
- | `infrastructure` with migration | `Migrations/` folder has .cs files | No migration files |
101
- | `infrastructure` with seed data | Seed data .cs files exist | 0 files created |
102
- | `application` | Service + DTO + Validator files exist | 0 files created |
103
- | `api` | Controller .cs files exist + GetAll supports `?search=` | 0 files created OR GetAll without search param |
104
- | `frontend` | .tsx page files exist + FK fields use EntityLookup (not plain text) | 0 files created OR FK Guid field as `<input type="text">` |
105
- | `test` | Test project dir exists AND contains test .cs files | No test project or 0 test files |
106
- | `validation` | `dotnet test` exit 0 AND `dotnet build` exit 0 | Either command fails |
107
-
108
- **Category-specific triggers:**
109
-
110
- | Category | Action |
111
- |----------|--------|
112
- | `infrastructure` with `_migrationMeta` | Migration sequence: `suggest_migration` MCP → `dotnet ef migrations add` → cleanup corrupted artifacts (`for d in src/*/bin?Debug; do [ -d "$d" ] && rm -rf "$d"; done`) → `dotnet ef database update` → `dotnet build` |
113
- | `infrastructure` with seed data keywords | **MANDATORY:** Read `references/core-seed-data.md` → implement templates → `dotnet build` |
114
- | `frontend` | MCP-first: `scaffold_api_client` → `scaffold_routes` (outputFormat: clientRoutes) → **wire to App.tsx** → **LOAD `/ui-components` skill** before creating ANY page → create pages using skill patterns (SmartTable, EntityCard, CSS variables, StatusBadge) → ALL visible text via `t()` from first line → `npm run typecheck && npm run lint` → **run frontend POST-CHECKs (section 3bis below)** |
115
- | `test` | **Create tests:** `scaffold_tests` MCP → **Run:** `dotnet test --verbosity normal` → **Fix loop:** if fail → fix SOURCE CODE → rebuild → retest → repeat until 100% pass |
116
- | `validation` | `dotnet clean && dotnet restore && dotnet build` → `dotnet test` (full) → `validate_conventions` MCP |
117
-
118
- **Post-batch verification (BLOCKING — ALL must pass before commit):**
119
-
120
- 1. **Backend build:**
121
- ```bash
122
- dotnet build --no-restore
123
- ```
124
- If FAIL → fix → rebuild → DO NOT commit until exit 0
125
-
126
- 2. **Tests (if test tasks in batch OR after infrastructure batch):**
127
- ```bash
128
- TEST_PROJECT="tests/$(basename $(pwd)).Tests.Unit"
129
- dotnet test "$TEST_PROJECT" --no-build --verbosity normal
130
- ```
131
- If FAIL → fix source code (NOT tests) → rebuild → retest → loop until 100% pass
132
-
133
- 2bis. **Runtime assembly check (if api/validation tasks in batch):**
134
- ```bash
135
- API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
136
- if [ -n "$API_PROJECT" ]; then
137
- dotnet run --project "$API_PROJECT" --urls "http://localhost:5098" > /tmp/ralph-startup-check.log 2>&1 &
138
- CHECK_PID=$!
139
- sleep 5
140
- if ! kill -0 $CHECK_PID 2>/dev/null; then
141
- CRASH_OUTPUT=$(cat /tmp/ralph-startup-check.log 2>/dev/null)
142
- echo "RUNTIME ASSEMBLY ERROR DETECTED"
143
- # Classify per references/error-classification.md
144
- # If Category A: dotnet add package → rebuild → DO NOT count as iteration failure
145
- fi
146
- kill $CHECK_PID 2>/dev/null
147
- wait $CHECK_PID 2>/dev/null
148
- rm -f /tmp/ralph-startup-check.log
149
- fi
150
- ```
151
- If FAIL → classify error per `references/error-classification.md` → apply fix → rebuild → verify again
152
-
153
- 2ter. **DI completeness (if application tasks in batch):**
154
- Verify `Application/DependencyInjection.cs` registers all validators and services:
155
- - Count validators in `Validators/` folder
156
- - Verify `AddValidatorsFromAssemblyContaining` is present
157
- - If empty/TODO → FAIL → fix DI registration → rebuild
158
-
159
- 3. **Frontend (if frontend/i18n tasks in batch):**
160
- ```bash
161
- npm run typecheck && npm run lint
162
- ```
163
- If FAIL → fix → re-check → loop until pass
164
-
165
- 3bis. **Frontend POST-CHECKs (BLOCKING — if frontend tasks in batch):**
166
-
167
- > **CRITICAL:** These checks enforce /ui-components compliance, i18n, and route conventions.
168
- > Without them, generated code silently regresses to raw HTML tables, hardcoded colors, and English-only text.
169
-
170
- ```bash
171
- # Resolve paths dynamically (handles web/ prefix)
172
- PAGE_DIR=$(find . -path "*/src/pages" -not -path "*/node_modules/*" -type d 2>/dev/null | head -1)
173
- HOOK_DIR=$(find . -path "*/src/hooks" -not -path "*/node_modules/*" -type d 2>/dev/null | head -1)
174
- COMP_DIR=$(find . -path "*/src/components" -not -path "*/node_modules/*" -type d 2>/dev/null | head -1)
175
- WEB_SRC=$(find . -name "App.tsx" -not -path "*/node_modules/*" -exec dirname {} \; 2>/dev/null | head -1)
176
-
177
- if [ -n "$PAGE_DIR" ]; then
178
- # BLOCKING: No raw HTML <table> — MUST use SmartTable/DataTable
179
- RAW_TABLES=$(grep -rPn '<table[\s>]|<thead[\s>]|<tbody[\s>]' "$PAGE_DIR" --include="*.tsx" 2>/dev/null)
180
- if [ -n "$RAW_TABLES" ]; then
181
- echo "BLOCKING: Raw HTML <table> detected — MUST use SmartTable or DataTable"
182
- echo "$RAW_TABLES" | head -5
183
- # FIX REQUIRED before commit
184
- fi
185
-
186
- # BLOCKING: No hardcoded Tailwind colors — MUST use CSS variables
187
- HARDCODED_COLORS=$(grep -rPn '(?:bg|text|border|ring)-(?:red|blue|green|yellow|orange|purple|pink|indigo|teal|cyan|emerald|violet|fuchsia|rose|amber|lime|sky|slate|gray|zinc|neutral|stone)-\d{2,3}' "$PAGE_DIR" "$COMP_DIR" --include="*.tsx" 2>/dev/null | head -10)
188
- if [ -n "$HARDCODED_COLORS" ]; then
189
- echo "BLOCKING: Hardcoded Tailwind colors — MUST use CSS variables (bg-[var(--bg-secondary)])"
190
- echo "$HARDCODED_COLORS" | head -5
191
- # FIX REQUIRED before commit
192
- fi
193
-
194
- # BLOCKING: No window.confirm() — use ConfirmDialog component
195
- BAD_CONFIRM=$(grep -rPn 'window\.confirm\s*\(' "$PAGE_DIR" --include="*.tsx" 2>/dev/null | grep -v '//')
196
- if [ -n "$BAD_CONFIRM" ]; then
197
- echo "BLOCKING: window.confirm() detected — use ConfirmDialog component with i18n"
198
- echo "$BAD_CONFIRM"
199
- # FIX REQUIRED before commit
200
- fi
201
-
202
- # BLOCKING: No hardcoded English UI text in JSX
203
- HARDCODED_TEXT=$(grep -rPn '>\s*(Create|Edit|Delete|Save|Cancel|Search|Loading|Error|No .* found|Are you sure|Submit|Back|Actions|Status)\s*<' "$PAGE_DIR" --include="*.tsx" 2>/dev/null | grep -v test | grep -v '//' | head -10)
204
- if [ -n "$HARDCODED_TEXT" ]; then
205
- echo "BLOCKING: Hardcoded English text — ALL visible text MUST use t() from useTranslation()"
206
- echo "$HARDCODED_TEXT" | head -5
207
- # FIX REQUIRED before commit
208
- fi
209
-
210
- # BLOCKING: No modals/drawers for forms — forms are full pages
211
- MODAL_IMPORTS=$(grep -rPn "import.*\b(Modal|Dialog|Drawer|Popup|Sheet)\b" "$PAGE_DIR" --include="*.tsx" 2>/dev/null)
212
- if [ -n "$MODAL_IMPORTS" ]; then
213
- echo "BLOCKING: Form modals/dialogs detected — forms MUST be full pages with own URL"
214
- echo "$MODAL_IMPORTS"
215
- # FIX REQUIRED before commit
216
- fi
217
- fi
218
-
219
- if [ -n "$HOOK_DIR" ]; then
220
- # BLOCKING: Hooks must use i18n for error messages
221
- HARDCODED_ERRORS=$(grep -rPn "(setError|throw new Error)\(['\"][A-Z]" "$HOOK_DIR" --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v "t(" | head -10)
222
- if [ -n "$HARDCODED_ERRORS" ]; then
223
- echo "BLOCKING: Hardcoded error messages in hooks — MUST use t('{mod}:errors.xxx')"
224
- echo "$HARDCODED_ERRORS" | head -5
225
- # FIX REQUIRED before commit
226
- fi
227
- fi
228
-
229
- # BLOCKING: i18n file structure — 4 languages with module-specific JSON files
230
- if [ -n "$WEB_SRC" ]; then
231
- I18N_DIR="$WEB_SRC/i18n/locales"
232
- if [ -d "$I18N_DIR" ]; then
233
- for LANG in fr en it de; do
234
- if [ ! -d "$I18N_DIR/$LANG" ]; then
235
- echo "BLOCKING: Missing i18n locale directory: $I18N_DIR/$LANG"
236
- # FIX REQUIRED before commit
237
- fi
238
- MODULE_JSONS=$(find "$I18N_DIR/$LANG" -name "*.json" ! -name "common.json" ! -name "navigation.json" 2>/dev/null)
239
- if [ -z "$MODULE_JSONS" ]; then
240
- echo "BLOCKING: No module translation files in $I18N_DIR/$LANG/"
241
- # FIX REQUIRED before commit
242
- fi
243
- done
244
- else
245
- echo "BLOCKING: Missing i18n/locales directory"
246
- # FIX REQUIRED before commit
247
- fi
248
- fi
249
-
250
- # Cross-validate route conventions (frontend vs backend)
251
- APP_TSX=$(find . -name "App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
252
- API_CONTROLLERS=$(find . -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
253
- if [ -n "$APP_TSX" ] && [ -n "$API_CONTROLLERS" ]; then
254
- API_SEGMENTS=$(grep -ohP '\[Route\("api/([^"]+)"\)\]' $API_CONTROLLERS | sed 's/\[Route("api\///;s/")\]//' | tr '/' '\n' | sort -u)
255
- CLIENT_PATHS=$(grep -ohP "path:\s*['\"]([^'\"]+)['\"]" "$APP_TSX" | sed "s/path:\s*['\"]//;s/['\"]//" | sort -u)
256
- for SEG in $API_SEGMENTS; do
257
- if echo "$SEG" | grep -qP '[a-z]+-[a-z]+'; then
258
- NO_HYPHEN=$(echo "$SEG" | tr -d '-')
259
- if echo "$CLIENT_PATHS" | grep -q "$NO_HYPHEN"; then
260
- echo "BLOCKING: Frontend uses '$NO_HYPHEN' but backend uses '$SEG' (kebab-case mismatch)"
261
- # FIX REQUIRED before commit
262
- fi
263
- fi
264
- done
265
- fi
266
- ```
267
- # BLOCKING: No custom entity hooks wrapping services (test-v4-014 root cause)
268
- if [ -n "$HOOK_DIR" ]; then
269
- CUSTOM_HOOKS=$(find "$HOOK_DIR" -name "use*.ts" -o -name "use*.tsx" 2>/dev/null | grep -iv "Preferences" | grep -v "node_modules")
270
- if [ -n "$CUSTOM_HOOKS" ]; then
271
- echo "BLOCKING: Custom entity hooks detected — pages MUST call services directly"
272
- echo "$CUSTOM_HOOKS"
273
- echo "Pattern: page useCallback → service.getAll() → setData(result.items)"
274
- echo "FORBIDDEN: useEmployees(), useProjects() etc. wrapping services with useState/useEffect"
275
- # FIX REQUIRED: delete custom hooks, move API calls into page components
276
- fi
277
- fi
278
-
279
- # BLOCKING: No direct array types in services — MUST use PaginatedResult<T>
280
- if [ -n "$WEB_SRC" ]; then
281
- SVC_DIR=$(find "$WEB_SRC" -path "*/services" -not -path "*/node_modules/*" -type d 2>/dev/null | head -1)
282
- if [ -n "$SVC_DIR" ]; then
283
- DIRECT_ARRAYS=$(grep -rPn 'api\.get<[A-Z]\w+\[\]>' "$SVC_DIR" --include="*.ts" 2>/dev/null)
284
- if [ -n "$DIRECT_ARRAYS" ]; then
285
- echo "BLOCKING: Direct array response types — MUST use PaginatedResult<T>"
286
- echo "$DIRECT_ARRAYS"
287
- echo "Pattern: api.get<PaginatedResult<Employee>>(url) then .items in page"
288
- # FIX REQUIRED before commit
289
- fi
290
- fi
291
- fi
292
-
293
- # BLOCKING: lazy() imports MUST have Suspense boundary in App.tsx
294
- if [ -n "$APP_TSX" ]; then
295
- HAS_LAZY=$(grep -c 'lazy(' "$APP_TSX" 2>/dev/null)
296
- HAS_SUSPENSE=$(grep -c 'Suspense' "$APP_TSX" 2>/dev/null)
297
- if [ "$HAS_LAZY" -gt 0 ] && [ "$HAS_SUSPENSE" -eq 0 ]; then
298
- echo "BLOCKING: lazy() imports without <Suspense> boundary in App.tsx"
299
- echo "Every lazy() page MUST be wrapped: <Suspense fallback={<PageLoader />}>"
300
- # FIX REQUIRED before commit
301
- fi
302
- fi
303
-
304
- If ANY POST-CHECK fails → fix the code → re-run ALL checks → loop until ALL pass.
305
- **NEVER commit with failing POST-CHECKs.**
306
-
307
- 3ter. **Dependency audit (if frontend tasks in batch):**
308
- ```bash
309
- cd {frontend_dir}
310
- npm ls --depth=0 2>&1 | grep "MISSING" && echo "FAIL: missing deps" && exit 1
311
- ```
312
- If FAIL → `npm install {missing_packages}` → re-check → loop until pass
313
-
314
- 4. **MCP validation:**
315
- `mcp__smartstack__validate_conventions` ONCE for the whole batch
316
-
317
- 5. **DB validation (if infrastructure/migration tasks in batch):**
318
- ```bash
319
- # Quick check: pending model changes after batch?
320
- INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
321
- API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
322
- if [ -n "$INFRA_PROJECT" ] && [ -n "$API_PROJECT" ]; then
323
- dotnet ef migrations has-pending-model-changes \
324
- --project "$INFRA_PROJECT" \
325
- --startup-project "$API_PROJECT"
326
- if [ $? -ne 0 ]; then
327
- echo "MIGRATION MISSING: Model has uncommitted changes"
328
- # Create fix task for missing migration
329
- fi
330
-
331
- # If batch included migration tasks: verify migration applies on real SQL Server
332
- DB_NAME="SmartStack_Ralph_Check_${iteration}"
333
- CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
334
- dotnet ef database update \
335
- --connection "$CONN_STRING" \
336
- --project "$INFRA_PROJECT" \
337
- --startup-project "$API_PROJECT"
338
- if [ $? -ne 0 ]; then
339
- echo "MIGRATION BROKEN: Cannot apply migrations on SQL Server"
340
- # Fix migration → rebuild → DO NOT commit until this passes
341
- fi
342
-
343
- # Cleanup temp database
344
- sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$DB_NAME]; END" 2>/dev/null
345
- fi
346
- ```
347
- If FAIL → migration is broken → fix → rebuild → DO NOT commit
348
-
349
- 5bis. **Navigation section route CRUD suffix check (BLOCKING — if seed data tasks in batch):**
350
- ```bash
351
- # Detect /list or /detail/:id in navigation section routes
352
- SEED_NAV_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*NavigationSeedData.cs" 2>/dev/null)
353
- if [ -n "$SEED_NAV_FILES" ]; then
354
- CRUD_ROUTES=$(grep -rn 'Route.*=.*\/list\b\|Route.*=.*\/detail' $SEED_NAV_FILES 2>/dev/null | grep -v '//.*Route')
355
- if [ -n "$CRUD_ROUTES" ]; then
356
- echo "BLOCKING: Navigation section routes contain /list or /detail/:id suffixes"
357
- echo "Convention: list → module route (no suffix), detail → module route + /:id"
358
- echo "$CRUD_ROUTES"
359
- # FIX REQUIRED before commit
360
- fi
361
- fi
362
- ```
363
-
364
- 5ter. **Core Seed Data Integrity (BLOCKING — if seed data tasks in batch):**
365
- ```bash
366
- # Verify NavigationApplicationSeedData.cs exists
367
- APP_SEED=$(find . -path "*/Seeding/Data/NavigationApplicationSeedData.cs" 2>/dev/null | head -1)
368
- if [ -z "$APP_SEED" ]; then
369
- echo "❌ BLOCKING: NavigationApplicationSeedData.cs NOT FOUND"
370
- echo "Without this: nav_Applications empty → menu invisible → modules inaccessible"
371
- echo "Fix: Generate from core-seed-data.md section 1b"
372
- # Create fix task
373
- fi
374
-
375
- # Verify no hardcoded placeholders in provider
376
- PROVIDER=$(find . -path "*/Seeding/*SeedDataProvider.cs" 2>/dev/null | head -1)
377
- if [ -n "$PROVIDER" ]; then
378
- if grep -qE '\{appLabel_|\{appDesc_|\{appIcon\}|\{ApplicationGuid\}' "$PROVIDER" 2>/dev/null; then
379
- echo "❌ BLOCKING: SeedDataProvider has unresolved placeholders"
380
- echo "Fix: Use NavigationApplicationSeedData.GetApplicationEntry()"
381
- fi
382
- fi
383
-
384
- # Verify ApplicationRolesSeedData references real GUID
385
- ROLES_SEED=$(find . -path "*/Seeding/Data/ApplicationRolesSeedData.cs" 2>/dev/null | head -1)
386
- if [ -n "$ROLES_SEED" ]; then
387
- if grep -q '{ApplicationGuid}' "$ROLES_SEED" 2>/dev/null; then
388
- echo "❌ BLOCKING: ApplicationRolesSeedData still has {ApplicationGuid} placeholder"
389
- echo "Fix: Replace with NavigationApplicationSeedData.ApplicationId"
390
- fi
391
- fi
392
-
393
- # Quick startup test to verify seed data runs without exceptions
394
- API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
395
- if [ -n "$API_PROJECT" ] && [ -n "$APP_SEED" ]; then
396
- echo "Running seed data startup test..."
397
- dotnet run --project "$API_PROJECT" --urls "http://localhost:0" -- --environment Development > /tmp/ralph-seed-check.log 2>&1 &
398
- SEED_PID=$!
399
- sleep 10
400
- if ! kill -0 $SEED_PID 2>/dev/null; then
401
- SEED_LOG=$(cat /tmp/ralph-seed-check.log 2>/dev/null | tail -20)
402
- echo "❌ BLOCKING: Application crashed during startup — seed data likely failed"
403
- echo "Last 20 lines: $SEED_LOG"
404
- # Do NOT continue to frontend/test — fix seed data first
405
- else
406
- echo "✓ Seed data startup test passed"
407
- kill $SEED_PID 2>/dev/null
408
- wait $SEED_PID 2>/dev/null
409
- fi
410
- rm -f /tmp/ralph-seed-check.log
411
- fi
412
- ```
413
- If FAIL → fix seed data → rebuild → DO NOT continue to frontend/test tasks
414
-
415
- **Error resolution cycle:**
416
- 1. Read the FULL error output (not just first line)
417
- 2. Identify root cause: file path + line number
418
- 3. Fix the issue in source code
419
- 4. Rebuild/retest
420
- 5. If still failing → repeat from step 1
421
- 6. **NEVER** commit with failing build or tests
96
+ ## B. Delegate Batch to /apex
422
97
 
423
- ---
98
+ > **Ralph NEVER generates code.** All code generation, MCP calls, POST-CHECKs,
99
+ > and build verification are handled by apex.
100
+
101
+ ### B1. Mark Batch In-Progress
102
+
103
+ ```javascript
104
+ for (const task of batch) {
105
+ task.status = 'in_progress';
106
+ task.started_at = new Date().toISOString();
107
+ }
108
+ writeJSON('.ralph/prd.json', prd);
109
+ ```
110
+
111
+ ### B2. Invoke /apex
424
112
 
425
- ## C. Commit Batch
113
+ **INVOKE `/apex -d .ralph/prd.json`**
426
114
 
427
- ### C1. Update PRD Status (MANDATORY — BEFORE git commit)
115
+ Apex handles everything for the current module:
116
+ - Reads PRD, extracts context (context_code, app_name, module_code, entities, sections)
117
+ - Executes ALL layers: domain → infrastructure → migration → application → api → seed data → frontend → tests
118
+ - Runs full POST-CHECKs (43 checks from `references/post-checks.md`)
119
+ - Commits per layer (atomic commits)
120
+ - Validates with MCP (`validate_conventions`)
121
+ - Updates task statuses in the PRD file directly
428
122
 
429
- > **CRITICAL:** PRD status MUST be updated BEFORE committing.
430
- > In test-v4-005, the compact loop executed 44 tasks but NEVER updated prd.json status.
431
- > This broke ALL downstream guardrails (module completeness check never triggered).
123
+ > **FLAGS:** `-d` implies `-a` (auto, no user confirmation) and `-e` (economy, no nested teams).
124
+
125
+ ### B3. Verify Post-Apex Results
432
126
 
433
127
  ```javascript
434
- const now = new Date().toISOString();
435
- const COMMIT_HASH_PENDING = 'pending-commit'; // Updated after git commit
128
+ // Re-read PRD after apex execution
129
+ const updatedPrd = readJSON('.ralph/prd.json');
130
+ const batchIds = batch.map(t => t.id);
436
131
 
437
- for (const task of batch) {
438
- if (task.status !== 'failed') task.status = 'completed';
439
- task.completed_at = now;
440
- task.iteration = prd.config.current_iteration;
441
- task.commit_hash = COMMIT_HASH_PENDING;
132
+ const completed = updatedPrd.tasks.filter(t => batchIds.includes(t.id) && t.status === 'completed').length;
133
+ const failed = updatedPrd.tasks.filter(t => batchIds.includes(t.id) && t.status === 'failed').length;
134
+ const pending = updatedPrd.tasks.filter(t => batchIds.includes(t.id) && t.status === 'pending').length;
135
+
136
+ if (failed > 0) {
137
+ console.log(`WARNING: ${failed} tasks failed during apex execution`);
138
+ // Failed tasks will be retried in next loop iteration if retries remain
442
139
  }
443
- prd.config.current_iteration++;
444
- prd.updated_at = now;
445
- writeJSON('.ralph/prd.json', prd);
140
+
141
+ if (pending > 0) {
142
+ console.log(`INFO: ${pending} tasks still pending — apex may not have reached them`);
143
+ }
144
+
145
+ console.log(`Apex completed: ${completed}/${batchIds.length} tasks`);
446
146
  ```
447
147
 
448
- ### C2. Update Progress File (MANDATORY)
148
+ ---
149
+
150
+ ## C. Commit PRD State
151
+
152
+ ### C1. Update Progress File (MANDATORY)
449
153
 
450
154
  ```javascript
451
- const completed = prd.tasks.filter(t => t.status === 'completed').length;
452
- const total = prd.tasks.length;
453
- const moduleName = prd.project?.module || 'unknown';
155
+ const prdCheck = readJSON('.ralph/prd.json');
156
+ const totalCompleted = prdCheck.tasks.filter(t => t.status === 'completed').length;
157
+ const total = prdCheck.tasks.length;
454
158
 
455
- // Append to progress.txt (NOT overwrite)
456
159
  appendFile('.ralph/progress.txt',
457
- `Iteration ${prd.config.current_iteration - 1}: ${batch.map(t => t.id).join('/')} COMPLETED — ` +
458
- `${batch[0].category} (${batch.length} tasks). ${completed}/${total} done.\n` +
459
- ` Files: ${batch.reduce((acc, t) => acc + (t.files_changed?.created?.length || 0), 0)} created\n`
160
+ `Iteration ${prdCheck.config.current_iteration}: Delegated to /apex — ` +
161
+ `${completed}/${batchIds.length} batch tasks completed. ${totalCompleted}/${total} overall.\n`
460
162
  );
461
163
  ```
462
164
 
463
- ### C3. Git Commit
165
+ ### C2. Increment Iteration
166
+
167
+ ```javascript
168
+ prdCheck.config.current_iteration++;
169
+ prdCheck.updated_at = new Date().toISOString();
170
+ writeJSON('.ralph/prd.json', prdCheck);
171
+ ```
172
+
173
+ ### C3. Git Commit (PRD state only — apex already committed code)
464
174
 
465
175
  ```bash
466
- # Stage all changed files from batch
467
- git add {all_files_from_batch}
468
176
  git add .ralph/prd.json .ralph/progress.txt
469
177
  [ -f .ralph/modules-queue.json ] && git add .ralph/modules-queue.json
470
178
 
471
179
  git commit -m "$(cat <<'EOF'
472
- feat({scope}): [{category}] {batch.length} tasks — {short summary}
180
+ chore(ralph): update PRD stateiteration {iteration}
473
181
 
474
- Tasks: {task_ids} / {total}
475
- Iteration: {iteration}
476
- {module ? "Module: " + module : ""}
182
+ Tasks: {completed}/{batch_size} completed via /apex
183
+ Overall: {totalCompleted}/{total}
477
184
 
478
185
  Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
479
186
  EOF
480
187
  )"
481
-
482
- COMMIT_HASH=$(git rev-parse --short HEAD)
483
188
  ```
484
189
 
485
- ### C4. Finalize PRD with Commit Hash
190
+ ### C4. PRD Sync Verification (HARD CHECK)
486
191
 
487
192
  ```javascript
488
- // Update commit hash now that we have the real one
489
- for (const task of batch) {
490
- if (task.commit_hash === 'pending-commit') task.commit_hash = COMMIT_HASH;
491
- }
492
- prd.history.push({
493
- iteration: prd.config.current_iteration - 1,
494
- task_ids: batch.map(t => t.id),
495
- action: 'batch-completed',
496
- timestamp: now,
497
- commit_hash: COMMIT_HASH,
498
- notes: "{summary}"
499
- });
500
- writeJSON('.ralph/prd.json', prd);
501
- ```
193
+ const prdVerify = readJSON('.ralph/prd.json');
194
+ const actuallyCompleted = prdVerify.tasks.filter(t => batchIds.includes(t.id) && t.status === 'completed');
502
195
 
503
- ### C5. PRD Sync Verification (HARD CHECK)
504
-
505
- > **MANDATORY:** Verify prd.json reflects reality before looping back.
506
-
507
- ```javascript
508
- const prdCheck = readJSON('.ralph/prd.json');
509
- const batchIds = batch.map(t => t.id);
510
- const actuallyCompleted = prdCheck.tasks.filter(t => batchIds.includes(t.id) && t.status === 'completed');
511
-
512
- if (actuallyCompleted.length !== batch.filter(t => t.status !== 'failed').length) {
513
- console.error('PRD SYNC ERROR: Tasks executed but not marked completed in prd.json');
514
- console.error(`Expected: ${batch.filter(t => t.status !== 'failed').length} completed, Got: ${actuallyCompleted.length}`);
515
- // Force re-write
516
- for (const task of batch) {
517
- const prdTask = prdCheck.tasks.find(t => t.id === task.id);
518
- if (prdTask && task.status === 'completed') prdTask.status = 'completed';
519
- if (prdTask) prdTask.commit_hash = COMMIT_HASH;
520
- }
521
- writeJSON('.ralph/prd.json', prdCheck);
522
- console.log('PRD SYNC REPAIRED');
196
+ if (actuallyCompleted.length !== completed) {
197
+ console.error('PRD SYNC ERROR: Mismatch between apex results and prd.json');
198
+ // Force re-read apex may have written after our read
199
+ // DO NOT overwrite — apex is the source of truth for task statuses
523
200
  }
524
201
  ```
525
202
 
@@ -82,29 +82,28 @@ for (const layer of layers) {
82
82
 
83
83
  ## 4. Teammate Prompt Template
84
84
 
85
- Each teammate receives a self-contained prompt with all context:
85
+ Each teammate receives a self-contained prompt that delegates to `/apex`:
86
86
 
87
87
  ```
88
88
  You are a Ralph Loop module worker for module "${moduleCode}".
89
89
 
90
90
  ## Your Mission
91
- Implement ALL tasks in the PRD below, following SmartStack conventions.
92
- Execute autonomously: domain infrastructure MIGRATION seed data → application → api → frontend → i18n → tests → validation.
91
+ Execute ALL tasks in the PRD by delegating to /apex.
92
+ You are an ORCHESTRATOR you NEVER generate code directly.
93
93
 
94
- ## PRD (your task list)
95
- ${JSON.stringify(prdContent, null, 2)}
94
+ ## PRD File
95
+ ${prdFile}
96
96
 
97
- ## Execution Rules
98
- 1. Read the skill file at: templates/skills/ralph-loop/references/category-rules.md
99
- 2. For seed data tasks, also read: templates/skills/ralph-loop/references/core-seed-data.md
100
- 3. Follow SmartStack conventions (MCP validation after each batch)
101
- 4. MIGRATION is MANDATORY after EF configs: mcp suggest_migration → dotnet ef migrations add → database update
102
- 5. Tests MUST pass before proceeding (dotnet test = 0 failures)
103
- 6. Frontend in src/pages/{Context}/{App}/{Module}/ (NOT flat)
104
- 7. Commit after each batch: git add + git commit
97
+ ## Execution
98
+ 1. INVOKE `/apex -d ${prdFile}`
99
+ Apex handles all layers: domain → infrastructure → migration → seed data application api → frontend → tests
100
+ Apex runs POST-CHECKs, MCP validation, build verification, and commits per layer
101
+ Apex updates task statuses in the PRD file directly
102
+ 2. After apex returns, re-read ${prdFile} to check task statuses
103
+ 3. If tasks remain pending/failed, re-invoke `/apex -d ${prdFile}`
105
104
 
106
105
  ## Communication Protocol
107
- - After domain + infrastructure + migration are done and build passes:
106
+ - After apex completes and build passes:
108
107
  SendMessage({ type: "message", recipient: "team-lead", content: "LAYER_READY:${moduleCode}", summary: "${moduleCode} foundation ready" })
109
108
  - When ALL tasks complete:
110
109
  SendMessage({ type: "message", recipient: "team-lead", content: "MODULE_COMPLETE:${moduleCode}", summary: "${moduleCode} complete" })