swallowkit 1.0.0-beta.55 → 1.0.0-beta.57

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 (141) hide show
  1. package/dist/cli/commands/add-auth.d.ts.map +1 -1
  2. package/dist/cli/commands/add-auth.js +154 -157
  3. package/dist/cli/commands/add-auth.js.map +1 -1
  4. package/dist/cli/commands/init.d.ts +5 -0
  5. package/dist/cli/commands/init.d.ts.map +1 -1
  6. package/dist/cli/commands/init.js +178 -25
  7. package/dist/cli/commands/init.js.map +1 -1
  8. package/dist/cli/commands/scaffold.d.ts +7 -2
  9. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  10. package/dist/cli/commands/scaffold.js +113 -123
  11. package/dist/cli/commands/scaffold.js.map +1 -1
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +127 -2
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/core/config.d.ts +1 -1
  16. package/dist/core/config.d.ts.map +1 -1
  17. package/dist/core/config.js +8 -4
  18. package/dist/core/config.js.map +1 -1
  19. package/dist/core/operations/auth-operations.d.ts +57 -0
  20. package/dist/core/operations/auth-operations.d.ts.map +1 -0
  21. package/dist/core/operations/auth-operations.js +269 -0
  22. package/dist/core/operations/auth-operations.js.map +1 -0
  23. package/dist/core/operations/create-model.d.ts.map +1 -1
  24. package/dist/core/operations/create-model.js +23 -13
  25. package/dist/core/operations/create-model.js.map +1 -1
  26. package/dist/core/operations/file-session.d.ts +56 -0
  27. package/dist/core/operations/file-session.d.ts.map +1 -0
  28. package/dist/core/operations/file-session.js +203 -0
  29. package/dist/core/operations/file-session.js.map +1 -0
  30. package/dist/core/operations/provision-operations.d.ts +52 -0
  31. package/dist/core/operations/provision-operations.d.ts.map +1 -0
  32. package/dist/core/operations/provision-operations.js +211 -0
  33. package/dist/core/operations/provision-operations.js.map +1 -0
  34. package/dist/core/operations/runtime.d.ts +5 -0
  35. package/dist/core/operations/runtime.d.ts.map +1 -1
  36. package/dist/core/operations/runtime.js +23 -0
  37. package/dist/core/operations/runtime.js.map +1 -1
  38. package/dist/core/operations/scaffold-apply.d.ts +21 -0
  39. package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
  40. package/dist/core/operations/scaffold-apply.js +57 -0
  41. package/dist/core/operations/scaffold-apply.js.map +1 -0
  42. package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
  43. package/dist/core/operations/scaffold-machine.js +1 -13
  44. package/dist/core/operations/scaffold-machine.js.map +1 -1
  45. package/dist/core/operations/scaffold-plan.d.ts +43 -0
  46. package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
  47. package/dist/core/operations/scaffold-plan.js +187 -0
  48. package/dist/core/operations/scaffold-plan.js.map +1 -0
  49. package/dist/core/project/artifacts.d.ts +58 -0
  50. package/dist/core/project/artifacts.d.ts.map +1 -0
  51. package/dist/core/project/artifacts.js +179 -0
  52. package/dist/core/project/artifacts.js.map +1 -0
  53. package/dist/core/project/boundaries.d.ts +50 -0
  54. package/dist/core/project/boundaries.d.ts.map +1 -0
  55. package/dist/core/project/boundaries.js +117 -0
  56. package/dist/core/project/boundaries.js.map +1 -0
  57. package/dist/core/project/drift.d.ts +29 -0
  58. package/dist/core/project/drift.d.ts.map +1 -0
  59. package/dist/core/project/drift.js +188 -0
  60. package/dist/core/project/drift.js.map +1 -0
  61. package/dist/core/project/infra.d.ts +49 -0
  62. package/dist/core/project/infra.d.ts.map +1 -0
  63. package/dist/core/project/infra.js +167 -0
  64. package/dist/core/project/infra.js.map +1 -0
  65. package/dist/core/project/state.d.ts +15 -0
  66. package/dist/core/project/state.d.ts.map +1 -0
  67. package/dist/core/project/state.js +106 -0
  68. package/dist/core/project/state.js.map +1 -0
  69. package/dist/core/project/workflows.d.ts +43 -0
  70. package/dist/core/project/workflows.d.ts.map +1 -0
  71. package/dist/core/project/workflows.js +255 -0
  72. package/dist/core/project/workflows.js.map +1 -0
  73. package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
  74. package/dist/core/scaffold/auth-generator.js +24 -27
  75. package/dist/core/scaffold/auth-generator.js.map +1 -1
  76. package/dist/core/scaffold/functions-generator.js +9 -9
  77. package/dist/core/scaffold/native-schema-generator.d.ts +7 -1
  78. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
  79. package/dist/core/scaffold/native-schema-generator.js +104 -47
  80. package/dist/core/scaffold/native-schema-generator.js.map +1 -1
  81. package/dist/core/scaffold/nextjs-generator.js +6 -6
  82. package/dist/core/scaffold/ui-generator.js +19 -19
  83. package/dist/core/scaffold/ui-generator.js.map +1 -1
  84. package/dist/core/verify/index.d.ts +62 -0
  85. package/dist/core/verify/index.d.ts.map +1 -0
  86. package/dist/core/verify/index.js +343 -0
  87. package/dist/core/verify/index.js.map +1 -0
  88. package/dist/machine/contracts.d.ts +8 -0
  89. package/dist/machine/contracts.d.ts.map +1 -1
  90. package/dist/machine/errors.d.ts +4 -1
  91. package/dist/machine/errors.d.ts.map +1 -1
  92. package/dist/machine/errors.js +9 -1
  93. package/dist/machine/errors.js.map +1 -1
  94. package/dist/machine/index.d.ts.map +1 -1
  95. package/dist/machine/index.js +350 -16
  96. package/dist/machine/index.js.map +1 -1
  97. package/dist/mcp/index.d.ts.map +1 -1
  98. package/dist/mcp/index.js +202 -1
  99. package/dist/mcp/index.js.map +1 -1
  100. package/dist/types/index.d.ts +14 -0
  101. package/dist/types/index.d.ts.map +1 -1
  102. package/package.json +1 -1
  103. package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +17 -17
  104. package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +6 -6
  105. package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +11 -11
  106. package/src/__tests__/agent-loop-phase34.test.ts +449 -0
  107. package/src/__tests__/file-session.test.ts +98 -0
  108. package/src/__tests__/init.test.ts +50 -0
  109. package/src/__tests__/mcp.test.ts +113 -5
  110. package/src/__tests__/plan-apply.test.ts +461 -0
  111. package/src/__tests__/scaffold.test.ts +2 -2
  112. package/src/cli/commands/add-auth.ts +164 -164
  113. package/src/cli/commands/init.ts +186 -24
  114. package/src/cli/commands/scaffold.ts +136 -130
  115. package/src/cli/index.ts +148 -2
  116. package/src/core/config.ts +5 -4
  117. package/src/core/operations/auth-operations.ts +353 -0
  118. package/src/core/operations/create-model.ts +25 -13
  119. package/src/core/operations/file-session.ts +222 -0
  120. package/src/core/operations/provision-operations.ts +297 -0
  121. package/src/core/operations/runtime.ts +23 -0
  122. package/src/core/operations/scaffold-apply.ts +106 -0
  123. package/src/core/operations/scaffold-machine.ts +2 -16
  124. package/src/core/operations/scaffold-plan.ts +215 -0
  125. package/src/core/project/artifacts.ts +205 -0
  126. package/src/core/project/boundaries.ts +170 -0
  127. package/src/core/project/drift.ts +202 -0
  128. package/src/core/project/infra.ts +196 -0
  129. package/src/core/project/state.ts +77 -0
  130. package/src/core/project/workflows.ts +249 -0
  131. package/src/core/scaffold/auth-generator.ts +24 -27
  132. package/src/core/scaffold/functions-generator.ts +9 -9
  133. package/src/core/scaffold/native-schema-generator.ts +152 -70
  134. package/src/core/scaffold/nextjs-generator.ts +6 -6
  135. package/src/core/scaffold/ui-generator.ts +19 -19
  136. package/src/core/verify/index.ts +392 -0
  137. package/src/machine/contracts.ts +16 -0
  138. package/src/machine/errors.ts +12 -1
  139. package/src/machine/index.ts +444 -15
  140. package/src/mcp/index.ts +198 -2
  141. package/src/types/index.ts +17 -0
