@cubis/foundry 0.3.78 → 0.3.80

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 (81) hide show
  1. package/dist/cli/build/commands.js +1 -1
  2. package/dist/cli/build/commands.js.map +1 -1
  3. package/dist/cli/core.js +752 -101
  4. package/dist/cli/core.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/cli/build/commands.ts +1 -1
  7. package/src/cli/core.ts +884 -114
  8. package/workflows/workflows/agent-environment-setup/generated/route-manifest.json +2 -2
  9. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/accessibility.toml +1 -1
  10. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/architecture.toml +2 -2
  11. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/backend.toml +1 -1
  12. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/create.toml +1 -1
  13. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/database.toml +1 -1
  14. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/debug.toml +1 -1
  15. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/devops.toml +1 -1
  16. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/implement-track.toml +1 -1
  17. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/migrate.toml +1 -1
  18. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/mobile.toml +1 -1
  19. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/onboard.toml +1 -1
  20. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/orchestrate.toml +1 -1
  21. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/plan.toml +1 -1
  22. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/refactor.toml +1 -1
  23. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/release.toml +1 -1
  24. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/review.toml +1 -1
  25. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/security.toml +1 -1
  26. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/spec.toml +1 -1
  27. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/test.toml +1 -1
  28. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/vercel.toml +1 -1
  29. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/architecture.md +20 -15
  30. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/spec.md +2 -2
  31. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/architecture.md +20 -15
  32. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/spec.md +2 -2
  33. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/architecture.md +20 -15
  34. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/spec.md +2 -2
  35. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-accessibility.prompt.md +1 -1
  36. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-architecture.prompt.md +2 -2
  37. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-backend.prompt.md +1 -1
  38. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-create.prompt.md +1 -1
  39. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-database.prompt.md +1 -1
  40. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-debug.prompt.md +1 -1
  41. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-devops.prompt.md +1 -1
  42. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-implement-track.prompt.md +1 -1
  43. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-migrate.prompt.md +1 -1
  44. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-mobile.prompt.md +1 -1
  45. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-onboard.prompt.md +1 -1
  46. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-orchestrate.prompt.md +1 -1
  47. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-plan.prompt.md +1 -1
  48. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-refactor.prompt.md +1 -1
  49. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-release.prompt.md +1 -1
  50. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-review.prompt.md +1 -1
  51. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-security.prompt.md +1 -1
  52. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-spec.prompt.md +1 -1
  53. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-test.prompt.md +1 -1
  54. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-vercel.prompt.md +1 -1
  55. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/architecture.md +20 -15
  56. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/spec.md +2 -2
  57. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/accessibility.toml +1 -1
  58. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/architecture.toml +2 -2
  59. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/backend.toml +1 -1
  60. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/create.toml +1 -1
  61. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/database.toml +1 -1
  62. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/debug.toml +1 -1
  63. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/devops.toml +1 -1
  64. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/implement-track.toml +1 -1
  65. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/migrate.toml +1 -1
  66. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/mobile.toml +1 -1
  67. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/onboard.toml +1 -1
  68. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/orchestrate.toml +1 -1
  69. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/plan.toml +1 -1
  70. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/refactor.toml +1 -1
  71. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/release.toml +1 -1
  72. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/review.toml +1 -1
  73. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/security.toml +1 -1
  74. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/spec.toml +1 -1
  75. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/test.toml +1 -1
  76. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/vercel.toml +1 -1
  77. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/architecture.md +20 -15
  78. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/spec.md +2 -2
  79. package/workflows/workflows/agent-environment-setup/shared/rules/STEERING.md +3 -3
  80. package/workflows/workflows/agent-environment-setup/shared/workflows/architecture.md +20 -15
  81. package/workflows/workflows/agent-environment-setup/shared/workflows/spec.md +2 -2
package/src/cli/core.ts CHANGED
@@ -65,10 +65,24 @@ const ENGINEERING_ARCHITECTURE_BLOCK_START_RE =
65
65
  /<!--\s*cbx:architecture:rules:start[^>]*-->/g;
66
66
  const ENGINEERING_ARCHITECTURE_BLOCK_END_RE =
67
67
  /<!--\s*cbx:architecture:rules:end\s*-->/g;
68
+ const PRODUCT_FOUNDATION_BLOCK_START_RE =
69
+ /<!--\s*cbx:product:foundation:start[^>]*-->/g;
70
+ const PRODUCT_FOUNDATION_BLOCK_END_RE =
71
+ /<!--\s*cbx:product:foundation:end\s*-->/g;
72
+ const ARCHITECTURE_DOC_BLOCK_START_RE =
73
+ /<!--\s*cbx:architecture:doc:start[^>]*-->/g;
74
+ const ARCHITECTURE_DOC_BLOCK_END_RE =
75
+ /<!--\s*cbx:architecture:doc:end\s*-->/g;
68
76
  const TECH_ARCHITECTURE_BLOCK_START_RE =
69
77
  /<!--\s*cbx:architecture:tech:start[^>]*-->/g;
70
78
  const TECH_ARCHITECTURE_BLOCK_END_RE =
71
79
  /<!--\s*cbx:architecture:tech:end\s*-->/g;
80
+ const ROADMAP_FOUNDATION_BLOCK_START_RE =
81
+ /<!--\s*cbx:roadmap:foundation:start[^>]*-->/g;
82
+ const ROADMAP_FOUNDATION_BLOCK_END_RE =
83
+ /<!--\s*cbx:roadmap:foundation:end\s*-->/g;
84
+ const FOUNDATION_DOCS_DIR = path.join("docs", "foundation");
85
+ const FOUNDATION_ADR_DIR = path.join(FOUNDATION_DOCS_DIR, "adr");
72
86
  const COPILOT_ALLOWED_SKILL_FRONTMATTER_KEYS = new Set([
73
87
  "compatibility",
74
88
  "description",
@@ -1105,6 +1119,181 @@ function buildArchitectureMermaid(snapshot) {
1105
1119
  return lines.join("\n");
1106
1120
  }
1107
1121
 
1122
+ function inferProductFoundationProfile(snapshot, specRoots = []) {
1123
+ const appRoots = (snapshot.architectureByApp || [])
1124
+ .map((item) => item.rootPath)
1125
+ .filter((value) => value && value !== ".");
1126
+ const primarySurfaces = appRoots.length > 0 ? appRoots : snapshot.topDirs.slice(0, 6);
1127
+ const userPersonas = [];
1128
+
1129
+ if (snapshot.frameworks.includes("Flutter")) {
1130
+ userPersonas.push("End users interacting through mobile or desktop app surfaces");
1131
+ }
1132
+ if (
1133
+ snapshot.frameworks.includes("Next.js") ||
1134
+ snapshot.frameworks.includes("React") ||
1135
+ snapshot.topDirs.includes("web")
1136
+ ) {
1137
+ userPersonas.push("Browser users and internal operators using web-facing flows");
1138
+ }
1139
+ if (snapshot.frameworks.includes("NestJS") || snapshot.topDirs.includes("api")) {
1140
+ userPersonas.push("Internal services, operators, or partner systems consuming API boundaries");
1141
+ }
1142
+ if (userPersonas.length === 0) {
1143
+ userPersonas.push(
1144
+ "Project stakeholders are not obvious from the repo alone; refine personas from product context before major feature work.",
1145
+ );
1146
+ }
1147
+
1148
+ const coreJourneys = [];
1149
+ if (specRoots.length > 0) {
1150
+ coreJourneys.push(
1151
+ `Active implementation themes are reflected in current spec packs: ${specRoots.join(", ")}.`,
1152
+ );
1153
+ }
1154
+ if (primarySurfaces.length > 0) {
1155
+ coreJourneys.push(
1156
+ `Primary product surfaces currently live in: ${primarySurfaces.join(", ")}.`,
1157
+ );
1158
+ }
1159
+ if (snapshot.isMcpServer || snapshot.mcpSignals.length > 0) {
1160
+ coreJourneys.push("Tool-assisted and MCP-driven workflows are part of the operating model and should stay stable.");
1161
+ }
1162
+ if (coreJourneys.length === 0) {
1163
+ coreJourneys.push(
1164
+ "Repository evidence is thin; capture the primary user journeys here before scaling the codebase further.",
1165
+ );
1166
+ }
1167
+
1168
+ const successSignals = [
1169
+ "Feature work should stay aligned to explicit user or operator value, not speculative abstractions.",
1170
+ "Architecture changes should reduce onboarding, debugging, and testing cost over time.",
1171
+ ];
1172
+ if (snapshot.cicdSignals.length > 0) {
1173
+ successSignals.push(
1174
+ `Delivery flows already rely on ${snapshot.cicdSignals.join(", ")} signals; keep release friction low for that pipeline.`,
1175
+ );
1176
+ }
1177
+
1178
+ return {
1179
+ productScope:
1180
+ snapshot.readmeExcerpt ||
1181
+ "No explicit product summary was detected from repo docs. Replace this with a concise product statement when better context exists.",
1182
+ primarySurfaces,
1183
+ userPersonas,
1184
+ coreJourneys,
1185
+ successSignals,
1186
+ };
1187
+ }
1188
+
1189
+ function buildProductFoundationSection(snapshot, specRoots = []) {
1190
+ const profile = inferProductFoundationProfile(snapshot, specRoots);
1191
+ const hash = hashStableObject(profile);
1192
+
1193
+ return [
1194
+ `<!-- cbx:product:foundation:start version=1 profile=${hash} -->`,
1195
+ "## Product Foundation (auto-managed)",
1196
+ "",
1197
+ "### Product Scope",
1198
+ profile.productScope,
1199
+ "",
1200
+ "### Primary Surfaces",
1201
+ ...(profile.primarySurfaces.length > 0
1202
+ ? profile.primarySurfaces.map((item) => `- ${item}`)
1203
+ : ["- No primary surfaces were detected automatically."]),
1204
+ "",
1205
+ "### Users and Operators",
1206
+ ...profile.userPersonas.map((item) => `- ${item}`),
1207
+ "",
1208
+ "### Core Journeys",
1209
+ ...profile.coreJourneys.map((item) => `- ${item}`),
1210
+ "",
1211
+ "### Success Signals",
1212
+ ...profile.successSignals.map((item) => `- ${item}`),
1213
+ "",
1214
+ "### Product Guardrails",
1215
+ "- Keep product intent stable across future features so agents do not optimize for the wrong user outcome.",
1216
+ "- Refresh this managed section when scope, personas, operating model, or success metrics change materially.",
1217
+ "<!-- cbx:product:foundation:end -->",
1218
+ "",
1219
+ ].join("\n");
1220
+ }
1221
+
1222
+ function inferArchitectureDocProfile(snapshot, specRoots = []) {
1223
+ const contract = inferArchitectureContractProfile(snapshot);
1224
+ const architectureSignals = (snapshot.architectureByApp || []).map((item) => {
1225
+ const label = item.rootPath === "." ? "repo root" : item.rootPath;
1226
+ const signals =
1227
+ item.architectureSignals && item.architectureSignals.length > 0
1228
+ ? item.architectureSignals.join(", ")
1229
+ : "not enough signals to classify";
1230
+ return `${label}: ${signals}`;
1231
+ });
1232
+ const decisionAreas = [
1233
+ "Module boundaries and dependency direction",
1234
+ "Design-system ownership and reusable primitives",
1235
+ "Testing and validation expectations by runtime boundary",
1236
+ ];
1237
+ if (specRoots.length > 0) {
1238
+ decisionAreas.push(
1239
+ `Active specs that may influence upcoming architecture work: ${specRoots.join(", ")}.`,
1240
+ );
1241
+ }
1242
+
1243
+ return {
1244
+ style: contract.style,
1245
+ designSystemSource: contract.designSystemSource,
1246
+ moduleBoundaries: contract.moduleBoundaries,
1247
+ architectureSignals,
1248
+ decisionAreas,
1249
+ scalingConstraints: contract.scalingConstraints,
1250
+ testingStrategy: contract.testingStrategy,
1251
+ };
1252
+ }
1253
+
1254
+ function buildArchitectureDocSection(snapshot, specRoots = []) {
1255
+ const profile = inferArchitectureDocProfile(snapshot, specRoots);
1256
+ const hash = hashStableObject(profile);
1257
+
1258
+ return [
1259
+ `<!-- cbx:architecture:doc:start version=1 profile=${hash} -->`,
1260
+ "## Accepted Architecture Backbone (auto-managed)",
1261
+ "",
1262
+ "### System Overview",
1263
+ `- Accepted style: ${profile.style}.`,
1264
+ `- Design-system source of truth: ${profile.designSystemSource}`,
1265
+ "",
1266
+ "### Bounded Contexts and Module Boundaries",
1267
+ ...(profile.moduleBoundaries.length > 0
1268
+ ? profile.moduleBoundaries.map((item) => `- ${item}`)
1269
+ : ["- No strong top-level module boundaries were detected automatically."]),
1270
+ "",
1271
+ "### Architecture Signals by Surface",
1272
+ ...(profile.architectureSignals.length > 0
1273
+ ? profile.architectureSignals.map((item) => `- ${item}`)
1274
+ : ["- No app-level architecture signals were inferred from the repo scan."]),
1275
+ "",
1276
+ "### Decision Areas to Preserve",
1277
+ ...profile.decisionAreas.map((item) => `- ${item}`),
1278
+ "",
1279
+ "### Scalability and Reliability Notes",
1280
+ ...profile.scalingConstraints.map((item) => `- ${item}`),
1281
+ "",
1282
+ "### Testing and Operability",
1283
+ ...profile.testingStrategy.map((item) => `- ${item}`),
1284
+ "",
1285
+ "### ADR Linkage",
1286
+ "- Keep durable architecture decisions in `docs/adr/` and summarize the active decision set here.",
1287
+ "",
1288
+ "### Mermaid Diagram",
1289
+ "```mermaid",
1290
+ buildArchitectureDocMermaid(snapshot),
1291
+ "```",
1292
+ "<!-- cbx:architecture:doc:end -->",
1293
+ "",
1294
+ ].join("\n");
1295
+ }
1296
+
1108
1297
  function buildEngineeringArchitectureSection(snapshot) {
1109
1298
  const profile = inferArchitectureContractProfile(snapshot);
1110
1299
  const hash = hashStableObject(profile);
@@ -1125,12 +1314,32 @@ function buildEngineeringArchitectureSection(snapshot) {
1125
1314
  ...profile.testingStrategy.map((rule) => ` - ${rule}`),
1126
1315
  "- Doc refresh policy:",
1127
1316
  " - Update these managed sections when architecture, scale, boundaries, design-system rules, or testing strategy changes.",
1128
- " - For non-trivial work, read this file before planning and read TECH.md next.",
1317
+ ` - For non-trivial work, read ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ENGINEERING_RULES.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, and ${FOUNDATION_DOCS_DIR}/TECH.md in that order when they exist.`,
1129
1318
  "<!-- cbx:architecture:rules:end -->",
1130
1319
  "",
1131
1320
  ].join("\n");
1132
1321
  }
1133
1322
 
1323
+ function buildArchitectureDocMermaid(snapshot) {
1324
+ const topDirs = snapshot.topDirs.slice(0, 5);
1325
+ const lines = [
1326
+ "flowchart LR",
1327
+ ' product["Product Intent"] --> rules["Engineering Rules"]',
1328
+ ' product --> arch["Architecture Backbone"]',
1329
+ ' arch --> tech["Current Tech Snapshot"]',
1330
+ ];
1331
+ if (topDirs.length > 0) {
1332
+ for (let index = 0; index < topDirs.length; index += 1) {
1333
+ const dir = topDirs[index];
1334
+ const nodeName = `D${index}`;
1335
+ lines.push(` arch --> ${nodeName}["${dir}/"]`);
1336
+ }
1337
+ }
1338
+ lines.push(' arch --> adr["docs/adr"]');
1339
+ lines.push(' product --> specs["docs/specs"]');
1340
+ return lines.join("\n");
1341
+ }
1342
+
1134
1343
  function buildTechArchitectureSection(snapshot) {
1135
1344
  const profile = inferArchitectureContractProfile(snapshot);
1136
1345
  const payload = {
@@ -1186,6 +1395,56 @@ function buildTechArchitectureSection(snapshot) {
1186
1395
  ].join("\n");
1187
1396
  }
1188
1397
 
1398
+ function buildRoadmapFoundationSection(snapshot, specRoots = []) {
1399
+ const payload = {
1400
+ topDirs: snapshot.topDirs,
1401
+ frameworks: snapshot.frameworks,
1402
+ specRoots,
1403
+ };
1404
+ const hash = hashStableObject(payload);
1405
+ const nowItems = specRoots.length > 0
1406
+ ? specRoots.map((item) => `Track active change planning in \`${item}\`.`)
1407
+ : [
1408
+ "No active spec packs detected. Create a spec pack before starting the next non-trivial feature or migration.",
1409
+ ];
1410
+ const nextItems = [];
1411
+ if (snapshot.frameworks.length > 0) {
1412
+ nextItems.push(
1413
+ `Keep shared conventions stable across the current stack: ${snapshot.frameworks.join(", ")}.`,
1414
+ );
1415
+ }
1416
+ if (snapshot.cicdSignals.length > 0) {
1417
+ nextItems.push(
1418
+ `Preserve release compatibility with the detected delivery surfaces: ${snapshot.cicdSignals.join(", ")}.`,
1419
+ );
1420
+ }
1421
+ if (nextItems.length === 0) {
1422
+ nextItems.push(
1423
+ "Document the next scaling milestones here once product direction and architecture constraints are clearer.",
1424
+ );
1425
+ }
1426
+
1427
+ return [
1428
+ `<!-- cbx:roadmap:foundation:start version=1 profile=${hash} -->`,
1429
+ "## Delivery Backbone (auto-managed)",
1430
+ "",
1431
+ "### Now",
1432
+ ...nowItems.map((item) => `- ${item}`),
1433
+ "",
1434
+ "### Next",
1435
+ ...nextItems.map((item) => `- ${item}`),
1436
+ "",
1437
+ "### Later",
1438
+ "- Use this section for medium-term scaling themes, major migrations, or cross-team architecture investments.",
1439
+ "",
1440
+ "### Backbone Maintenance",
1441
+ `- Keep ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ENGINEERING_RULES.md, and ${FOUNDATION_DOCS_DIR}/TECH.md aligned when direction or structure changes.`,
1442
+ "- Link major roadmap themes back to specs and ADRs instead of burying them in chat-only planning.",
1443
+ "<!-- cbx:roadmap:foundation:end -->",
1444
+ "",
1445
+ ].join("\n");
1446
+ }
1447
+
1189
1448
  function buildEngineeringRulesTemplate() {
1190
1449
  return [
1191
1450
  "# Engineering Rules",
@@ -1288,14 +1547,144 @@ function buildEngineeringRulesTemplate() {
1288
1547
  ].join("\n");
1289
1548
  }
1290
1549
 
1550
+ function buildProductTemplate(snapshot, specRoots = []) {
1551
+ return [
1552
+ "# Product",
1553
+ "",
1554
+ "This file is the durable product backbone for the project.",
1555
+ "",
1556
+ buildProductFoundationSection(snapshot, specRoots).trimEnd(),
1557
+ "",
1558
+ ].join("\n");
1559
+ }
1560
+
1561
+ function buildArchitectureDocTemplate(snapshot, specRoots = []) {
1562
+ return [
1563
+ "# Architecture",
1564
+ "",
1565
+ "This file captures the accepted architecture backbone for the project.",
1566
+ "",
1567
+ buildArchitectureDocSection(snapshot, specRoots).trimEnd(),
1568
+ "",
1569
+ ].join("\n");
1570
+ }
1571
+
1572
+ function buildRoadmapTemplate(snapshot, specRoots = []) {
1573
+ return [
1574
+ "# Roadmap",
1575
+ "",
1576
+ "This file captures the living delivery backbone for medium-term product and architecture work.",
1577
+ "",
1578
+ buildRoadmapFoundationSection(snapshot, specRoots).trimEnd(),
1579
+ "",
1580
+ ].join("\n");
1581
+ }
1582
+
1583
+ function buildProductBuildSkeleton() {
1584
+ return [
1585
+ "# Product",
1586
+ "",
1587
+ "This file is managed by `cbx build architecture`.",
1588
+ "",
1589
+ "<!-- cbx:product:foundation:start version=1 profile=uninitialized -->",
1590
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
1591
+ "<!-- cbx:product:foundation:end -->",
1592
+ "",
1593
+ ].join("\n");
1594
+ }
1595
+
1596
+ function buildArchitectureBuildSkeleton() {
1597
+ return [
1598
+ "# Architecture",
1599
+ "",
1600
+ "This file is managed by `cbx build architecture`.",
1601
+ "",
1602
+ "<!-- cbx:architecture:doc:start version=1 profile=uninitialized -->",
1603
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
1604
+ "<!-- cbx:architecture:doc:end -->",
1605
+ "",
1606
+ ].join("\n");
1607
+ }
1608
+
1609
+ function buildTechBuildSkeleton() {
1610
+ return [
1611
+ "# TECH.md",
1612
+ "",
1613
+ "This file is managed by `cbx build architecture`.",
1614
+ "",
1615
+ "<!-- cbx:architecture:tech:start version=1 snapshot=uninitialized -->",
1616
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
1617
+ "<!-- cbx:architecture:tech:end -->",
1618
+ "",
1619
+ ].join("\n");
1620
+ }
1621
+
1622
+ function buildAdrReadme() {
1623
+ return [
1624
+ "# Architecture Decision Records",
1625
+ "",
1626
+ "Use this directory for durable decisions that future contributors and agents need to preserve.",
1627
+ "",
1628
+ "## When to add an ADR",
1629
+ "",
1630
+ "- Architecture style or boundary changes",
1631
+ "- Data model or persistence strategy changes",
1632
+ "- Deployment or scaling model changes",
1633
+ "- Design-system ownership or shared UX pattern changes",
1634
+ "",
1635
+ "## Suggested format",
1636
+ "",
1637
+ "1. Context",
1638
+ "2. Decision",
1639
+ "3. Consequences",
1640
+ "4. Validation",
1641
+ "",
1642
+ "Start with `0000-template.md` and create numbered follow-up ADRs for accepted decisions.",
1643
+ "",
1644
+ ].join("\n");
1645
+ }
1646
+
1647
+ function buildAdrTemplate() {
1648
+ return [
1649
+ "# ADR 0000: Title",
1650
+ "",
1651
+ "## Status",
1652
+ "",
1653
+ "Proposed",
1654
+ "",
1655
+ "## Context",
1656
+ "",
1657
+ "- What problem or pressure led to this decision?",
1658
+ "",
1659
+ "## Decision",
1660
+ "",
1661
+ "- What is the chosen direction?",
1662
+ "",
1663
+ "## Consequences",
1664
+ "",
1665
+ "- What tradeoffs, benefits, or costs follow from this choice?",
1666
+ "",
1667
+ "## Validation",
1668
+ "",
1669
+ "- How will the team know this decision is working?",
1670
+ "",
1671
+ ].join("\n");
1672
+ }
1673
+
1291
1674
  function buildEngineeringRulesManagedBlock({
1292
1675
  platform,
1676
+ productFilePath,
1677
+ architectureFilePath,
1293
1678
  engineeringRulesFilePath,
1294
1679
  techMdFilePath,
1680
+ roadmapFilePath,
1295
1681
  ruleFilePath,
1296
1682
  }) {
1683
+ const productRef = toPosixPath(path.resolve(productFilePath));
1684
+ const architectureRef = toPosixPath(path.resolve(architectureFilePath));
1297
1685
  const engineeringRef = toPosixPath(path.resolve(engineeringRulesFilePath));
1298
1686
  const techRef = toPosixPath(path.resolve(techMdFilePath));
1687
+ const roadmapRef = toPosixPath(path.resolve(roadmapFilePath));
1299
1688
  const ruleRef = toPosixPath(path.resolve(ruleFilePath));
1300
1689
 
1301
1690
  return [
@@ -1303,8 +1692,11 @@ function buildEngineeringRulesManagedBlock({
1303
1692
  "## Engineering Guardrails (auto-managed)",
1304
1693
  "Apply these before planning, coding, review, and release:",
1305
1694
  "",
1695
+ `- Product backbone: \`${productRef}\``,
1696
+ `- Accepted architecture: \`${architectureRef}\``,
1306
1697
  `- Required baseline: \`${engineeringRef}\``,
1307
1698
  `- Project tech map: \`${techRef}\``,
1699
+ `- Delivery roadmap: \`${roadmapRef}\``,
1308
1700
  `- Active platform rule file: \`${ruleRef}\``,
1309
1701
  "",
1310
1702
  "Hard policy:",
@@ -1312,7 +1704,7 @@ function buildEngineeringRulesManagedBlock({
1312
1704
  "2. Keep architecture simple (KISS) and avoid speculative work (YAGNI).",
1313
1705
  "3. Apply SOLID pragmatically to reduce change risk, not add ceremony.",
1314
1706
  "4. Use clear naming with focused responsibilities and explicit boundaries.",
1315
- "5. For non-trivial work, read ENGINEERING_RULES.md first and TECH.md next before planning or implementation.",
1707
+ `5. For non-trivial work, read ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ENGINEERING_RULES.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, and ${FOUNDATION_DOCS_DIR}/TECH.md in that order when they exist before planning or implementation.`,
1316
1708
  "6. Require validation evidence (lint/types/tests) before merge.",
1317
1709
  "7. Use Decision Log response style.",
1318
1710
  "8. Every Decision Log must include a `Skills Used` section listing skill, workflow, or agent names.",
@@ -1437,14 +1829,20 @@ async function upsertEngineeringRulesFile({
1437
1829
  async function upsertEngineeringRulesBlock({
1438
1830
  ruleFilePath,
1439
1831
  platform,
1832
+ productFilePath,
1833
+ architectureFilePath,
1440
1834
  engineeringRulesFilePath,
1441
1835
  techMdFilePath,
1836
+ roadmapFilePath,
1442
1837
  dryRun = false,
1443
1838
  }) {
1444
1839
  const block = buildEngineeringRulesManagedBlock({
1445
1840
  platform,
1841
+ productFilePath,
1842
+ architectureFilePath,
1446
1843
  engineeringRulesFilePath,
1447
1844
  techMdFilePath,
1845
+ roadmapFilePath,
1448
1846
  ruleFilePath,
1449
1847
  });
1450
1848
  const exists = await pathExists(ruleFilePath);
@@ -1531,6 +1929,17 @@ async function upsertTaggedSectionInFile({
1531
1929
  trimmed.length > 0 ? `${trimmed}\n\n${block}\n` : `${block}\n`;
1532
1930
  }
1533
1931
 
1932
+ if (!exists) {
1933
+ if (!dryRun) {
1934
+ await mkdir(path.dirname(targetPath), { recursive: true });
1935
+ await writeFile(targetPath, nextContent, "utf8");
1936
+ }
1937
+ return {
1938
+ action: dryRun ? "would-create" : "created",
1939
+ filePath: targetPath,
1940
+ };
1941
+ }
1942
+
1534
1943
  if (nextContent === original) {
1535
1944
  return {
1536
1945
  action: "unchanged",
@@ -1558,28 +1967,51 @@ async function upsertTaggedSectionInFile({
1558
1967
  function buildArchitectureBuildMetadata({
1559
1968
  platform,
1560
1969
  researchMode,
1561
- rulesProfileHash,
1562
- techSnapshotHash,
1970
+ managedDocs,
1563
1971
  }) {
1564
1972
  return {
1565
- schemaVersion: 1,
1973
+ schemaVersion: 3,
1566
1974
  generatedBy: "cbx build architecture",
1567
1975
  generatedAt: new Date().toISOString(),
1568
1976
  platform,
1569
1977
  researchMode,
1570
- rulesProfileHash,
1571
- techSnapshotHash,
1978
+ managedDocs,
1572
1979
  };
1573
1980
  }
1574
1981
 
1575
1982
  async function ensureArchitectureDocScaffold({
1576
1983
  workspaceRoot,
1577
1984
  snapshot,
1985
+ specRoots = [],
1578
1986
  overwrite = false,
1579
1987
  dryRun = false,
1580
1988
  }) {
1989
+ const productPath = path.join(workspaceRoot, "PRODUCT.md");
1990
+ const architectureDocPath = path.join(workspaceRoot, "ARCHITECTURE.md");
1581
1991
  const engineeringRulesPath = path.join(workspaceRoot, "ENGINEERING_RULES.md");
1582
1992
  const techMdPath = path.join(workspaceRoot, "TECH.md");
1993
+ const roadmapPath = path.join(workspaceRoot, "ROADMAP.md");
1994
+ const adrDir = path.join(workspaceRoot, "docs", "adr");
1995
+ const adrReadmePath = path.join(adrDir, "README.md");
1996
+ const adrTemplatePath = path.join(adrDir, "0000-template.md");
1997
+
1998
+ const productResult = await upsertTaggedSectionInFile({
1999
+ targetPath: productPath,
2000
+ initialContent: `${buildProductTemplate(snapshot, specRoots)}\n`,
2001
+ block: buildProductFoundationSection(snapshot, specRoots),
2002
+ startPattern: PRODUCT_FOUNDATION_BLOCK_START_RE,
2003
+ endPattern: PRODUCT_FOUNDATION_BLOCK_END_RE,
2004
+ dryRun,
2005
+ });
2006
+
2007
+ const architectureDocResult = await upsertTaggedSectionInFile({
2008
+ targetPath: architectureDocPath,
2009
+ initialContent: `${buildArchitectureDocTemplate(snapshot, specRoots)}\n`,
2010
+ block: buildArchitectureDocSection(snapshot, specRoots),
2011
+ startPattern: ARCHITECTURE_DOC_BLOCK_START_RE,
2012
+ endPattern: ARCHITECTURE_DOC_BLOCK_END_RE,
2013
+ dryRun,
2014
+ });
1583
2015
 
1584
2016
  const rulesTemplate = buildEngineeringRulesTemplate();
1585
2017
  const rulesFileResult = await upsertEngineeringRulesFile({
@@ -1613,13 +2045,126 @@ async function ensureArchitectureDocScaffold({
1613
2045
  dryRun,
1614
2046
  });
1615
2047
 
2048
+ const roadmapResult = await upsertTaggedSectionInFile({
2049
+ targetPath: roadmapPath,
2050
+ initialContent: `${buildRoadmapTemplate(snapshot, specRoots)}\n`,
2051
+ block: buildRoadmapFoundationSection(snapshot, specRoots),
2052
+ startPattern: ROADMAP_FOUNDATION_BLOCK_START_RE,
2053
+ endPattern: ROADMAP_FOUNDATION_BLOCK_END_RE,
2054
+ dryRun,
2055
+ });
2056
+
2057
+ const adrReadmeResult = await writeTextFile({
2058
+ targetPath: adrReadmePath,
2059
+ content: `${buildAdrReadme()}\n`,
2060
+ overwrite,
2061
+ dryRun,
2062
+ });
2063
+ const adrTemplateResult = await writeTextFile({
2064
+ targetPath: adrTemplatePath,
2065
+ content: `${buildAdrTemplate()}\n`,
2066
+ overwrite,
2067
+ dryRun,
2068
+ });
2069
+
1616
2070
  return {
2071
+ productPath,
2072
+ architectureDocPath,
1617
2073
  engineeringRulesPath,
1618
2074
  techMdPath,
2075
+ roadmapPath,
2076
+ adrReadmePath,
2077
+ adrTemplatePath,
2078
+ productResult,
2079
+ architectureDocResult,
1619
2080
  rulesFileResult,
1620
2081
  rulesArchitectureResult,
1621
2082
  techResult,
1622
2083
  techArchitectureResult,
2084
+ roadmapResult,
2085
+ adrReadmeResult,
2086
+ adrTemplateResult,
2087
+ };
2088
+ }
2089
+
2090
+ async function ensureArchitectureBuildScaffold({
2091
+ workspaceRoot,
2092
+ dryRun = false,
2093
+ }) {
2094
+ const foundationRoot = path.join(workspaceRoot, FOUNDATION_DOCS_DIR);
2095
+ const productPath = path.join(foundationRoot, "PRODUCT.md");
2096
+ const architectureDocPath = path.join(foundationRoot, "ARCHITECTURE.md");
2097
+ const techMdPath = path.join(foundationRoot, "TECH.md");
2098
+ const adrDir = path.join(workspaceRoot, FOUNDATION_ADR_DIR);
2099
+ const adrReadmePath = path.join(adrDir, "README.md");
2100
+ const adrTemplatePath = path.join(adrDir, "0000-template.md");
2101
+
2102
+ const productResult = await upsertTaggedSectionInFile({
2103
+ targetPath: productPath,
2104
+ initialContent: `${buildProductBuildSkeleton()}\n`,
2105
+ block: [
2106
+ "<!-- cbx:product:foundation:start version=1 profile=uninitialized -->",
2107
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
2108
+ "<!-- cbx:product:foundation:end -->",
2109
+ "",
2110
+ ].join("\n"),
2111
+ startPattern: PRODUCT_FOUNDATION_BLOCK_START_RE,
2112
+ endPattern: PRODUCT_FOUNDATION_BLOCK_END_RE,
2113
+ dryRun,
2114
+ });
2115
+
2116
+ const architectureDocResult = await upsertTaggedSectionInFile({
2117
+ targetPath: architectureDocPath,
2118
+ initialContent: `${buildArchitectureBuildSkeleton()}\n`,
2119
+ block: [
2120
+ "<!-- cbx:architecture:doc:start version=1 profile=uninitialized -->",
2121
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
2122
+ "<!-- cbx:architecture:doc:end -->",
2123
+ "",
2124
+ ].join("\n"),
2125
+ startPattern: ARCHITECTURE_DOC_BLOCK_START_RE,
2126
+ endPattern: ARCHITECTURE_DOC_BLOCK_END_RE,
2127
+ dryRun,
2128
+ });
2129
+
2130
+ const techResult = await upsertTaggedSectionInFile({
2131
+ targetPath: techMdPath,
2132
+ initialContent: `${buildTechBuildSkeleton()}\n`,
2133
+ block: [
2134
+ "<!-- cbx:architecture:tech:start version=1 snapshot=uninitialized -->",
2135
+ "Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
2136
+ "<!-- cbx:architecture:tech:end -->",
2137
+ "",
2138
+ ].join("\n"),
2139
+ startPattern: TECH_ARCHITECTURE_BLOCK_START_RE,
2140
+ endPattern: TECH_ARCHITECTURE_BLOCK_END_RE,
2141
+ dryRun,
2142
+ });
2143
+
2144
+ const adrReadmeResult = await writeTextFile({
2145
+ targetPath: adrReadmePath,
2146
+ content: `${buildAdrReadme()}\n`,
2147
+ overwrite: false,
2148
+ dryRun,
2149
+ });
2150
+ const adrTemplateResult = await writeTextFile({
2151
+ targetPath: adrTemplatePath,
2152
+ content: `${buildAdrTemplate()}\n`,
2153
+ overwrite: false,
2154
+ dryRun,
2155
+ });
2156
+
2157
+ return {
2158
+ productPath,
2159
+ architectureDocPath,
2160
+ techMdPath,
2161
+ adrReadmePath,
2162
+ adrTemplatePath,
2163
+ productResult,
2164
+ architectureDocResult,
2165
+ techResult,
2166
+ adrReadmeResult,
2167
+ adrTemplateResult,
1623
2168
  };
1624
2169
  }
1625
2170
 
@@ -8755,14 +9300,6 @@ async function performWorkflowInstall(
8755
9300
  dryRun,
8756
9301
  cwd,
8757
9302
  });
8758
- const engineeringArtifactsResult = await upsertEngineeringArtifacts({
8759
- platform,
8760
- scope: ruleScope,
8761
- overwrite: false,
8762
- dryRun,
8763
- skipTech: false,
8764
- cwd,
8765
- });
8766
9303
  const postmanSetupResult = await configurePostmanInstallArtifacts({
8767
9304
  platform,
8768
9305
  scope,
@@ -8808,7 +9345,7 @@ async function performWorkflowInstall(
8808
9345
  bundleId,
8809
9346
  installResult,
8810
9347
  syncResult,
8811
- engineeringArtifactsResult,
9348
+ engineeringArtifactsResult: null,
8812
9349
  postmanSetupResult,
8813
9350
  terminalVerificationRuleResult,
8814
9351
  };
@@ -8838,10 +9375,7 @@ async function runWorkflowInstall(options) {
8838
9375
  dryRun: result.dryRun,
8839
9376
  });
8840
9377
  printRuleSyncResult(result.syncResult);
8841
- printInstallEngineeringSummary({
8842
- engineeringResults: result.engineeringArtifactsResult.engineeringResults,
8843
- techResult: result.engineeringArtifactsResult.techResult,
8844
- });
9378
+ printInstallDocumentationNotice();
8845
9379
  printPostmanSetupSummary({
8846
9380
  postmanSetup: result.postmanSetupResult,
8847
9381
  });
@@ -12296,6 +12830,16 @@ function printInstallEngineeringSummary({ engineeringResults, techResult }) {
12296
12830
  }
12297
12831
  }
12298
12832
 
12833
+ function printInstallDocumentationNotice() {
12834
+ console.log("\nProject backbone docs:");
12835
+ console.log(
12836
+ "- Install only wires the rule references and workflow assets.",
12837
+ );
12838
+ console.log(
12839
+ `- Use \`cbx rules init\` to scaffold ENGINEERING_RULES.md and TECH.md, or \`cbx build architecture --platform <codex|claude|gemini|copilot>\` to generate ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md, and ADR scaffolds.`,
12840
+ );
12841
+ }
12842
+
12299
12843
  async function upsertEngineeringArtifacts({
12300
12844
  platform,
12301
12845
  scope,
@@ -12313,10 +12857,10 @@ async function upsertEngineeringArtifacts({
12313
12857
  const scaffold = await ensureArchitectureDocScaffold({
12314
12858
  workspaceRoot,
12315
12859
  snapshot,
12860
+ specRoots: [],
12316
12861
  overwrite,
12317
12862
  dryRun,
12318
12863
  });
12319
- const techMdPath = path.join(workspaceRoot, "TECH.md");
12320
12864
  const targets = [{ ruleFilePath }];
12321
12865
 
12322
12866
  if (scope === "global") {
@@ -12341,8 +12885,11 @@ async function upsertEngineeringArtifacts({
12341
12885
  const blockResult = await upsertEngineeringRulesBlock({
12342
12886
  ruleFilePath: target.ruleFilePath,
12343
12887
  platform,
12888
+ productFilePath: scaffold.productPath,
12889
+ architectureFilePath: scaffold.architectureDocPath,
12344
12890
  engineeringRulesFilePath: scaffold.engineeringRulesPath,
12345
- techMdFilePath: techMdPath,
12891
+ techMdFilePath: scaffold.techMdPath,
12892
+ roadmapFilePath: scaffold.roadmapPath,
12346
12893
  dryRun,
12347
12894
  });
12348
12895
  engineeringResults.push({
@@ -12474,6 +13021,68 @@ async function listSpecPackRoots(workspaceRoot) {
12474
13021
  .slice(0, 8);
12475
13022
  }
12476
13023
 
13024
+ async function resolveArchitectureInspectionAnchors(
13025
+ workspaceRoot,
13026
+ snapshot,
13027
+ specRoots,
13028
+ ) {
13029
+ const seen = new Set();
13030
+ const ordered = [];
13031
+ const pushCandidate = async (relativePath) => {
13032
+ const normalized = toPosixPath(relativePath);
13033
+ if (!normalized || seen.has(normalized)) return;
13034
+ if (!(await pathExists(path.join(workspaceRoot, relativePath)))) return;
13035
+ seen.add(normalized);
13036
+ ordered.push(normalized);
13037
+ };
13038
+
13039
+ for (const candidate of [
13040
+ "README.md",
13041
+ "package.json",
13042
+ "pubspec.yaml",
13043
+ "go.mod",
13044
+ "pyproject.toml",
13045
+ "Cargo.toml",
13046
+ "Dockerfile",
13047
+ "docker-compose.yml",
13048
+ "docker-compose.yaml",
13049
+ "compose.yaml",
13050
+ "cbx_config.json",
13051
+ ".vscode/mcp.json",
13052
+ ".gemini/settings.json",
13053
+ ]) {
13054
+ await pushCandidate(candidate);
13055
+ }
13056
+
13057
+ for (const specRoot of specRoots.slice(0, 4)) {
13058
+ await pushCandidate(specRoot);
13059
+ }
13060
+
13061
+ for (const app of snapshot.architectureByApp || []) {
13062
+ if (!app?.rootPath || app.rootPath === ".") continue;
13063
+ await pushCandidate(app.rootPath);
13064
+ for (const child of [
13065
+ "README.md",
13066
+ "src",
13067
+ "lib",
13068
+ "app",
13069
+ "prisma",
13070
+ "migrations",
13071
+ "test",
13072
+ "tests",
13073
+ "docs",
13074
+ ]) {
13075
+ await pushCandidate(path.join(app.rootPath, child));
13076
+ }
13077
+ }
13078
+
13079
+ for (const dir of snapshot.topDirs || []) {
13080
+ await pushCandidate(dir);
13081
+ }
13082
+
13083
+ return ordered.slice(0, 18);
13084
+ }
13085
+
12477
13086
  function resolveArchitectureConditionalSkills(snapshot, specRoots, researchMode) {
12478
13087
  const conditional = [];
12479
13088
  const frameworks = new Set(snapshot.frameworks || []);
@@ -12536,13 +13145,17 @@ function buildArchitecturePrompt({
12536
13145
  workspaceRoot,
12537
13146
  snapshot,
12538
13147
  specRoots,
13148
+ inspectionAnchors,
12539
13149
  researchMode,
12540
13150
  coreSkills,
12541
13151
  conditionalSkills,
12542
13152
  skillPathHints,
12543
13153
  }) {
12544
- const rulesPath = "ENGINEERING_RULES.md";
12545
- const techPath = "TECH.md";
13154
+ const productPath = `${FOUNDATION_DOCS_DIR}/PRODUCT.md`;
13155
+ const architecturePath = `${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md`;
13156
+ const techPath = `${FOUNDATION_DOCS_DIR}/TECH.md`;
13157
+ const adrReadmePath = `${FOUNDATION_ADR_DIR}/README.md`;
13158
+ const adrTemplatePath = `${FOUNDATION_ADR_DIR}/0000-template.md`;
12546
13159
  const architectureSignals = snapshot.architectureByApp
12547
13160
  .filter((item) => (item.architectureSignals || []).length > 0)
12548
13161
  .map((item) => {
@@ -12554,9 +13167,9 @@ function buildArchitecturePrompt({
12554
13167
  `You are running inside ${platform}.`,
12555
13168
  "",
12556
13169
  "Objective:",
12557
- `- Inspect the repository at ${toPosixPath(workspaceRoot)} and refresh the managed architecture sections in ${rulesPath} and ${techPath}.`,
12558
- "- Keep ENGINEERING_RULES.md normative and TECH.md descriptive.",
12559
- "- Preserve manual content outside the managed `cbx:architecture:*` markers.",
13170
+ `- Inspect the repository at ${toPosixPath(workspaceRoot)} and author or refresh the core foundation docs in ${productPath}, ${architecturePath}, ${techPath}, ${adrReadmePath}, and ${adrTemplatePath}.`,
13171
+ "- The content should be primarily AI-authored from repository inspection, not copied from placeholder scaffolding.",
13172
+ "- Preserve manual content outside the managed `cbx:*` markers.",
12560
13173
  "",
12561
13174
  "Required skill bundle:",
12562
13175
  `- Load these exact skill IDs first: ${coreSkills.map((skillId) => `\`${skillId}\``).join(", ")}`,
@@ -12575,24 +13188,33 @@ function buildArchitecturePrompt({
12575
13188
  architectureSignals.length > 0
12576
13189
  ? `- Architecture signals: ${architectureSignals.join(" | ")}`
12577
13190
  : "- Architecture signals: none confidently inferred from the repo scan",
13191
+ `- Entry points: ${snapshot.entryPoints.length > 0 ? snapshot.entryPoints.slice(0, 8).join(" | ") : "none detected"}`,
13192
+ `- Key scripts: ${snapshot.keyScripts.length > 0 ? snapshot.keyScripts.slice(0, 8).map((item) => `${item.name}=${item.command}`).join(" | ") : "none detected"}`,
13193
+ `- Inspection anchors: ${inspectionAnchors.length > 0 ? inspectionAnchors.join(", ") : "no concrete anchors detected; inspect the repo root, main source trees, and manifest files manually"}`,
12578
13194
  "",
12579
13195
  "Execution contract:",
12580
- "1. Read ENGINEERING_RULES.md first if present, then read TECH.md.",
12581
- "2. Inspect the repo before making architecture claims.",
12582
- "3. Update only the content between the existing `cbx:architecture:rules` and `cbx:architecture:tech` markers.",
12583
- "4. Keep the marker lines themselves intact, including their hash metadata.",
12584
- "5. In ENGINEERING_RULES.md, state architecture style, dependency rules, feature or module structure rules, design-system source of truth, testability expectations, and doc refresh policy.",
12585
- "6. In TECH.md, update architecture snapshot, module or app topology, flow narratives, Mermaid diagrams, and scaling or deployment notes.",
13196
+ "1. Inspect the repository first before writing any backbone doc content. Derive structure, product surfaces, runtime boundaries, and technical constraints from the actual codebase.",
13197
+ "2. Complete a real inspection pass before drafting. At minimum, inspect the concrete anchors listed above, plus any adjacent directories needed to understand the main execution paths, data boundaries, and integration surfaces.",
13198
+ "3. Do not infer architecture from filenames alone when you can open representative files. Read enough source to validate the main app boundaries, runtime flows, and persistence/integration patterns.",
13199
+ `4. Then read ${productPath}, ${architecturePath}, and ${techPath} in that order when they exist so you can preserve useful manual context and update existing managed sections cleanly.`,
13200
+ `5. Replace or update only the content between the existing managed markers in ${productPath}, ${architecturePath}, and ${techPath}. Do not append a second marker block.`,
13201
+ `6. In ${productPath}, write a concrete product foundation: product purpose, primary users/operators, main journeys, business capabilities, operational constraints, and what future contributors must preserve.`,
13202
+ `7. In ${architecturePath}, write a lean but detailed architecture backbone in a pragmatic arc42/C4 style: system purpose and constraints, bounded contexts, major building blocks, dependency rules, data and integration boundaries, runtime flows, deployment/operability notes, testing/debugging strategy, and only the diagram levels that add real value.`,
13203
+ `8. In ${techPath}, write the developer-facing technical map: stack, repo layout, key commands, entrypoints, data stores, external services, environment/config surfaces, MCP/tooling footprint, and change hotspots future agents should inspect before editing code.`,
13204
+ "9. Every major claim should be grounded in repository evidence. Mention concrete repo paths in the docs when a structural claim would otherwise be ambiguous.",
13205
+ "10. Avoid placeholder filler, generic checklists, and duplicated content across files. Each doc should have a clear job.",
13206
+ "11. Do not create ROADMAP.md, ENGINEERING_RULES.md, or other extra docs unless the prompt explicitly asks for them.",
12586
13207
  researchMode === "never"
12587
- ? "7. Stay repo-only. Do not use outside research."
12588
- : "7. Use repo evidence first. Use official docs when needed. Treat Reddit or community sources only as labeled secondary evidence.",
13208
+ ? "12. Stay repo-only. Do not use outside research."
13209
+ : "12. Use repo evidence first. Use official docs when needed. Treat Reddit or community sources only as labeled secondary evidence.",
12589
13210
  researchMode === "always"
12590
- ? "8. Include an external research evidence subsection in TECH.md with clearly labeled primary and secondary evidence."
12591
- : "8. Include external research notes only if they materially informed the architecture update.",
12592
- "9. If the project clearly follows Clean Architecture, feature-first modules, or another stable structure, make that explicit so future implementation stays consistent.",
13211
+ ? `13. Include an external research evidence subsection in ${techPath} with clearly labeled primary and secondary evidence.`
13212
+ : "13. Include external research notes only if they materially informed the architecture update.",
13213
+ `14. If the project clearly follows Clean Architecture, feature-first modules, DDD, modular monolith, or another stable structure, make that explicit in ${architecturePath} with evidence from the repo.`,
13214
+ `15. Ensure ${adrReadmePath} and ${adrTemplatePath} exist as ADR entrypoints, but keep them lean.`,
12593
13215
  "",
12594
13216
  "Return one JSON object on the last line with this shape:",
12595
- '{"files_written":["ENGINEERING_RULES.md","TECH.md"],"research_used":false,"gaps":[],"next_actions":[]}',
13217
+ `{"files_written":["${productPath}","${architecturePath}","${techPath}","${adrReadmePath}","${adrTemplatePath}"],"research_used":false,"gaps":[],"next_actions":[]}`,
12596
13218
  "",
12597
13219
  "Do not emit placeholder TODOs in the managed sections.",
12598
13220
  ].join("\n");
@@ -12622,6 +13244,95 @@ async function execFileCapture(command, args, options = {}) {
12622
13244
  }
12623
13245
  }
12624
13246
 
13247
+ async function spawnCapture(command, args, options = {}) {
13248
+ const { cwd, env, streamOutput = false } = options;
13249
+ return await new Promise((resolve, reject) => {
13250
+ let stdout = "";
13251
+ let stderr = "";
13252
+ const child = spawn(command, args, {
13253
+ cwd,
13254
+ env,
13255
+ stdio: ["ignore", "pipe", "pipe"],
13256
+ });
13257
+
13258
+ child.stdout.on("data", (chunk) => {
13259
+ const text = chunk.toString();
13260
+ stdout += text;
13261
+ if (streamOutput) process.stdout.write(text);
13262
+ });
13263
+
13264
+ child.stderr.on("data", (chunk) => {
13265
+ const text = chunk.toString();
13266
+ stderr += text;
13267
+ if (streamOutput) process.stderr.write(text);
13268
+ });
13269
+
13270
+ child.on("error", (error) => {
13271
+ if (error?.code === "ENOENT") {
13272
+ reject(
13273
+ new Error(`Required CLI '${command}' is not installed or not on PATH.`),
13274
+ );
13275
+ return;
13276
+ }
13277
+ reject(error);
13278
+ });
13279
+
13280
+ child.on("close", (code) => {
13281
+ resolve({
13282
+ ok: code === 0,
13283
+ stdout,
13284
+ stderr,
13285
+ code: code ?? 1,
13286
+ });
13287
+ });
13288
+ });
13289
+ }
13290
+
13291
+ function explainArchitectureBuildFailure(platform, execution) {
13292
+ const combined = String(
13293
+ `${execution.stderr || ""}\n${execution.stdout || ""}`.trim(),
13294
+ );
13295
+ const notes = [];
13296
+
13297
+ if (platform === "gemini") {
13298
+ if (
13299
+ combined.includes("Error during discovery for MCP server") ||
13300
+ combined.includes("[MCP error]")
13301
+ ) {
13302
+ notes.push(
13303
+ "Gemini CLI is failing while loading MCP servers from your Gemini settings. Start the required MCP runtime(s) first or disable the broken server entries in `.gemini/settings.json` before retrying.",
13304
+ );
13305
+ }
13306
+ if (
13307
+ combined.includes("cloudaicompanion.companions.generateChat") ||
13308
+ combined.includes("PERMISSION_DENIED") ||
13309
+ combined.includes("403")
13310
+ ) {
13311
+ notes.push(
13312
+ "Gemini CLI reached Google auth, but the active account or project cannot generate chat content. Re-authenticate Gemini CLI with a permitted account or configure a supported Gemini API credential and project before retrying.",
13313
+ );
13314
+ }
13315
+ }
13316
+
13317
+ if (platform === "claude" && combined.includes("permission")) {
13318
+ notes.push(
13319
+ "Claude CLI appears to be blocked by its own permission model. Re-run in a Claude environment that allows non-interactive edits for this workspace.",
13320
+ );
13321
+ }
13322
+
13323
+ if (notes.length === 0) {
13324
+ return `Architecture build failed via ${platform}. ${combined}`.trim();
13325
+ }
13326
+
13327
+ return [
13328
+ `Architecture build failed via ${platform}.`,
13329
+ ...notes.map((note) => `- ${note}`),
13330
+ combined ? `Raw CLI output:\n${combined}` : "",
13331
+ ]
13332
+ .filter(Boolean)
13333
+ .join("\n");
13334
+ }
13335
+
12625
13336
  async function probeArchitectureAdapter(platform, cwd) {
12626
13337
  if (platform === "codex") {
12627
13338
  const help = await execFileCapture("codex", ["exec", "--help"], { cwd });
@@ -12710,9 +13421,8 @@ async function probeArchitectureAdapter(platform, cwd) {
12710
13421
  function normalizeArchitectureResult({
12711
13422
  stdout,
12712
13423
  workspaceRoot,
12713
- rulesPath,
12714
- techPath,
12715
13424
  researchMode,
13425
+ changedFiles = [],
12716
13426
  }) {
12717
13427
  const trimmed = String(stdout || "").trim();
12718
13428
  if (trimmed) {
@@ -12722,9 +13432,12 @@ function normalizeArchitectureResult({
12722
13432
  const parsed = JSON.parse(lastLine);
12723
13433
  return {
12724
13434
  outputRoot: workspaceRoot,
12725
- filesWritten: Array.isArray(parsed.files_written)
12726
- ? parsed.files_written
12727
- : [rulesPath, techPath],
13435
+ filesWritten:
13436
+ changedFiles.length > 0
13437
+ ? changedFiles
13438
+ : Array.isArray(parsed.files_written)
13439
+ ? parsed.files_written
13440
+ : [],
12728
13441
  researchUsed:
12729
13442
  typeof parsed.research_used === "boolean"
12730
13443
  ? parsed.research_used
@@ -12743,7 +13456,7 @@ function normalizeArchitectureResult({
12743
13456
 
12744
13457
  return {
12745
13458
  outputRoot: workspaceRoot,
12746
- filesWritten: [rulesPath, techPath],
13459
+ filesWritten: changedFiles,
12747
13460
  researchUsed: researchMode === "always",
12748
13461
  gaps: [],
12749
13462
  nextActions: [],
@@ -12751,51 +13464,76 @@ function normalizeArchitectureResult({
12751
13464
  };
12752
13465
  }
12753
13466
 
13467
+ async function captureFileContents(filePaths) {
13468
+ const snapshot = {};
13469
+ for (const filePath of filePaths) {
13470
+ if (await pathExists(filePath)) {
13471
+ snapshot[filePath] = await readFile(filePath, "utf8");
13472
+ } else {
13473
+ snapshot[filePath] = null;
13474
+ }
13475
+ }
13476
+ return snapshot;
13477
+ }
13478
+
12754
13479
  async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
12755
- const rulesPath = path.join(workspaceRoot, "ENGINEERING_RULES.md");
12756
- const techPath = path.join(workspaceRoot, "TECH.md");
13480
+ const productPath = path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md");
13481
+ const architecturePath = path.join(
13482
+ workspaceRoot,
13483
+ FOUNDATION_DOCS_DIR,
13484
+ "ARCHITECTURE.md",
13485
+ );
13486
+ const techPath = path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md");
13487
+ const adrReadmePath = path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md");
12757
13488
  const metadataPath = path.join(
12758
13489
  workspaceRoot,
12759
13490
  ".cbx",
12760
13491
  ARCHITECTURE_BUILD_METADATA_FILENAME,
12761
13492
  );
12762
- const rulesExists = await pathExists(rulesPath);
13493
+ const productExists = await pathExists(productPath);
13494
+ const architectureExists = await pathExists(architecturePath);
12763
13495
  const techExists = await pathExists(techPath);
12764
-
12765
- const expectedRulesHash = hashStableObject(
12766
- inferArchitectureContractProfile(snapshot),
12767
- );
12768
- const expectedTechHash = hashStableObject({
12769
- style: inferArchitectureContractProfile(snapshot).style,
12770
- topDirs: snapshot.topDirs,
12771
- frameworks: snapshot.frameworks,
12772
- architectureByApp: snapshot.architectureByApp,
12773
- });
13496
+ const adrReadmeExists = await pathExists(adrReadmePath);
12774
13497
 
12775
13498
  const findings = [];
12776
- let actualRulesHash = null;
13499
+ let actualProductHash = null;
13500
+ let actualArchitectureHash = null;
12777
13501
  let actualTechHash = null;
12778
13502
 
12779
- if (!rulesExists) {
12780
- findings.push("ENGINEERING_RULES.md is missing.");
13503
+ if (!productExists) {
13504
+ findings.push(`${FOUNDATION_DOCS_DIR}/PRODUCT.md is missing.`);
13505
+ } else {
13506
+ const content = await readFile(productPath, "utf8");
13507
+ actualProductHash = extractTaggedMarkerAttribute(
13508
+ content,
13509
+ PRODUCT_FOUNDATION_BLOCK_START_RE,
13510
+ "profile",
13511
+ );
13512
+ if (!actualProductHash) {
13513
+ findings.push(
13514
+ `${FOUNDATION_DOCS_DIR}/PRODUCT.md is missing the managed product foundation block.`,
13515
+ );
13516
+ }
13517
+ }
13518
+
13519
+ if (!architectureExists) {
13520
+ findings.push(`${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md is missing.`);
12781
13521
  } else {
12782
- const content = await readFile(rulesPath, "utf8");
12783
- actualRulesHash = extractTaggedMarkerAttribute(
13522
+ const content = await readFile(architecturePath, "utf8");
13523
+ actualArchitectureHash = extractTaggedMarkerAttribute(
12784
13524
  content,
12785
- ENGINEERING_ARCHITECTURE_BLOCK_START_RE,
13525
+ ARCHITECTURE_DOC_BLOCK_START_RE,
12786
13526
  "profile",
12787
13527
  );
12788
- if (!actualRulesHash) {
12789
- findings.push("ENGINEERING_RULES.md is missing the managed architecture contract block.");
12790
- } else if (actualRulesHash !== expectedRulesHash) {
13528
+ if (!actualArchitectureHash) {
12791
13529
  findings.push(
12792
- `ENGINEERING_RULES.md architecture profile is stale (expected ${expectedRulesHash}, found ${actualRulesHash}).`,
13530
+ `${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md is missing the managed architecture backbone block.`,
12793
13531
  );
12794
13532
  }
12795
13533
  }
12796
13534
 
12797
13535
  if (!techExists) {
12798
- findings.push("TECH.md is missing.");
13536
+ findings.push(`${FOUNDATION_DOCS_DIR}/TECH.md is missing.`);
12799
13537
  } else {
12800
13538
  const content = await readFile(techPath, "utf8");
12801
13539
  actualTechHash = extractTaggedMarkerAttribute(
@@ -12804,14 +13542,16 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
12804
13542
  "snapshot",
12805
13543
  );
12806
13544
  if (!actualTechHash) {
12807
- findings.push("TECH.md is missing the managed architecture snapshot block.");
12808
- } else if (actualTechHash !== expectedTechHash) {
12809
13545
  findings.push(
12810
- `TECH.md architecture snapshot is stale (expected ${expectedTechHash}, found ${actualTechHash}).`,
13546
+ `${FOUNDATION_DOCS_DIR}/TECH.md is missing the managed architecture snapshot block.`,
12811
13547
  );
12812
13548
  }
12813
13549
  }
12814
13550
 
13551
+ if (!adrReadmeExists) {
13552
+ findings.push(`${FOUNDATION_ADR_DIR}/README.md is missing.`);
13553
+ }
13554
+
12815
13555
  const metadata = await readJsonFileIfExists(metadataPath);
12816
13556
  if (!metadata.exists) {
12817
13557
  findings.push("Architecture build metadata is missing.");
@@ -12820,12 +13560,13 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
12820
13560
  return {
12821
13561
  stale: findings.length > 0,
12822
13562
  findings,
12823
- rulesPath,
13563
+ productPath,
13564
+ architecturePath,
12824
13565
  techPath,
13566
+ adrReadmePath,
12825
13567
  metadataPath,
12826
- expectedRulesHash,
12827
- expectedTechHash,
12828
- actualRulesHash,
13568
+ actualProductHash,
13569
+ actualArchitectureHash,
12829
13570
  actualTechHash,
12830
13571
  };
12831
13572
  }
@@ -12841,6 +13582,7 @@ async function runBuildArchitecture(options) {
12841
13582
  const cwd = process.cwd();
12842
13583
  const workspaceRoot = findWorkspaceRoot(cwd);
12843
13584
  const snapshot = await collectTechSnapshot(workspaceRoot);
13585
+ const specRoots = await listSpecPackRoots(workspaceRoot);
12844
13586
 
12845
13587
  if (checkOnly) {
12846
13588
  const drift = await readArchitectureDriftStatus(workspaceRoot, snapshot);
@@ -12850,6 +13592,9 @@ async function runBuildArchitecture(options) {
12850
13592
  console.log(`Platform: ${platform}`);
12851
13593
  console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
12852
13594
  console.log(`Status: ${drift.stale ? "stale" : "fresh"}`);
13595
+ console.log(
13596
+ `Backbone docs: ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md, ${FOUNDATION_ADR_DIR}/README.md`,
13597
+ );
12853
13598
  if (drift.findings.length > 0) {
12854
13599
  console.log("Findings:");
12855
13600
  for (const finding of drift.findings) {
@@ -12861,13 +13606,13 @@ async function runBuildArchitecture(options) {
12861
13606
  return;
12862
13607
  }
12863
13608
 
12864
- const scaffold = await ensureArchitectureDocScaffold({
12865
- workspaceRoot,
12866
- snapshot,
12867
- overwrite,
12868
- dryRun,
12869
- });
12870
- const specRoots = await listSpecPackRoots(workspaceRoot);
13609
+ const managedFilePaths = [
13610
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md"),
13611
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "ARCHITECTURE.md"),
13612
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md"),
13613
+ path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md"),
13614
+ path.join(workspaceRoot, FOUNDATION_ADR_DIR, "0000-template.md"),
13615
+ ];
12871
13616
  const coreSkills = [
12872
13617
  "architecture-doc",
12873
13618
  "system-design",
@@ -12885,11 +13630,17 @@ async function runBuildArchitecture(options) {
12885
13630
  cwd,
12886
13631
  skillBundle,
12887
13632
  );
13633
+ const inspectionAnchors = await resolveArchitectureInspectionAnchors(
13634
+ workspaceRoot,
13635
+ snapshot,
13636
+ specRoots,
13637
+ );
12888
13638
  const prompt = buildArchitecturePrompt({
12889
13639
  platform,
12890
13640
  workspaceRoot,
12891
13641
  snapshot,
12892
13642
  specRoots,
13643
+ inspectionAnchors,
12893
13644
  researchMode,
12894
13645
  coreSkills,
12895
13646
  conditionalSkills,
@@ -12897,6 +13648,13 @@ async function runBuildArchitecture(options) {
12897
13648
  });
12898
13649
  const adapter = await probeArchitectureAdapter(platform, workspaceRoot);
12899
13650
  const args = adapter.buildInvocation(prompt);
13651
+ const managedTargets = [
13652
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md"),
13653
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "ARCHITECTURE.md"),
13654
+ path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md"),
13655
+ path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md"),
13656
+ path.join(workspaceRoot, FOUNDATION_ADR_DIR, "0000-template.md"),
13657
+ ].map((filePath) => toPosixPath(filePath));
12900
13658
 
12901
13659
  if (dryRun) {
12902
13660
  const summary = {
@@ -12905,10 +13663,7 @@ async function runBuildArchitecture(options) {
12905
13663
  adapter: adapter.binary,
12906
13664
  invocation: [adapter.binary, ...args],
12907
13665
  researchMode,
12908
- managedTargets: [
12909
- toPosixPath(scaffold.engineeringRulesPath),
12910
- toPosixPath(scaffold.techMdPath),
12911
- ],
13666
+ managedTargets,
12912
13667
  skillBundle,
12913
13668
  };
12914
13669
  if (emitJson) {
@@ -12919,7 +13674,7 @@ async function runBuildArchitecture(options) {
12919
13674
  console.log(`Adapter: ${adapter.binary}`);
12920
13675
  console.log(`Research mode: ${researchMode}`);
12921
13676
  console.log(
12922
- `Managed targets: ${toPosixPath(scaffold.engineeringRulesPath)}, ${toPosixPath(scaffold.techMdPath)}`,
13677
+ `Managed targets: ${summary.managedTargets.join(", ")}`,
12923
13678
  );
12924
13679
  console.log(`Skill bundle: ${skillBundle.join(", ")}`);
12925
13680
  console.log(`Invocation: ${[adapter.binary, ...args].join(" ")}`);
@@ -12927,18 +13682,38 @@ async function runBuildArchitecture(options) {
12927
13682
  return;
12928
13683
  }
12929
13684
 
12930
- const execution = await execFileCapture(adapter.binary, args, {
13685
+ const filesBefore = await captureFileContents(managedFilePaths);
13686
+ const scaffold = await ensureArchitectureBuildScaffold({
13687
+ workspaceRoot,
13688
+ dryRun,
13689
+ });
13690
+
13691
+ if (!emitJson) {
13692
+ console.log(`Streaming ${adapter.binary} output...`);
13693
+ }
13694
+
13695
+ const execution = await spawnCapture(adapter.binary, args, {
12931
13696
  cwd: workspaceRoot,
12932
13697
  env: process.env,
13698
+ streamOutput: !emitJson,
12933
13699
  });
12934
13700
  if (!execution.ok) {
12935
- throw new Error(
12936
- `Architecture build failed via ${adapter.binary}. ${String(execution.stderr || execution.stdout || "").trim()}`,
12937
- );
13701
+ throw new Error(explainArchitectureBuildFailure(platform, execution));
12938
13702
  }
12939
13703
 
12940
- const rulesContent = await readFile(scaffold.engineeringRulesPath, "utf8");
12941
- const techContent = await readFile(scaffold.techMdPath, "utf8");
13704
+ const filesAfter = await captureFileContents(managedFilePaths);
13705
+ const changedFiles = managedFilePaths
13706
+ .filter((filePath) => filesBefore[filePath] !== filesAfter[filePath])
13707
+ .map((filePath) => toPosixPath(path.relative(workspaceRoot, filePath)));
13708
+
13709
+ const techContent =
13710
+ filesAfter[scaffold.techMdPath] ?? (await readFile(scaffold.techMdPath, "utf8"));
13711
+ const productContent =
13712
+ filesAfter[scaffold.productPath] ?? (await readFile(scaffold.productPath, "utf8"));
13713
+ const architectureContent =
13714
+ filesAfter[scaffold.architectureDocPath] ??
13715
+ (await readFile(scaffold.architectureDocPath, "utf8"));
13716
+
12942
13717
  const metadataPath = path.join(
12943
13718
  workspaceRoot,
12944
13719
  ".cbx",
@@ -12947,18 +13722,13 @@ async function runBuildArchitecture(options) {
12947
13722
  const metadata = buildArchitectureBuildMetadata({
12948
13723
  platform,
12949
13724
  researchMode,
12950
- rulesProfileHash:
12951
- extractTaggedMarkerAttribute(
12952
- rulesContent,
12953
- ENGINEERING_ARCHITECTURE_BLOCK_START_RE,
12954
- "profile",
12955
- ) || "unknown",
12956
- techSnapshotHash:
12957
- extractTaggedMarkerAttribute(
12958
- techContent,
12959
- TECH_ARCHITECTURE_BLOCK_START_RE,
12960
- "snapshot",
12961
- ) || "unknown",
13725
+ managedDocs: [
13726
+ `${FOUNDATION_DOCS_DIR}/PRODUCT.md`,
13727
+ `${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md`,
13728
+ `${FOUNDATION_DOCS_DIR}/TECH.md`,
13729
+ `${FOUNDATION_ADR_DIR}/README.md`,
13730
+ `${FOUNDATION_ADR_DIR}/0000-template.md`,
13731
+ ],
12962
13732
  });
12963
13733
  await mkdir(path.dirname(metadataPath), { recursive: true });
12964
13734
  await writeFile(
@@ -12970,9 +13740,8 @@ async function runBuildArchitecture(options) {
12970
13740
  const result = normalizeArchitectureResult({
12971
13741
  stdout: execution.stdout,
12972
13742
  workspaceRoot: toPosixPath(workspaceRoot),
12973
- rulesPath: "ENGINEERING_RULES.md",
12974
- techPath: "TECH.md",
12975
13743
  researchMode,
13744
+ changedFiles: [...new Set(changedFiles)],
12976
13745
  });
12977
13746
 
12978
13747
  if (emitJson) {
@@ -12994,7 +13763,12 @@ async function runBuildArchitecture(options) {
12994
13763
  console.log(`Platform: ${platform}`);
12995
13764
  console.log(`Adapter: ${adapter.binary}`);
12996
13765
  console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
12997
- console.log(`Managed docs: ENGINEERING_RULES.md, TECH.md`);
13766
+ console.log(
13767
+ `Managed docs: ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md`,
13768
+ );
13769
+ console.log(
13770
+ `ADR scaffold: ${FOUNDATION_ADR_DIR}/README.md, ${FOUNDATION_ADR_DIR}/0000-template.md`,
13771
+ );
12998
13772
  console.log(`Skill bundle: ${skillBundle.join(", ")}`);
12999
13773
  console.log(
13000
13774
  `Files written: ${(result.filesWritten || []).join(", ") || "(none reported)"}`,
@@ -13273,11 +14047,7 @@ async function runInitWizard(options) {
13273
14047
  dryRun: installOutcome.dryRun,
13274
14048
  });
13275
14049
  printRuleSyncResult(installOutcome.syncResult);
13276
- printInstallEngineeringSummary({
13277
- engineeringResults:
13278
- installOutcome.engineeringArtifactsResult.engineeringResults,
13279
- techResult: installOutcome.engineeringArtifactsResult.techResult,
13280
- });
14050
+ printInstallDocumentationNotice();
13281
14051
  printPostmanSetupSummary({
13282
14052
  postmanSetup: installOutcome.postmanSetupResult,
13283
14053
  });