@@ -17,6 +17,7 @@ import {
17
17
  getSwaAppBuildCommand,
18
18
  } from "../../utils/package-manager";
19
19
  import { syncProjectManifest } from "../../core/project/manifest";
20
+ import { writeWorkflowDocs, writeAgentSkills } from "../../core/project/workflows";
20
21
  import {
21
22
  buildCSharpCodegenToolManifestSource,
22
23
  buildPythonCodegenRequirementsSource,
@@ -296,6 +297,25 @@ export async function initCommand(options: InitOptions) {
296
297
  process.exit(1);
297
298
  }
298
299
 
300
+ // 非対話環境でプロンプトに入るとハングするため、不足フラグを明示エラーで案内する
301
+ const interactive =
302
+ process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
303
+ if (!interactive) {
304
+ const missing: string[] = [];
305
+ if (!options.cicd) missing.push('--cicd <github|azure|skip>');
306
+ if (!options.backendLanguage) missing.push('--backend-language <typescript|csharp|python>');
307
+ if (!options.cosmosDbMode) missing.push('--cosmos-db-mode <freetier|serverless>');
308
+ if (!options.vnet) missing.push('--vnet <outbound|none>');
309
+ if (!options.swaPlan) missing.push('--swa-plan <free|standard>');
310
+ if (missing.length > 0) {
311
+ console.error(
312
+ `❌ Non-interactive environment detected. Pass all configuration flags to run init without prompts:\n` +
313
+ missing.map((flag) => ` ${flag}`).join('\n')
314
+ );
315
+ process.exit(1);
316
+ }
317
+ }
318
+
299
319
  // Use flag values if provided, otherwise prompt interactively
300
320
  const cicdProvider: CiCdProvider = options.cicd || await promptCiCd();
301
321
  const backendLanguage: BackendLanguage = options.backendLanguage || await promptBackendLanguage();
@@ -564,8 +584,9 @@ export async function withNpmLockfileSafeManifests(projectDir: string, action: (
564
584
  * For pnpm, additionally tee stdout/stderr to a buffer so that if the command
565
585
  * fails due to `ERR_PNPM_IGNORED_BUILDS`, we can:
566
586
  * 1. detect which packages were ignored,
567
- * 2. interactively ask the user whether to approve them, and
568
- * 3. run `pnpm approve-builds` followed by a retry of the original command.
587
+ * 2. approve them (interactively or automatically),
588
+ * 3. clean-reinstall and retry — repeating if pnpm reports further ignored
589
+ * packages (pnpm does not always list every unapproved package at once).
569
590
  */
570
591
  async function runPackageManagerCommand(
571
592
  pm: PackageManager,
@@ -573,26 +594,48 @@ async function runPackageManagerCommand(
573
594
  projectDir: string,
574
595
  label: string,
575
596
  ): Promise<void> {
576
- const { code, output } = await spawnAndCapture(pm, args, projectDir, pm === 'pnpm');
597
+ let { code, output } = await spawnAndCapture(pm, args, projectDir, pm === 'pnpm');
577
598
 
578
599
  if (code === 0) return;
579
600
 
580
601
  if (pm === 'pnpm') {
581
- const ignoredBuilds = parseIgnoredBuilds(output);
582
- if (ignoredBuilds.length > 0) {
602
+ for (let attempt = 0; attempt < 3; attempt++) {
603
+ const ignoredBuilds = parseIgnoredBuilds(output);
604
+ if (ignoredBuilds.length === 0) break;
583
605
  const approved = await maybeApproveBuilds(projectDir, ignoredBuilds);
584
- if (approved) {
585
- // Retry the original command now that build scripts are approved.
586
- const retry = await spawnAndCapture(pm, args, projectDir, true);
587
- if (retry.code === 0) return;
588
- throw new Error(`${label} exited with code ${retry.code} after approving builds`);
589
- }
606
+ if (!approved) break;
607
+ // 中断された install はパッケージ抽出が不完全なまま "Already up to date"
608
+ // と判定されることがあるため、node_modules を消して決定論的に入れ直す
609
+ removeWorkspaceNodeModules(projectDir);
610
+ const retry = await spawnAndCapture(pm, args, projectDir, true);
611
+ code = retry.code;
612
+ output = retry.output;
613
+ if (code === 0) return;
614
+ }
615
+ if (parseIgnoredBuilds(output).length > 0) {
616
+ throw new Error(
617
+ `${label} exited with code ${code}: pnpm still reports unapproved build scripts. ` +
618
+ 'Run "pnpm approve-builds" inside the project, then re-run the command.'
619
+ );
590
620
  }
591
621
  }
592
622
 
593
623
  throw new Error(`${label} exited with code ${code}`);
594
624
  }
595
625
 
626
+ /** workspace root と直下パッケージの node_modules を削除する(クリーン再インストール用)。 */
627
+ function removeWorkspaceNodeModules(projectDir: string): void {
628
+ const targets = [projectDir, ...fs.readdirSync(projectDir, { withFileTypes: true })
629
+ .filter((entry) => entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.'))
630
+ .map((entry) => path.join(projectDir, entry.name))];
631
+ for (const dir of targets) {
632
+ const nodeModules = path.join(dir, 'node_modules');
633
+ if (fs.existsSync(nodeModules)) {
634
+ fs.rmSync(nodeModules, { recursive: true, force: true });
635
+ }
636
+ }
637
+ }
638
+
596
639
  /**
597
640
  * Spawn a child process inheriting stdin (so interactive prompts still work)
598
641
  * while either inheriting or capturing+teeing stdout/stderr.
@@ -651,6 +694,10 @@ export function parseIgnoredBuilds(output: string): string[] {
651
694
  * Prompt the user and, if approved, run `pnpm approve-builds` followed by
652
695
  * `pnpm rebuild <packages>`. Returns true if the user approved (regardless of
653
696
  * which packages they actually selected inside approve-builds).
697
+ *
698
+ * In non-interactive environments (CI, coding agents, piped output) prompting
699
+ * would hang forever, so build scripts are approved automatically via
700
+ * package.json `pnpm.onlyBuiltDependencies` instead.
654
701
  */
655
702
  async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]): Promise<boolean> {
656
703
  console.log(
@@ -658,6 +705,18 @@ async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]):
658
705
  ' These packages (e.g. sharp) need their build scripts to run correctly.\n',
659
706
  );
660
707
 
708
+ const interactive =
709
+ process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
710
+ if (!interactive) {
711
+ console.log(
712
+ 'ℹ️ Non-interactive environment detected — approving build scripts automatically\n' +
713
+ ' via "allowBuilds" in pnpm-workspace.yaml.\n',
714
+ );
715
+ // rebuild は不要: 呼び出し側がクリーン再インストールで build script を実行する
716
+ approveBuildsViaWorkspaceYaml(projectDir, ignoredBuilds);
717
+ return true;
718
+ }
719
+
661
720
  const response = await prompts({
662
721
  type: 'confirm',
663
722
  name: 'approve',
@@ -679,6 +738,43 @@ async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]):
679
738
  return true;
680
739
  }
681
740
 
741
+ /**
742
+ * pnpm-workspace.yaml の allowBuilds にパッケージを true で登録して build script を許可する。
743
+ * (pnpm 11+ の正準設定。失敗時に pnpm が追記する placeholder 行も true に置き換える)
744
+ */
745
+ export function approveBuildsViaWorkspaceYaml(projectDir: string, packages: string[]): void {
746
+ const workspaceYamlPath = path.join(projectDir, 'pnpm-workspace.yaml');
747
+ const existing = fs.existsSync(workspaceYamlPath)
748
+ ? fs.readFileSync(workspaceYamlPath, 'utf-8')
749
+ : '';
750
+ const yamlKey = (pkg: string) => (/^[A-Za-z0-9_.-]+$/.test(pkg) ? pkg : `'${pkg}'`);
751
+
752
+ const lines = existing.length > 0 ? existing.split(/\r?\n/) : [];
753
+ const keyIndex = lines.findIndex((line) => /^allowBuilds\s*:/.test(line));
754
+
755
+ if (keyIndex === -1) {
756
+ const block = `allowBuilds:\n${packages.map((pkg) => ` ${yamlKey(pkg)}: true`).join('\n')}\n`;
757
+ const base = existing.length > 0 && !existing.endsWith('\n') ? `${existing}\n` : existing;
758
+ fs.writeFileSync(workspaceYamlPath, `${base}${block}`, 'utf-8');
759
+ return;
760
+ }
761
+
762
+ // 既存マップ内の対象パッケージ(placeholder 含む)を true に更新し、無いものは追記する
763
+ let endIndex = keyIndex + 1;
764
+ const updated = new Set<string>();
765
+ while (endIndex < lines.length && /^\s+\S/.test(lines[endIndex])) {
766
+ const entry = lines[endIndex].match(/^\s+['"]?([A-Za-z0-9@/_.-]+)['"]?\s*:/);
767
+ if (entry && packages.includes(entry[1])) {
768
+ lines[endIndex] = ` ${yamlKey(entry[1])}: true`;
769
+ updated.add(entry[1]);
770
+ }
771
+ endIndex++;
772
+ }
773
+ const additions = packages.filter((pkg) => !updated.has(pkg)).map((pkg) => ` ${yamlKey(pkg)}: true`);
774
+ lines.splice(endIndex, 0, ...additions);
775
+ fs.writeFileSync(workspaceYamlPath, lines.join('\n'), 'utf-8');
776
+ }
777
+
682
778
  function runSimple(command: string, args: string[], cwd: string): Promise<void> {
683
779
  return new Promise((resolve, reject) => {
684
780
  const child = spawn(command, args, { cwd, stdio: 'inherit', shell: true });
@@ -946,7 +1042,7 @@ function getFunctionsKeyHeaders(functionsBaseUrl: string): Record<string, string
946
1042
  async function request<T>(
947
1043
  endpoint: string,
948
1044
  method: 'GET' | 'POST' | 'PUT' | 'DELETE',
949
- body?: any,
1045
+ body?: unknown,
950
1046
  queryParams?: Record<string, string>
951
1047
  ): Promise<T> {
952
1048
  const functionsBaseUrl = getFunctionsBaseUrl();
@@ -1018,14 +1114,14 @@ export const api = {
1018
1114
  /**
1019
1115
  * Make a POST request
1020
1116
  */
1021
- post: <T>(endpoint: string, body?: any): Promise<T> => {
1117
+ post: <T>(endpoint: string, body?: unknown): Promise<T> => {
1022
1118
  return request<T>(endpoint, 'POST', body);
1023
1119
  },
1024
1120
 
1025
1121
  /**
1026
1122
  * Make a PUT request
1027
1123
  */
1028
- put: <T>(endpoint: string, body?: any): Promise<T> => {
1124
+ put: <T>(endpoint: string, body?: unknown): Promise<T> => {
1029
1125
  return request<T>(endpoint, 'PUT', body);
1030
1126
  },
1031
1127
 
@@ -1086,7 +1182,7 @@ export async function register() {
1086
1182
  const originalConsoleError = console.error;
1087
1183
  const originalConsoleWarn = console.warn;
1088
1184
 
1089
- console.log = function(...args: any[]) {
1185
+ console.log = function(...args: unknown[]) {
1090
1186
  originalConsoleLog.apply(console, args);
1091
1187
  const message = args.map(arg =>
1092
1188
  typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
@@ -1097,7 +1193,7 @@ export async function register() {
1097
1193
  });
1098
1194
  };
1099
1195
 
1100
- console.error = function(...args: any[]) {
1196
+ console.error = function(...args: unknown[]) {
1101
1197
  originalConsoleError.apply(console, args);
1102
1198
  const message = args.map(arg =>
1103
1199
  typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
@@ -1108,7 +1204,7 @@ export async function register() {
1108
1204
  });
1109
1205
  };
1110
1206
 
1111
- console.warn = function(...args: any[]) {
1207
+ console.warn = function(...args: unknown[]) {
1112
1208
  originalConsoleWarn.apply(console, args);
1113
1209
  const message = args.map(arg =>
1114
1210
  typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
@@ -2069,18 +2165,66 @@ ${functionsStructureLine}
2069
2165
  └── .github/workflows/ # CI/CD workflows (if configured)
2070
2166
  \`\`\`
2071
2167
 
2168
+ ## Setup & Everyday Commands
2169
+
2170
+ \`\`\`bash
2171
+ ${pm} install # install dependencies
2172
+ ${runCmd} swallowkit dev # Next.js (3000) + Azure Functions (7071)
2173
+ ${pm} run build # production build
2174
+ ${pm} run lint # ESLint (generated code must stay error-free)
2175
+ ${runCmd} swallowkit verify # structure / drift / typecheck (exit 1 on failure)
2176
+ \`\`\`
2177
+
2178
+ Run \`${runCmd} swallowkit verify\` (or \`machine verify project\`) before finishing any task.
2179
+
2072
2180
  ## SwallowKit MCP / Machine Workflow
2073
2181
 
2074
2182
  - This repository includes a project-scoped \`.mcp.json\` file that resolves and starts the latest SwallowKit MCP server on each launch. Set \`SWALLOWKIT_MCP_VERSION\` in that file to pin a specific version.
2075
2183
  - Prefer the \`swallowkit_*\` MCP tools for framework-owned inspection, validation, and generation when they are available.
2076
2184
  - If MCP is unavailable in your runtime, fall back to the machine CLI:
2077
2185
  - \`${runCmd} swallowkit machine inspect project\`
2186
+ - \`${runCmd} swallowkit machine inspect boundaries\` — responsibility boundary contract (which files you may edit freely)
2078
2187
  - \`${runCmd} swallowkit machine validate project\`
2079
- - \`${runCmd} swallowkit machine generate scaffold <name> --api-only\`
2188
+ - \`${runCmd} swallowkit machine plan scaffold <name>\` → \`apply scaffold --plan <planId>\` — safe two-phase generation
2189
+ - \`${runCmd} swallowkit machine verify project\` → \`explain failure\` — verification loop
2080
2190
  - Do not hand-edit framework-owned artifacts when the MCP or machine interface can generate or validate them for you.
2081
2191
  - The MCP bootstrap uses ${pm} and requires network access when the selected version is not cached.
2082
2192
  - **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
2083
2193
 
2194
+ ## Autonomous Loop (Plan / Apply / Verify)
2195
+
2196
+ Machine commands return a \`status\` terminal state (\`complete\` / \`in-progress\` / \`blocked\` / \`requires-human\` / \`failed\`) and \`nextActions\`. Standard loop:
2197
+
2198
+ 1. \`plan scaffold <model>\` — compute changes without writing (get \`planId\`)
2199
+ 2. \`apply scaffold --plan <planId>\` — apply with freshness + approval checks
2200
+ 3. \`verify project\` — structure / drift / typecheck (and project-specific checks)
2201
+ 4. \`explain failure\` — evidence and repair actions when verification fails
2202
+
2203
+ Step-by-step runbooks live in \`.swallowkit/workflows/\` (agent-agnostic Markdown):
2204
+
2205
+ - \`.swallowkit/workflows/add-model.md\`
2206
+ - \`.swallowkit/workflows/modify-model.md\`
2207
+ - \`.swallowkit/workflows/verify-and-repair.md\`
2208
+ - \`.swallowkit/workflows/provision.md\`
2209
+
2210
+ The same runbooks are installed as **Agent Skills** ([agentskills.io](https://agentskills.io/) open standard) under \`.github/skills/\`:
2211
+
2212
+ | Skill | Use when |
2213
+ |-------|----------|
2214
+ | \`swallowkit-add-model\` | adding a new model / entity / CRUD feature |
2215
+ | \`swallowkit-modify-model\` | changing an existing schema and re-aligning artifacts |
2216
+ | \`swallowkit-verify-repair\` | converging to a verified state after any change |
2217
+ | \`swallowkit-provision\` | provisioning Azure infrastructure (human approval required) |
2218
+
2219
+ Skills-aware agents (GitHub Copilot in VS Code / CLI / cloud agent, and other agents supporting the standard) discover these automatically from their \`name\`/\`description\` and load the body on demand. If your agent does not support skills, read the equivalent runbook in \`.swallowkit/workflows/\` before performing these tasks.
2220
+
2221
+ ## Responsibility Boundary (AI × Deterministic Generation)
2222
+
2223
+ - **ai-authored (write freely)**: \`shared/models/\`, business logic, custom pages/components, tests.
2224
+ - **deterministic (never hand-edit)**: artifacts recorded in \`.swallowkit/artifacts.json\` with \`managed\` ownership, and \`.swallowkit/\` metadata. Change the model/config and regenerate via plan/apply instead.
2225
+ - **shared (edit outside markers)**: \`infra/main.bicep\`, \`functions/function_app.py\`, \`shared/index.ts\`.
2226
+ - Full machine-readable contract: \`${runCmd} swallowkit machine inspect boundaries\`
2227
+
2084
2228
  ## Critical Design Principles
2085
2229
 
2086
2230
  ### 1. Next.js API Routes Are Strictly a BFF (Backend for Frontend)
@@ -2191,11 +2335,12 @@ app.http('{model}-get-all', {
2191
2335
  | Cosmos DB partition key | \`/id\` (default) | Custom: \`export const partitionKey = '/field'\` |
2192
2336
  | Bicep container file | \`infra/containers/{kebab-case}-container.bicep\` | \`infra/containers/todo-container.bicep\` |
2193
2337
 
2194
- ## Adding New Models (SwallowKit CLI Skills)
2338
+ ## Adding New Models (SwallowKit CLI)
2195
2339
 
2196
2340
  Use the SwallowKit CLI — do **not** manually create model files or CRUD boilerplate.
2341
+ For autonomous agents, prefer the plan/apply loop above (or the \`swallowkit-add-model\` skill); the commands below are the human-friendly equivalents.
2197
2342
 
2198
- ### Skill: Create a new data model
2343
+ ### Create a new data model
2199
2344
 
2200
2345
  \`\`\`bash
2201
2346
  ${runCmd} swallowkit create-model <name>
@@ -2206,7 +2351,7 @@ ${runCmd} swallowkit create-model user post comment
2206
2351
  Creates \`shared/models/<name>.ts\` with a Zod schema template including \`id\`, \`createdAt\`, \`updatedAt\`.
2207
2352
  Edit the generated file to add your domain-specific fields, then run scaffold.
2208
2353
 
2209
- ### Skill: Generate full CRUD from a model
2354
+ ### Generate full CRUD from a model
2210
2355
 
2211
2356
  \`\`\`bash
2212
2357
  ${runCmd} swallowkit scaffold shared/models/<name>.ts
@@ -2218,7 +2363,7 @@ Generates:
2218
2363
  - UI pages (\`app/<name>/page.tsx\`, detail, create, edit pages)
2219
2364
  - Cosmos DB Bicep container config (\`infra/containers/<name>-container.bicep\`)
2220
2365
 
2221
- ### Skill: Start development servers
2366
+ ### Start development servers
2222
2367
 
2223
2368
  \`\`\`bash
2224
2369
  ${runCmd} swallowkit dev
@@ -2227,7 +2372,7 @@ ${runCmd} swallowkit dev
2227
2372
  Runs Next.js (http://localhost:3000) and Azure Functions (http://localhost:7071) concurrently.
2228
2373
  Checks for Cosmos DB Emulator availability.
2229
2374
 
2230
- ### Skill: Provision Azure resources
2375
+ ### Provision Azure resources
2231
2376
 
2232
2377
  \`\`\`bash
2233
2378
  ${runCmd} swallowkit provision --resource-group <name> --location <region>
@@ -2287,6 +2432,9 @@ This file is for Claude Code. Read AGENTS.md in the project root for the full ar
2287
2432
  - This repository includes a project-scoped \`.mcp.json\` that resolves and starts the latest SwallowKit MCP server on each launch. Set \`SWALLOWKIT_MCP_VERSION\` in that file to pin a specific version.
2288
2433
  - When the \`swallowkit_*\` tools are available, prefer them for inspect / validate / generate tasks.
2289
2434
  - If MCP is unavailable, use \`${runCmd} swallowkit machine ...\` instead.
2435
+ - For generation, prefer the two-phase flow: \`plan scaffold <name>\` → \`apply scaffold --plan <planId>\` → \`verify project\`. Runbooks: \`.swallowkit/workflows/\`.
2436
+ - Agent Skills (agentskills.io) for the same workflows live in \`.github/skills/\` (\`swallowkit-add-model\`, \`swallowkit-modify-model\`, \`swallowkit-verify-repair\`, \`swallowkit-provision\`). If your runtime does not auto-discover them, read the relevant \`SKILL.md\` before performing these tasks.
2437
+ - Boundary contract (what you may edit freely vs what SwallowKit regenerates): \`${runCmd} swallowkit machine inspect boundaries\`
2290
2438
  - **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
2291
2439
 
2292
2440
  ## SwallowKit CLI Commands
@@ -2340,7 +2488,9 @@ Frontend (Next.js App Router) → BFF (Next.js API Routes) → Backend (Azure Fu
2340
2488
 
2341
2489
  - Prefer the SwallowKit MCP or machine interface for framework-owned inspection, validation, and generation instead of hand-editing generated files.
2342
2490
  - If your runtime loads project-scoped MCP config from \`.mcp.json\`, use the \`swallowkit_*\` tools.
2343
- - Otherwise use \`${runCmd} swallowkit machine inspect project\`, \`${runCmd} swallowkit machine validate project\`, and \`${runCmd} swallowkit machine generate scaffold <name> --api-only\`.
2491
+ - Otherwise use \`${runCmd} swallowkit machine inspect project\`, \`${runCmd} swallowkit machine validate project\`, and the two-phase flow \`${runCmd} swallowkit machine plan scaffold <name>\` → \`apply scaffold --plan <planId>\` → \`verify project\`.
2492
+ - Agent Skills in \`.github/skills/\` (\`swallowkit-add-model\`, \`swallowkit-modify-model\`, \`swallowkit-verify-repair\`, \`swallowkit-provision\`) cover these workflows — load them when the task matches.
2493
+ - Boundary contract: \`${runCmd} swallowkit machine inspect boundaries\` tells you which files are free to edit and which are regenerated. Runbooks live in \`.swallowkit/workflows/\`.
2344
2494
  - **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
2345
2495
 
2346
2496
  ## Naming
@@ -2476,6 +2626,17 @@ app.http('{model}-get-all', {
2476
2626
  console.log(' - bff-routes.instructions.md');
2477
2627
  console.log(' - azure-functions.instructions.md');
2478
2628
 
2629
+ // ── 5. .swallowkit/workflows/*.md (agent-agnostic runbooks) ────────
2630
+ writeWorkflowDocs(projectDir, runCmd);
2631
+ console.log(' ✅ .swallowkit/workflows/ (agent-agnostic autonomous-loop runbooks)');
2632
+
2633
+ // ── 6. .github/skills/<name>/SKILL.md (Agent Skills, agentskills.io) ─
2634
+ const skillPaths = writeAgentSkills(projectDir, runCmd);
2635
+ console.log(' ✅ .github/skills/ (Agent Skills — agentskills.io open standard)');
2636
+ for (const skillPath of skillPaths) {
2637
+ console.log(` - ${skillPath}`);
2638
+ }
2639
+
2479
2640
  console.log('\n✅ AI agent files created\n');
2480
2641
  console.log(' Supported agents:');
2481
2642
  console.log(' - OpenAI Codex → AGENTS.md');
@@ -2483,6 +2644,7 @@ app.http('{model}-get-all', {
2483
2644
  console.log(' - Project MCP runtimes → .mcp.json');
2484
2645
  console.log(' - GitHub Copilot → .github/copilot-instructions.md');
2485
2646
  console.log(' - GitHub Copilot (edit) → .github/instructions/*.instructions.md');
2647
+ console.log(' - Skills-aware agents → .github/skills/*/SKILL.md');
2486
2648
  console.log('');
2487
2649
  }
2488
2650