stageflow 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (501) hide show
  1. package/README.md +10 -3
  2. package/dist/a2a/contracts.d.ts +1 -0
  3. package/dist/a2a/contracts.js +1 -0
  4. package/dist/a2a/registry.d.ts +2 -0
  5. package/dist/a2a/registry.js +20 -1
  6. package/dist/a2a/server.d.ts +7 -0
  7. package/dist/a2a/server.js +5 -2
  8. package/dist/a2a/service.d.ts +1 -1
  9. package/dist/a2a/service.js +57 -8
  10. package/dist/a2a/store.d.ts +8 -5
  11. package/dist/a2a/store.js +24 -67
  12. package/dist/agent/activity.d.ts +3 -0
  13. package/dist/agent/bootProviderConfig.d.ts +21 -0
  14. package/dist/agent/bootProviderConfig.js +74 -0
  15. package/dist/agent/piAdapter.d.ts +9 -1
  16. package/dist/agent/piAdapter.js +58 -3
  17. package/dist/agent/piIsolatedMcp.d.ts +2 -0
  18. package/dist/agent/piIsolatedMcp.js +10 -2
  19. package/dist/agent/port.d.ts +6 -0
  20. package/dist/agent/streamLogRedact.d.ts +1 -1
  21. package/dist/agent/streamLogRedact.js +4 -11
  22. package/dist/cli/artifactCommand.js +9 -16
  23. package/dist/cli/backupCommand.d.ts +9 -0
  24. package/dist/cli/backupCommand.js +111 -0
  25. package/dist/cli/debugRunCommand.d.ts +10 -0
  26. package/dist/cli/debugRunCommand.js +109 -0
  27. package/dist/cli/doctorCommand.d.ts +32 -0
  28. package/dist/cli/doctorCommand.js +453 -0
  29. package/dist/cli/envelopeCommand.js +9 -2
  30. package/dist/cli/exportAllCommand.d.ts +55 -0
  31. package/dist/cli/exportAllCommand.js +218 -0
  32. package/dist/cli/exportRunCommand.js +23 -21
  33. package/dist/cli/hostClient.d.ts +21 -3
  34. package/dist/cli/hostClient.js +93 -12
  35. package/dist/cli/initTemplates.d.ts +1 -1
  36. package/dist/cli/initTemplates.js +8 -1
  37. package/dist/cli/resolveSafeOutPath.d.ts +2 -0
  38. package/dist/cli/resolveSafeOutPath.js +40 -0
  39. package/dist/cli/restoreCommand.d.ts +10 -0
  40. package/dist/cli/restoreCommand.js +90 -0
  41. package/dist/cli/runCommand.d.ts +3 -2
  42. package/dist/cli/runCommand.js +93 -11
  43. package/dist/cli/runOutput.d.ts +4 -0
  44. package/dist/cli/runOutput.js +33 -7
  45. package/dist/cli/runStageCommand.d.ts +1 -0
  46. package/dist/cli/runStageCommand.js +44 -25
  47. package/dist/cli/runsCommand.d.ts +1 -1
  48. package/dist/cli/runsCommand.js +162 -8
  49. package/dist/cli.js +171 -30
  50. package/dist/config/catalogRelativePath.d.ts +62 -0
  51. package/dist/config/catalogRelativePath.js +118 -0
  52. package/dist/config/configOrigin.d.ts +27 -0
  53. package/dist/config/configOrigin.js +59 -0
  54. package/dist/config/hostConfig.d.ts +55 -0
  55. package/dist/config/hostConfig.js +333 -0
  56. package/dist/config/listSkills.d.ts +26 -0
  57. package/dist/config/listSkills.js +190 -3
  58. package/dist/config/loadOutcome.d.ts +1 -1
  59. package/dist/config/loadPipeline.js +23 -2
  60. package/dist/config/loadStage.js +18 -0
  61. package/dist/config/loadTask.d.ts +2 -0
  62. package/dist/config/loadTask.js +57 -18
  63. package/dist/config/materializeStageModels.js +5 -1
  64. package/dist/config/mergePipelineIncludes.d.ts +3 -0
  65. package/dist/config/mergePipelineIncludes.js +19 -0
  66. package/dist/config/migrateYaml.js +6 -11
  67. package/dist/config/multiProjectCatalog.d.ts +30 -0
  68. package/dist/config/multiProjectCatalog.js +142 -0
  69. package/dist/config/normalizePipelineStageEntry.js +20 -1
  70. package/dist/config/pipelineStageKeys.js +2 -0
  71. package/dist/config/resolveCatalogRoots.d.ts +27 -0
  72. package/dist/config/resolveCatalogRoots.js +76 -0
  73. package/dist/config/resolveModel.d.ts +7 -1
  74. package/dist/config/resolveModel.js +11 -1
  75. package/dist/config/resolveStageMcpServers.d.ts +9 -1
  76. package/dist/config/resolveStageMcpServers.js +36 -9
  77. package/dist/config/secretFromEnvOrFile.d.ts +9 -0
  78. package/dist/config/secretFromEnvOrFile.js +34 -0
  79. package/dist/config/seededCatalog.d.ts +11 -0
  80. package/dist/config/seededCatalog.js +29 -0
  81. package/dist/config/toolRequires.d.ts +24 -0
  82. package/dist/config/toolRequires.js +115 -0
  83. package/dist/config/validateCatalog.d.ts +5 -1
  84. package/dist/config/validateCatalog.js +140 -1
  85. package/dist/diagnostics/checks.d.ts +39 -0
  86. package/dist/diagnostics/checks.js +135 -0
  87. package/dist/errors/codes.d.ts +14 -0
  88. package/dist/errors/codes.js +59 -0
  89. package/dist/git/cache.d.ts +14 -0
  90. package/dist/git/cache.js +150 -0
  91. package/dist/git/credentials.d.ts +9 -0
  92. package/dist/git/credentials.js +88 -0
  93. package/dist/git/errors.d.ts +20 -0
  94. package/dist/git/errors.js +94 -0
  95. package/dist/git/exec.d.ts +16 -0
  96. package/dist/git/exec.js +135 -0
  97. package/dist/git/operations.d.ts +29 -0
  98. package/dist/git/operations.js +153 -0
  99. package/dist/git/version.d.ts +1 -0
  100. package/dist/git/version.js +10 -0
  101. package/dist/logging/audit.d.ts +16 -0
  102. package/dist/logging/audit.js +19 -0
  103. package/dist/logging/commonWords.d.ts +2 -0
  104. package/dist/logging/commonWords.js +13 -0
  105. package/dist/logging/logger.d.ts +49 -0
  106. package/dist/logging/logger.js +193 -0
  107. package/dist/logging/namedSecrets.d.ts +6 -0
  108. package/dist/logging/namedSecrets.js +58 -0
  109. package/dist/logging/redact.d.ts +13 -0
  110. package/dist/logging/redact.js +88 -0
  111. package/dist/mcp/catalogTools.js +456 -80
  112. package/dist/mcp/checkoutTools.d.ts +52 -0
  113. package/dist/mcp/checkoutTools.js +332 -0
  114. package/dist/mcp/controlTools.js +179 -5
  115. package/dist/mcp/deps.d.ts +1 -0
  116. package/dist/mcp/getStartedTool.d.ts +3 -0
  117. package/dist/mcp/getStartedTool.js +62 -0
  118. package/dist/mcp/readArtifact.d.ts +11 -0
  119. package/dist/mcp/readArtifact.js +46 -30
  120. package/dist/mcp/server.js +1 -0
  121. package/dist/mcp/tools.js +4 -0
  122. package/dist/net/proxy.d.ts +14 -0
  123. package/dist/net/proxy.js +78 -0
  124. package/dist/package-meta.d.ts +2 -1
  125. package/dist/package-meta.js +2 -1
  126. package/dist/preflight/bash.d.ts +8 -0
  127. package/dist/preflight/bash.js +34 -0
  128. package/dist/preflight/claudeRoot.d.ts +11 -0
  129. package/dist/preflight/claudeRoot.js +23 -0
  130. package/dist/preflight/mcpCommands.d.ts +8 -0
  131. package/dist/preflight/mcpCommands.js +36 -0
  132. package/dist/preflight/pipelinePreflight.d.ts +40 -0
  133. package/dist/preflight/pipelinePreflight.js +192 -0
  134. package/dist/preflight/tls.d.ts +6 -0
  135. package/dist/preflight/tls.js +18 -0
  136. package/dist/preflight/toolchain.d.ts +45 -0
  137. package/dist/preflight/toolchain.js +219 -0
  138. package/dist/project/findProjectRoot.js +3 -4
  139. package/dist/project/globalHome.d.ts +7 -0
  140. package/dist/project/globalHome.js +63 -2
  141. package/dist/project/resolveProjectContext.js +2 -2
  142. package/dist/project/resolveStageflowContext.js +2 -2
  143. package/dist/projection/projectRun.d.ts +2 -1
  144. package/dist/projection/projectRun.js +1 -0
  145. package/dist/runstore/assertTmpdir.d.ts +1 -0
  146. package/dist/runstore/assertTmpdir.js +21 -0
  147. package/dist/runstore/backup.d.ts +52 -0
  148. package/dist/runstore/backup.js +292 -0
  149. package/dist/runstore/createStore.d.ts +18 -1
  150. package/dist/runstore/createStore.js +64 -5
  151. package/dist/runstore/debugBundle.d.ts +60 -0
  152. package/dist/runstore/debugBundle.js +143 -0
  153. package/dist/runstore/diskUsage.d.ts +50 -0
  154. package/dist/runstore/diskUsage.js +214 -0
  155. package/dist/runstore/exportRunPayload.d.ts +8 -0
  156. package/dist/runstore/exportRunPayload.js +23 -0
  157. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  158. package/dist/runstore/normalizeCatalogPath.js +10 -0
  159. package/dist/runstore/paths.d.ts +5 -0
  160. package/dist/runstore/paths.js +145 -1
  161. package/dist/runstore/port.d.ts +111 -13
  162. package/dist/runstore/port.js +8 -1
  163. package/dist/runstore/restore.d.ts +81 -0
  164. package/dist/runstore/restore.js +355 -0
  165. package/dist/runstore/retention.d.ts +27 -0
  166. package/dist/runstore/retention.js +74 -0
  167. package/dist/runstore/runManifest.d.ts +146 -0
  168. package/dist/runstore/runManifest.js +288 -0
  169. package/dist/runstore/runProjection.d.ts +3 -1
  170. package/dist/runstore/runProjection.js +63 -1
  171. package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -3
  172. package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
  173. package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
  174. package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
  175. package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
  176. package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
  177. package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
  178. package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
  179. package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
  180. package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
  181. package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
  182. package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
  183. package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
  184. package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
  185. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
  186. package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
  187. package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
  188. package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
  189. package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
  190. package/dist/runstore/sqlite/migrations/index.js +72 -0
  191. package/dist/runstore/sqlite/schema.d.ts +20 -1
  192. package/dist/runstore/sqlite/schema.js +277 -1
  193. package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
  194. package/dist/runstore/sqlite/storeOpenError.js +11 -0
  195. package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
  196. package/dist/runstore/sqlite/storeSchemaError.js +8 -0
  197. package/dist/runstore/stageExecution.js +3 -0
  198. package/dist/runstore/storeFilesystem.d.ts +32 -0
  199. package/dist/runstore/storeFilesystem.js +148 -0
  200. package/dist/runstore/trackProjection.js +2 -0
  201. package/dist/runstore/workspaceLayout.d.ts +13 -0
  202. package/dist/runstore/workspaceLayout.js +76 -0
  203. package/dist/runtime/completionCheckRunner.d.ts +3 -0
  204. package/dist/runtime/completionCheckRunner.js +45 -7
  205. package/dist/runtime/containerLimits.d.ts +16 -0
  206. package/dist/runtime/containerLimits.js +84 -0
  207. package/dist/runtime/credentialMaterialisation.d.ts +28 -0
  208. package/dist/runtime/credentialMaterialisation.js +128 -0
  209. package/dist/runtime/gitCheckoutCapability.js +7 -13
  210. package/dist/runtime/pipelineRunner.d.ts +36 -1
  211. package/dist/runtime/pipelineRunner.js +178 -17
  212. package/dist/runtime/pipelineScheduler.d.ts +15 -0
  213. package/dist/runtime/pipelineScheduler.js +135 -27
  214. package/dist/runtime/reloadRunCatalog.js +6 -1
  215. package/dist/runtime/repositoryMaterialize.d.ts +47 -0
  216. package/dist/runtime/repositoryMaterialize.js +235 -0
  217. package/dist/runtime/resumeTimedOut.d.ts +1 -1
  218. package/dist/runtime/resumeTimedOut.js +5 -2
  219. package/dist/runtime/runChangeBus.js +9 -0
  220. package/dist/runtime/runDeletion.d.ts +7 -0
  221. package/dist/runtime/runDeletion.js +37 -0
  222. package/dist/runtime/runManager.d.ts +158 -4
  223. package/dist/runtime/runManager.js +1596 -79
  224. package/dist/runtime/runRetentionSweep.d.ts +31 -0
  225. package/dist/runtime/runRetentionSweep.js +328 -0
  226. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  227. package/dist/runtime/runRetryCoordinator.js +19 -2
  228. package/dist/runtime/runSkills.d.ts +40 -0
  229. package/dist/runtime/runSkills.js +173 -0
  230. package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
  231. package/dist/runtime/stageAttemptBootstrap.js +195 -24
  232. package/dist/runtime/stageCacheEnv.d.ts +6 -0
  233. package/dist/runtime/stageCacheEnv.js +34 -0
  234. package/dist/runtime/stageConcurrency.d.ts +2 -1
  235. package/dist/runtime/stageConcurrency.js +4 -2
  236. package/dist/runtime/stageEnvironment.d.ts +38 -0
  237. package/dist/runtime/stageEnvironment.js +193 -0
  238. package/dist/runtime/stageProcessLauncher.d.ts +18 -0
  239. package/dist/runtime/stageProcessLauncher.js +194 -38
  240. package/dist/runtime/stageRecovery.d.ts +3 -1
  241. package/dist/runtime/stageRecovery.js +19 -4
  242. package/dist/runtime/stageRoots.d.ts +38 -1
  243. package/dist/runtime/stageRoots.js +118 -0
  244. package/dist/runtime/stageRunner.d.ts +1 -0
  245. package/dist/runtime/stageRunner.js +3 -1
  246. package/dist/runtime/stageSecretDecl.d.ts +9 -0
  247. package/dist/runtime/stageSecretDecl.js +102 -0
  248. package/dist/runtime/stageSecrets.d.ts +40 -0
  249. package/dist/runtime/stageSecrets.js +181 -0
  250. package/dist/runtime/stageWorker.d.ts +3 -2
  251. package/dist/runtime/stageWorker.js +58 -10
  252. package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
  253. package/dist/runtime/stageWorkerProtocol.js +8 -0
  254. package/dist/runtime/startPayload.d.ts +32 -0
  255. package/dist/runtime/startPayload.js +59 -0
  256. package/dist/runtime/taskInput.js +14 -5
  257. package/dist/runtime/verifiedStageExecution.d.ts +1 -0
  258. package/dist/runtime/verifiedStageExecution.js +2 -1
  259. package/dist/runtime/workspaceBinding.d.ts +20 -0
  260. package/dist/runtime/workspaceBinding.js +60 -0
  261. package/dist/server/allowedHosts.d.ts +19 -0
  262. package/dist/server/allowedHosts.js +179 -0
  263. package/dist/server/bootstrap.d.ts +36 -2
  264. package/dist/server/bootstrap.js +209 -5
  265. package/dist/server/controlToken.d.ts +47 -0
  266. package/dist/server/controlToken.js +241 -0
  267. package/dist/server/createHttpHost.d.ts +11 -2
  268. package/dist/server/createHttpHost.js +103 -10
  269. package/dist/server/ensureGlobalService.d.ts +5 -1
  270. package/dist/server/ensureGlobalService.js +35 -1
  271. package/dist/server/healthSurfaces.d.ts +6 -0
  272. package/dist/server/healthSurfaces.js +98 -0
  273. package/dist/server/http.d.ts +12 -1
  274. package/dist/server/http.js +1085 -485
  275. package/dist/server/listenHost.d.ts +5 -0
  276. package/dist/server/listenHost.js +56 -0
  277. package/dist/server/mcpHost.d.ts +10 -1
  278. package/dist/server/mcpHost.js +36 -6
  279. package/dist/server/operatorResults.d.ts +2 -2
  280. package/dist/server/operatorResults.js +40 -29
  281. package/dist/server/requestAuthContext.d.ts +12 -0
  282. package/dist/server/requestAuthContext.js +21 -0
  283. package/dist/server/shutdown.d.ts +69 -0
  284. package/dist/server/shutdown.js +219 -0
  285. package/dist/types/pipeline.d.ts +7 -0
  286. package/dist/types/stage.d.ts +8 -0
  287. package/dist/types/task.d.ts +8 -0
  288. package/dist/ui/assets/index-B6hlSXXn.js +120 -0
  289. package/dist/ui/index.html +1 -1
  290. package/examples/README.md +98 -0
  291. package/examples/archify-on-pr/README.md +213 -0
  292. package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
  293. package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
  294. package/examples/archify-on-pr/author-diagrams.yaml +106 -0
  295. package/examples/archify-on-pr/detect-changes.yaml +89 -0
  296. package/examples/ci-validate/README.md +35 -0
  297. package/examples/ci-validate/check.yaml +13 -0
  298. package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
  299. package/examples/ci-validate/validate.sh +5 -0
  300. package/examples/compliance-review-demo/README.md +125 -0
  301. package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
  302. package/examples/compliance-review-demo/connect-account.yaml +47 -0
  303. package/examples/compliance-review-demo/map-to-control.yaml +123 -0
  304. package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
  305. package/examples/compliance-review-demo/publish-report.yaml +79 -0
  306. package/examples/compliance-review-demo/review-verdict.yaml +122 -0
  307. package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
  308. package/examples/compliance-review-demo/store-evidence.yaml +143 -0
  309. package/examples/conditional-fork/README.md +89 -0
  310. package/examples/conditional-fork/branch-a.yaml +13 -0
  311. package/examples/conditional-fork/branch-b.yaml +13 -0
  312. package/examples/conditional-fork/decide.yaml +35 -0
  313. package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
  314. package/examples/conditional-fork/fork-demo.task.yaml +8 -0
  315. package/examples/context7-mcp/README.md +42 -0
  316. package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
  317. package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
  318. package/examples/context7-mcp/fetch-docs.yaml +52 -0
  319. package/examples/context7-mcp/resolve-library.yaml +31 -0
  320. package/examples/context7-mcp/write-brief.yaml +52 -0
  321. package/examples/feature-loop/README.md +104 -0
  322. package/examples/feature-loop/address-feedback.yaml +148 -0
  323. package/examples/feature-loop/align.yaml +116 -0
  324. package/examples/feature-loop/decompose.yaml +86 -0
  325. package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
  326. package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
  327. package/examples/feature-loop/feature-loop.task.yaml +25 -0
  328. package/examples/feature-loop/implement.yaml +128 -0
  329. package/examples/feature-loop/plan.yaml +111 -0
  330. package/examples/feature-loop/publish.yaml +167 -0
  331. package/examples/feature-loop/review.yaml +146 -0
  332. package/examples/feature-loop/verify.yaml +106 -0
  333. package/examples/feedback-loop/README.md +72 -0
  334. package/examples/feedback-loop/VERIFY.md +208 -0
  335. package/examples/feedback-loop/continue-only.task.yaml +4 -0
  336. package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
  337. package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
  338. package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
  339. package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
  340. package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
  341. package/examples/feedback-loop/implement.yaml +14 -0
  342. package/examples/feedback-loop/plan.yaml +14 -0
  343. package/examples/feedback-loop/review.yaml +15 -0
  344. package/examples/feedback-loop/send-back-once.task.yaml +6 -0
  345. package/examples/feedback-loop/submit.yaml +12 -0
  346. package/examples/generic-fan-in/README.md +151 -0
  347. package/examples/generic-fan-in/clarify.yaml +18 -0
  348. package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
  349. package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
  350. package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
  351. package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
  352. package/examples/generic-fan-in/research.yaml +45 -0
  353. package/examples/generic-fan-in/synthesize.yaml +66 -0
  354. package/examples/generic-fan-in/validation.yaml +45 -0
  355. package/examples/github-release/README.md +78 -0
  356. package/examples/github-release/draft-release-notes.yaml +64 -0
  357. package/examples/github-release/github-release.pipeline.yaml +11 -0
  358. package/examples/github-release/github-release.task.yaml +13 -0
  359. package/examples/github-release/publish-github-release.yaml +64 -0
  360. package/examples/hello-world/README.md +28 -0
  361. package/examples/hello-world/hello.pipeline.yaml +4 -0
  362. package/examples/hello-world/my-task.task.yaml +6 -0
  363. package/examples/hello-world/research.yaml +18 -0
  364. package/examples/mcp-hitl-tour/README.md +113 -0
  365. package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
  366. package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
  367. package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
  368. package/examples/mcp-hitl-tour/gather.yaml +31 -0
  369. package/examples/mcp-hitl-tour/intake.yaml +62 -0
  370. package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
  371. package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
  372. package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
  373. package/examples/mcp-hitl-tour/polish.yaml +33 -0
  374. package/examples/mcp-hitl-tour/review.yaml +17 -0
  375. package/examples/mcp-hitl-tour/ship.yaml +25 -0
  376. package/examples/oss-issue-contribution/README.md +218 -0
  377. package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
  378. package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
  379. package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
  380. package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
  381. package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
  382. package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
  383. package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
  384. package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
  385. package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
  386. package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
  387. package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
  388. package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
  389. package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
  390. package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
  391. package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
  392. package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
  393. package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
  394. package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
  395. package/examples/oss-quick-fix/README.md +65 -0
  396. package/examples/oss-quick-fix/implement-fix.yaml +84 -0
  397. package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
  398. package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
  399. package/examples/oss-quick-fix/ship-fix.yaml +81 -0
  400. package/examples/oss-quick-fix/understand-issue.yaml +67 -0
  401. package/examples/oss-quick-fix/verify-fix.yaml +73 -0
  402. package/examples/plan-review/README.md +37 -0
  403. package/examples/plan-review/plan-review-followup.yaml +13 -0
  404. package/examples/plan-review/plan-review.pipeline.yaml +9 -0
  405. package/examples/plan-review/plan-review.task.yaml +9 -0
  406. package/examples/plan-review/plan-review.yaml +25 -0
  407. package/examples/playwright-mcp/README.md +39 -0
  408. package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
  409. package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
  410. package/examples/playwright-mcp/screenshot.yaml +40 -0
  411. package/examples/retry-tour/README.md +75 -0
  412. package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
  413. package/examples/retry-tour/retry-tour.task.yaml +9 -0
  414. package/examples/route-if-tour/README.md +202 -0
  415. package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
  416. package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
  417. package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
  418. package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
  419. package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
  420. package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
  421. package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
  422. package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
  423. package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
  424. package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
  425. package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
  426. package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
  427. package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
  428. package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
  429. package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
  430. package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
  431. package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
  432. package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
  433. package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
  434. package/examples/route-wiring-smoke-test/README.md +377 -0
  435. package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
  436. package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
  437. package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
  438. package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
  439. package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
  440. package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
  441. package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
  442. package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
  443. package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
  444. package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
  445. package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
  446. package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
  447. package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
  448. package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
  449. package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
  450. package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
  451. package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
  452. package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
  453. package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
  454. package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
  455. package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
  456. package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
  457. package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
  458. package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
  459. package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
  460. package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
  461. package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
  462. package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
  463. package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
  464. package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
  465. package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
  466. package/examples/ship-feature/README.md +190 -0
  467. package/examples/ship-feature/feat-address-feedback.yaml +119 -0
  468. package/examples/ship-feature/feat-implement.yaml +180 -0
  469. package/examples/ship-feature/feat-plan.yaml +120 -0
  470. package/examples/ship-feature/feat-review.yaml +109 -0
  471. package/examples/ship-feature/feat-ship.yaml +203 -0
  472. package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
  473. package/examples/ship-feature/ship-feature.task.yaml +78 -0
  474. package/examples/stage-mcp/README.md +144 -0
  475. package/examples/stage-mcp/echo-mcp.mjs +20 -0
  476. package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
  477. package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
  478. package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
  479. package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
  480. package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
  481. package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
  482. package/examples/stage-mcp/use-echo.yaml +20 -0
  483. package/examples/verify-tour/README.md +80 -0
  484. package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
  485. package/examples/verify-tour/verify-tour.task.yaml +11 -0
  486. package/package.json +5 -1
  487. package/skills/stageflow/SKILL.md +6 -6
  488. package/skills/stageflow/references/control-surface.md +11 -5
  489. package/skills/stageflow/scripts/detect-host.mjs +14 -1
  490. package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
  491. package/skills/stageflow-author/SKILL.md +4 -3
  492. package/skills/stageflow-author/references/catalog-mapping.md +16 -0
  493. package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
  494. package/skills/stageflow-run/SKILL.md +20 -12
  495. package/skills/stageflow-run/references/mcp-call.md +9 -1
  496. package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
  497. package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
  498. package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
  499. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
  500. package/skills/stageflow-setup/SKILL.md +40 -8
  501. package/dist/ui/assets/index-Da5EHU6M.js +0 -119
@@ -0,0 +1,377 @@
1
+ # route wiring smoke test
2
+
3
+ Seventeen small, self-contained pipelines that together cover the `route`-based pipeline wiring YAML surface, plus twenty-nine deliberately-invalid ones that each trigger one specific rejection error.
4
+
5
+ - The 17 **valid** ones live directly in this directory and are registered in the repo's `stageflow.yaml` catalog (the directory is listed once; new `*.pipeline.yaml` files dropped in here are picked up automatically), so they show up in `sf ui` / the pipeline picker and are runnable end-to-end with `smoke-test.task.yaml`.
6
+ - The 29 **rejected** ones live in `rejected/` and are excluded from the catalog via `stageflow.yaml`'s `exclude:` list — **they will not show up in the UI on purpose**, so they don't clutter the picker or fail a catalog-wide validate/CI run. Each demonstrates one distinct pipeline-level failure; since a whole pipeline fails to load on its first error, these can't usefully be merged into fewer files without hiding all but one message per file. They're CLI-only, via `sf validate --pipeline <path>`.
7
+
8
+ ## Patterns covered — which pipeline for which feature
9
+
10
+ `route` is declarative wiring. Listed forward `to:` stay on the DAG. After a **succeeded** source, each forward entry is eligible (an entry without `if` fires; `if` match fires; `if` miss **skips** that target — the run can still succeed). Single-parent launch still requires succeeded. `on:` is skip-cascade policy, not launch-from-failed. `if` may be a leaf (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `not_in`) or nested `all` / `any` / `not`. There is no agent `fork_choice` for catalog pipelines, and `route_select` / `allow_none` are rejected.
11
+
12
+ A Join (two or more parents name the same child) waits for *every* parent to become terminal. A false inbound `if` (leaf or `all` / `any` / `not` composition) does **not** skip the child while another parent is still running. After every parent **succeeded**, the child runs only if every inbound edge fired (`if` true, or no `if`); it then opens with every parent's success envelope. If any inbound `if` missed, the child is **skipped** — not pending forever, not opened with a partial envelope set. A failed parent still blocks. Pipelines with **no** forward `if` keep today's Join: skipped sibling + succeeded sibling can still run; all-skipped still force-skip. Mixed skip + a succeeded arm’s `if` miss still runs — the all-fired check is only when every parent succeeded.
13
+
14
+ State-gated routing uses `on:` on the source stage (`succeeded` / `failed`) as skip-cascade policy.
15
+
16
+ | Pipeline ID | File | Demonstrates |
17
+ |---|---|---|
18
+ | `route-demo-core` | `01-core-routing.pipeline.yaml` | The broadest single flow: entry, forward routing, loop (`require_continue`/`resume`), unconditional fan-out from `qa` and `ship`, fan-in join. After qa succeeds, both `ship` and `request-changes` run. After ship succeeds, all three notify stages run. `close` fans in those four parents. |
19
+ | `route-demo-on-gate` | `02-on-gating.pipeline.yaml` | `on: [succeeded]` / `on: [failed]` state-gated routing, declared on the source stage. |
20
+ | `route-demo-two-entries` | `03-two-entry-points.pipeline.yaml` | Multiple independent `entry: true` roots. |
21
+ | `route-demo-entry-false` | `04-entry-false-equivalent-to-omitted.pipeline.yaml` | `entry: false` behaves like omitting the key (code-review fix). |
22
+ | `route-demo-fork-choice` | `05-fork-choice.pipeline.yaml` | Larger unconditional fan-out: `triage` lists two follow-ups; `quick-fix` lists three. All listed `to:` targets run. Overlaps `06` on purpose — a bigger fan-out graph in one file. |
23
+ | `route-demo-fan-out-fan-in` | `06-fan-out-fan-in.pipeline.yaml` | Parallel fan-out (all 3 branches always run) into a join that waits for and combines all 3 real outputs. |
24
+ | `route-demo-loop-human-decision` | `07-loop-human-decision.pipeline.yaml` | The loop config variants `01` doesn't cover: `on_max_replays: wait_for_human` + `replay_session: new_session`. Reliably parks the run waiting for a human decision — exercises the HITL UI flow (`npx tsx src/cli.ts runs answer`), not a bug/stuck state. |
25
+ | `route-demo-skip-and-multi-on` | `08-skip-fallback-and-multi-on-gate.pipeline.yaml` | `decide` fans out to both `risky-step` and `safe-step`. `risky-step` is a leaf. `done` stays only on the safe-step arm (not a join across both). |
26
+ | `route-demo-multi-loop-targets` | `09-multi-loop-targets.pipeline.yaml` | Two *different* stages (`review`, `qa`) each declaring their own loop entry back to the *same* ancestor — `qa` loops to a stage two hops back, not its immediate parent. |
27
+ | `route-demo-uses-dialect-fork` | `10-uses-dialect-fork.pipeline.yaml` | `route`/`entry` combined with the `uses:` external-stage-file dialect — every other pipeline here uses inline `system_prompt`/`model` bodies instead. Both branches always run. |
28
+ | `route-demo-sequential-io` | `11-sequential-io-handoff.pipeline.yaml` | Sequential `io` handoff: parent `draft` `io.output.schema` and child `review` `io.input.schema` share the same object contract (`required: [title]`). `sf validate` is how users see this compatibility check. |
29
+ | `route-demo-complex-io` | `12-complex-io-schemas.pipeline.yaml` | Sequential `io` with pipeline `schemas:` (`finding`, `report`, `analyzed`): nested metadata, array of `$ref` items, enum/pattern/minLength/integer score. `draft → analyze → summarize`; summarize input is a subset (`title`/`summary`/`score` as number). Some `io` sides stay inline (`draft.in`, `summarize.in`/`out`). |
30
+ | `route-demo-ref-io` | `13-ref-io-handoff.pipeline.yaml` | Sequential `io` where **both** every `io.input.schema` and every `io.output.schema` is `$ref: "#/schemas/..."`. `draft.out` and `review.in` share `#/schemas/doc`; `ship.in` is `#/schemas/title-only` (subset of `analyzed`). Unlike `12`, no inline schema sides. |
31
+ | `route-demo-if-eq` | `14-if-eq-gating.pipeline.yaml` | Gated forward `if: { field: severity, op: eq, value: high }` to `page`, plus always-run `notify`. Default prompt emits `severity: low`, so `page` is skipped and the run succeeds. |
32
+ | `route-demo-if-all-gated` | `15-if-all-gated.pipeline.yaml` | Every forward `to:` has `if`. `sf validate` warns `pipeline.route_all_gated` with `ok: true`; `--strict` does not fail. |
33
+ | `route-demo-if-composition` | `16-if-composition.pipeline.yaml` | Nested `not` around `all`, dotted `customer.tier`, and `in`. Default prompt emits a miss, so `page` is skipped and always-run `notify` still runs. |
34
+ | `route-demo-if-join` | `17-if-join.pipeline.yaml` | Two-parent Join gated by inbound `if`s. `write` fires when `ready` is true; `draw` fires when `complete` is true. Default prompts emit both true, so `assemble` runs with both envelopes. Either miss skips `assemble`; the run still succeeds. |
35
+
36
+ ## Important: use the local build, not your global `sf`
37
+
38
+ Your globally-installed `sf` (`/opt/homebrew/bin/sf`, `stageflow@0.1.0`) is a much older release and does not contain this branch's changes — running the bare `sf` command would test the wrong code entirely. Use one of these instead, from the **repository git root**:
39
+
40
+ ```bash
41
+ # no build step, always current — what every command below uses
42
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml --strict
43
+
44
+ # or build once, then use the built CLI directly
45
+ npm run build
46
+ node dist/cli.js validate --pipeline examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml --strict
47
+ ```
48
+
49
+ If you want the bare `sf`/`stageflow` command itself to point at this worktree (e.g. so `sf ui` in a browser tab uses it too), run `npm link` from the repo root once — that swaps your global install for this working copy until you `npm unlink` or reinstall the real global package. That's a machine-wide change, so it's your call whether to do it; the commands below don't need it.
50
+
51
+ `sf validate` never calls a model — it only resolves the pipeline's DAG and runs this project's parsing/validation logic, so every command below is free and instant.
52
+
53
+ ## Valid pipelines (should pass)
54
+
55
+ ```bash
56
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml --strict
57
+ ```
58
+ Expect: **Validation passed.** One pipeline, most of the new surface in one realistic flow:
59
+ `plan -> implement -> review` (review's `route` mixes a normal forward entry to `qa` with a `type: loop` entry back to `implement`, `max_replays: 2`, `on_max_replays: require_continue`, `replay_session: resume`) `-> qa` (fans out to both `ship` and `request-changes`) `-> ship` (fans out to `notify-slack`/`notify-email`/`update-changelog`) `-> close` (fan-in of request-changes plus the three notify stages; all four run on the happy path. The Join waits until every parent is terminal. With no inbound `if`, it runs if at least one succeeded. It stays pending if a parent failed. It does not run if every parent skipped).
60
+
61
+ ```bash
62
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml --strict
63
+ ```
64
+ Expect: **Validation passed.** `run-tests` lists `ship` (default succeeded) and `hotfix` with `on: [failed]`. `on: [failed]` opts hotfix out of skip-cascade when tests fail; hotfix does not launch; launch still needs a succeeded parent. Deterministic branching after success uses `if`.
65
+
66
+ ```bash
67
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml --strict
68
+ ```
69
+ Expect: **Validation passed.** Two independent `entry: true` stages, no wiring between them — a topology the core pipeline can't demonstrate (it only has one root).
70
+
71
+ ```bash
72
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml --strict
73
+ ```
74
+ Expect: **Validation passed.** `draft` explicitly writes `entry: false`; this must behave exactly like omitting the key. This is the code-review fix that closed a bug where `entry: false` used to incorrectly force the whole pipeline into strict entry-stage validation.
75
+
76
+ ```bash
77
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml --strict
78
+ ```
79
+ Expect: **Validation passed.** Unconditional fan-out: `triage` lists `quick-fix` and `big-project` — both always run. `quick-fix` lists `notify-team`/`update-docs`/`schedule-followup` — all three always run. `close` fans in those three notify stages. `big-project` is a leaf.
80
+
81
+ ```bash
82
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml --strict
83
+ ```
84
+ Expect: **Validation passed.** `kickoff`'s `route` list of three targets (`research`/`analysis`/`review-notes`) all fire unconditionally — parallel fan-out, no skipping. `synthesize` is the fan-in join: it waits for and combines all three, every run.
85
+
86
+ ```bash
87
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml --strict
88
+ ```
89
+ Expect: **Validation passed.** The loop config variants `01-core-routing` doesn't exercise: `on_max_replays: wait_for_human` (vs. `require_continue`) and `replay_session: new_session` (vs. `resume`). `review`'s prompt always sends work back to `implement`; with `max_replays: 1`, the second send-back exhausts the budget and parks the run for a human decision instead of failing or looping forever.
90
+
91
+ ```bash
92
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml --strict
93
+ ```
94
+ Expect: **Validation passed.** `decide` lists both `risky-step` and `safe-step`, so both always run. `risky-step` is a leaf. `safe-step` routes to `notify-either-way` on success (the default `on:`), then `done`. `done` is only on that arm, not a join across both.
95
+
96
+ ```bash
97
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml --strict
98
+ ```
99
+ Expect: **Validation passed.** `review` and `qa` each declare their own `type: loop` entry back to `implement`. `review`'s stays dormant (always continues); `qa`'s fires once (sends back on its first attempt, continues on its second) — demonstrating a loop target that isn't the looping stage's immediate parent (`implement` is two hops back from `qa`), and two independent loop points converging on the same ancestor.
100
+
101
+ ```bash
102
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml --strict
103
+ ```
104
+ Expect: **Validation passed.** Same fan-out shape as `05-fork-choice`'s `triage` (both listed branches always run), but every stage body lives in an external file under `stages/` and is loaded via `uses:` instead of inline `system_prompt`/`model` — confirms `route`/`entry` work identically under both stage-body dialects.
105
+
106
+ ```bash
107
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml --strict
108
+ ```
109
+ Expect: **Validation passed.** Parent `draft` `io.output` matches child `review` `io.input` — the same object contract (`required: [title]`). This is the check users see from `sf validate` on sequential (non-clone) edges.
110
+
111
+ ```bash
112
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml --strict
113
+ ```
114
+ Expect: **Validation passed.** Three-stage `draft → analyze → summarize` with pipeline `schemas:` (`finding`, `report`, `analyzed`): nested metadata, array of `$ref` items, enum/pattern/minLength/integer score. `summarize` input is a subset (`title`/`summary`/`score` as number). Some `io` sides stay inline.
115
+
116
+ ```bash
117
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml --strict
118
+ ```
119
+ Expect: **Validation passed.** Every `io.input.schema` and `io.output.schema` is `$ref: "#/schemas/..."`. `draft.out` and `review.in` share `#/schemas/doc`; `ship.in` is `#/schemas/title-only` (subset of `analyzed`). Unlike `12`, both sides of every stage are `$ref`.
120
+
121
+ ```bash
122
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml --strict
123
+ ```
124
+ Expect: **Validation passed.** `triage` routes to `page` only when `severity` equals `high`, and always to `notify`. Mixed gated + always-run siblings do not warn `pipeline.route_all_gated`.
125
+
126
+ ```bash
127
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml --strict --json
128
+ ```
129
+ Expect: **Validation passed** (`ok: true`) with warning `pipeline.route_all_gated`. `--strict` does not promote that warning to an error.
130
+
131
+ ```bash
132
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml --strict
133
+ ```
134
+ Expect: **Validation passed.** `page` is gated by `not` / `all` over `severity` and `customer.tier` `in` `[bronze]`. `notify` always runs. Nested required object paths are legal.
135
+
136
+ ```bash
137
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/17-if-join.pipeline.yaml --strict
138
+ ```
139
+ Expect: **Validation passed.** `write` and `draw` both route to `assemble` with inbound `if`. Default prompts emit `ready: true` and `complete: true`, so the Join child runs with both success envelopes. Change either payload so the predicate misses and `assemble` is skipped (run still succeeds). A false `if` on one parent does not skip `assemble` while the other parent is still running.
140
+
141
+ ## Rejected pipelines (should fail with the given message)
142
+
143
+ ```bash
144
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml --strict
145
+ ```
146
+ Expect: `stage "review": "needs" is no longer supported — declare the wiring on the source stage's "route" instead`
147
+
148
+ ```bash
149
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml --strict
150
+ ```
151
+ Expect: `stage "decide": "fork" is no longer supported — use "route" instead; listed route targets always run`
152
+
153
+ ```bash
154
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml --strict
155
+ ```
156
+ Expect: `stage "review": "feedback_loop" is no longer supported — use a "type: loop" entry inside "route" instead`
157
+
158
+ ```bash
159
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml --strict
160
+ ```
161
+ Expect: `no stage is marked entry: true` — this pipeline uses `route` but nothing is marked as a start.
162
+
163
+ ```bash
164
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml --strict
165
+ ```
166
+ Expect: `stage "orphan" is unreachable: not marked entry: true and not targeted by any route entry`
167
+
168
+ ```bash
169
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml --strict
170
+ ```
171
+ Expect: `stage "decide": "allow_none" is no longer supported — listed route targets always run`
172
+
173
+ ```bash
174
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml --strict
175
+ ```
176
+ Expect: `dependency cycle detected` — `a` routes to `b`, `b` routes back to `a`, as plain forward entries (not a loop).
177
+
178
+ ```bash
179
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml --strict
180
+ ```
181
+ Expect: `stage "b": feedback_loop target "c" must be an earlier ancestor` — `b`'s loop entry targets `c`, which is `a`'s other branch (a sibling), not an ancestor of `b`.
182
+
183
+ ```bash
184
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml --strict
185
+ ```
186
+ Expect: `stage "decide": "route_select" is no longer supported — listed route targets always run` — the field itself is unsupported, including on a leaf.
187
+
188
+ ```bash
189
+ ```
190
+
191
+ ```bash
192
+ ```
193
+
194
+ ```bash
195
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml --strict
196
+ ```
197
+ Expect: `stage "review": feedback_loop target "implement" replays replay_safe: false stage "middle"` — a stage sitting on the replay route (between target and source) is marked `replay_safe: false`.
198
+
199
+ ```bash
200
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml --strict
201
+ ```
202
+ Expect: `stage "review": route supports at most one loop entry, got 2` — two `type: loop` entries (with different, both-valid targets) on the same stage.
203
+
204
+ ```bash
205
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml --strict
206
+ ```
207
+ Expect: `Duplicate stage id "review" in ...` — two stage entries with the same `id` in one pipeline file. (Caught earlier, at the catalog/merge layer, before the route-specific checks even run.)
208
+
209
+ ```bash
210
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml --strict
211
+ ```
212
+ Expect: `stage "draft" has unknown route target "nonexistent-stage"`
213
+
214
+ ```bash
215
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml --strict
216
+ ```
217
+ Expect: `stage "draft": route item must have a non-empty "to" stage id` — a route entry with only `on:`, no `to:`.
218
+
219
+ ```bash
220
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml --json
221
+ ```
222
+ Expect: `io.input is not a structural subset` / `pipeline.io_incompatible` — `draft` outputs `verdict`, `review` requires `title`.
223
+
224
+ ```bash
225
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml --json
226
+ ```
227
+ Expect: `pipeline.io_incompatible` / `io.input is not a structural subset` — nested `metadata.owner.email` required on child, parent only has `metadata.source`.
228
+
229
+ ```bash
230
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml --json
231
+ ```
232
+ Expect: `pipeline.io_incompatible` / `io.input is not a structural subset` — array items `$ref` child requires `severity`, parent items only `id`.
233
+
234
+ ```bash
235
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml --json
236
+ ```
237
+ Expect: `pipeline.io_incompatible` / `io.input is not a structural subset` — child `additionalProperties: false` while parent has extra `extra`.
238
+
239
+ ```bash
240
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml --json
241
+ ```
242
+ Expect: `pipeline.io_incompatible` — `draft.out` `$ref` `#/schemas/produced` vs `review.in` `$ref` `#/schemas/consumed` (`consumed` requires extra field `extra`).
243
+
244
+ ```bash
245
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml --json
246
+ ```
247
+ Expect: `pipeline.route_if_invalid` — `if.field` is not a property of the source `io.output.schema`.
248
+
249
+ ```bash
250
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml --json
251
+ ```
252
+ Expect: `pipeline.route_if_invalid` — `if.field` is present on the output schema but not in `required`.
253
+
254
+ ```bash
255
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml --json
256
+ ```
257
+ Expect: `pipeline.route_if_invalid` — empty `all:` list.
258
+
259
+ ```bash
260
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml --json
261
+ ```
262
+ Expect: `pipeline.route_if_invalid` — numeric op `gt` on a string field.
263
+
264
+ ```bash
265
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml --json
266
+ ```
267
+ Expect: `pipeline.route_if_invalid` — nested path `customer.tier` is not required on the object schema.
268
+
269
+ ```bash
270
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml --json
271
+ ```
272
+ Expect: `pipeline.route_if_invalid` — `if` on a `{ type: loop }` Route Entry.
273
+
274
+ ```bash
275
+ ```
276
+
277
+ ```bash
278
+ npx tsx src/cli.ts validate --pipeline examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml --json
279
+ ```
280
+ Expect: `pipeline.route_if_invalid` — `if` combined with `on: [failed]`.
281
+
282
+ ## Run from the UI / CLI
283
+
284
+ All 17 valid pipelines and `smoke-test.task.yaml` are registered in the repo-root `stageflow.yaml`. Point the UI at the local build (see "Important" above — either `npm link` first, or run the UI via `npx tsx src/cli.ts ui`):
285
+
286
+ ```bash
287
+ npx tsx src/cli.ts ui
288
+ ```
289
+
290
+ Start a new run, pick any of the 17 pipeline IDs from the table above, `route-smoke-test` as the task. Requires a Pi-compatible provider connected (`npx tsx src/cli.ts providers login` or via the UI's own connect flow) — actually executing a stage calls a real model, unlike the validate command above.
291
+
292
+ From the repo git root, run a pipeline with this worktree's CLI (never global `sf`):
293
+
294
+ ```bash
295
+ npx tsx src/cli.ts run \
296
+ --pipeline examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml \
297
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
298
+ ```
299
+
300
+ ```bash
301
+ npx tsx src/cli.ts run \
302
+ --pipeline examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml \
303
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
304
+ ```
305
+
306
+ ```bash
307
+ npx tsx src/cli.ts run \
308
+ --pipeline examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml \
309
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
310
+ ```
311
+
312
+ Pipeline `07` *will* stop and wait for a human — that's expected (`on_max_replays: wait_for_human`). Unstick it:
313
+
314
+ ```bash
315
+ npx tsx src/cli.ts runs waiting
316
+ npx tsx src/cli.ts runs answer --run <runId> --stage review --answer '{"action":"continue"}'
317
+ ```
318
+
319
+ (or the UI's own decide control).
320
+
321
+ ```bash
322
+ npx tsx src/cli.ts run \
323
+ --pipeline examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml \
324
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
325
+ ```
326
+
327
+ ```bash
328
+ npx tsx src/cli.ts run \
329
+ --pipeline examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml \
330
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
331
+ ```
332
+
333
+ ```bash
334
+ npx tsx src/cli.ts run \
335
+ --pipeline examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml \
336
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
337
+ ```
338
+
339
+ ```bash
340
+ npx tsx src/cli.ts run \
341
+ --pipeline examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml \
342
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
343
+ ```
344
+
345
+ ```bash
346
+ npx tsx src/cli.ts run \
347
+ --pipeline examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml \
348
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
349
+ ```
350
+
351
+ ```bash
352
+ npx tsx src/cli.ts run \
353
+ --pipeline examples/route-wiring-smoke-test/17-if-join.pipeline.yaml \
354
+ --task examples/route-wiring-smoke-test/smoke-test.task.yaml
355
+ ```
356
+
357
+ Pipelines **11–13** require the agent to emit the example payloads in each stage prompt (`11` draft: `{ "title": "<short string>" }`; `12` draft/analyze copy the `#/schemas/report` / `#/schemas/analyzed` examples; `13` draft/review copy the `#/schemas/doc` / `#/schemas/analyzed` examples). Review/summarize/ship may emit `payload: {}`.
358
+
359
+ - Want to watch a larger fan-out (triage plus three follow-ups from quick-fix)? Run `route-demo-fork-choice`.
360
+ - Want to watch true parallel fan-out/fan-in? Run `route-demo-fan-out-fan-in`.
361
+ - Want to practice the human-in-the-loop decision flow? Run `route-demo-loop-human-decision`.
362
+ - Want to see both arms of a fan-out run, with `done` only on the safe-step arm? Run `route-demo-skip-and-multi-on`.
363
+ - Want to see two loop points converging on one ancestor? Run `route-demo-multi-loop-targets` — it also parks briefly for a replay, same idea as `07`, but resolves itself (`require_continue`) rather than needing a human.
364
+ - Want to confirm the `uses:` dialect works the same as inline stage bodies? Run `route-demo-uses-dialect-fork`.
365
+ - Want to see a payload-gated `page` skip while `notify` still runs? Run `route-demo-if-eq`. The skipped stage is skipped, not a failed run.
366
+ - Want nested `all` / `not` and `customer.tier` `in`? Run `route-demo-if-composition`. Default payload misses, so `page` skips.
367
+ - Want to see a two-parent Join gated by inbound `if`s? Run `route-demo-if-join`. Default payloads match, so `assemble` runs with both envelopes.
368
+ - Want the broadest single flow, including notify stages that all run after ship? Run `route-demo-core`.
369
+
370
+ ## What's still out of scope
371
+
372
+ A few things intentionally aren't in this catalog because they're orthogonal to the `route` migration (pre-existing features the migration didn't touch, not gaps in route coverage):
373
+
374
+ - **`gate_kinds`** / non-`feedback_loop` HITL gates — a stage-body concept, unrelated to wiring.
375
+ - **`verify`/`on_verify_fail`** completion contracts interacting with `route` — these fields pass through the migration completely unchanged; already covered by the existing (non-route) test suite.
376
+ - **`skill`/`mcp`** fields on a routed stage — capability wiring, unrelated to routing wiring.
377
+ - **The exact two-sequential-forks race timing** that caused the original "stuck-looking run" bug report — deliberately not turned into a hand-runnable example, since its whole point is a timing race that a live run can't reliably reproduce on demand. It lives only as an automated regression test: `tests/fixtures/pipelines/two-sequential-forks-join.pipeline.yaml` + `tests/runtime.genericFanIn.schedule.test.ts`.
@@ -0,0 +1,26 @@
1
+ id: route-demo-reject-needs
2
+ stages:
3
+ - id: draft
4
+ entry: true
5
+ route:
6
+ - to: review
7
+ system_prompt: Draft.
8
+ model: cursor/auto
9
+ io:
10
+ input:
11
+ schema:
12
+ type: object
13
+ output:
14
+ schema:
15
+ type: object
16
+ - id: review
17
+ needs: draft
18
+ system_prompt: Review.
19
+ model: cursor/auto
20
+ io:
21
+ input:
22
+ schema:
23
+ type: object
24
+ output:
25
+ schema:
26
+ type: object
@@ -0,0 +1,25 @@
1
+ id: route-demo-reject-fork
2
+ stages:
3
+ - id: decide
4
+ entry: true
5
+ fork:
6
+ select: one
7
+ system_prompt: Decide.
8
+ model: cursor/auto
9
+ io:
10
+ input:
11
+ schema:
12
+ type: object
13
+ output:
14
+ schema:
15
+ type: object
16
+ - id: branch-a
17
+ system_prompt: Branch A.
18
+ model: cursor/auto
19
+ io:
20
+ input:
21
+ schema:
22
+ type: object
23
+ output:
24
+ schema:
25
+ type: object
@@ -0,0 +1,30 @@
1
+ id: route-demo-reject-feedback-loop
2
+ stages:
3
+ - id: implement
4
+ entry: true
5
+ route:
6
+ - to: review
7
+ system_prompt: Implement.
8
+ model: cursor/auto
9
+ io:
10
+ input:
11
+ schema:
12
+ type: object
13
+ output:
14
+ schema:
15
+ type: object
16
+ - id: review
17
+ feedback_loop:
18
+ target: implement
19
+ max_replays: 2
20
+ on_max_replays: require_continue
21
+ replay_session: resume
22
+ system_prompt: Review.
23
+ model: cursor/auto
24
+ io:
25
+ input:
26
+ schema:
27
+ type: object
28
+ output:
29
+ schema:
30
+ type: object
@@ -0,0 +1,24 @@
1
+ id: route-demo-reject-missing-entry
2
+ stages:
3
+ - id: draft
4
+ route:
5
+ - to: review
6
+ system_prompt: Draft.
7
+ model: cursor/auto
8
+ io:
9
+ input:
10
+ schema:
11
+ type: object
12
+ output:
13
+ schema:
14
+ type: object
15
+ - id: review
16
+ system_prompt: Review.
17
+ model: cursor/auto
18
+ io:
19
+ input:
20
+ schema:
21
+ type: object
22
+ output:
23
+ schema:
24
+ type: object
@@ -0,0 +1,35 @@
1
+ id: route-demo-reject-unreachable
2
+ stages:
3
+ - id: draft
4
+ entry: true
5
+ route:
6
+ - to: review
7
+ system_prompt: Draft.
8
+ model: cursor/auto
9
+ io:
10
+ input:
11
+ schema:
12
+ type: object
13
+ output:
14
+ schema:
15
+ type: object
16
+ - id: review
17
+ system_prompt: Review.
18
+ model: cursor/auto
19
+ io:
20
+ input:
21
+ schema:
22
+ type: object
23
+ output:
24
+ schema:
25
+ type: object
26
+ - id: orphan
27
+ system_prompt: Nobody routes to me, and I'm not marked entry.
28
+ model: cursor/auto
29
+ io:
30
+ input:
31
+ schema:
32
+ type: object
33
+ output:
34
+ schema:
35
+ type: object
@@ -0,0 +1,37 @@
1
+ id: route-demo-reject-allow-none
2
+ stages:
3
+ - id: decide
4
+ entry: true
5
+ allow_none: true
6
+ route:
7
+ - to: path-a
8
+ - to: path-b
9
+ system_prompt: Decide.
10
+ model: cursor/auto
11
+ io:
12
+ input:
13
+ schema:
14
+ type: object
15
+ output:
16
+ schema:
17
+ type: object
18
+ - id: path-a
19
+ system_prompt: A.
20
+ model: cursor/auto
21
+ io:
22
+ input:
23
+ schema:
24
+ type: object
25
+ output:
26
+ schema:
27
+ type: object
28
+ - id: path-b
29
+ system_prompt: B.
30
+ model: cursor/auto
31
+ io:
32
+ input:
33
+ schema:
34
+ type: object
35
+ output:
36
+ schema:
37
+ type: object
@@ -0,0 +1,27 @@
1
+ id: route-demo-reject-cycle
2
+ stages:
3
+ - id: a
4
+ entry: true
5
+ route:
6
+ - to: b
7
+ system_prompt: A.
8
+ model: cursor/auto
9
+ io:
10
+ input:
11
+ schema:
12
+ type: object
13
+ output:
14
+ schema:
15
+ type: object
16
+ - id: b
17
+ route:
18
+ - to: a
19
+ system_prompt: B.
20
+ model: cursor/auto
21
+ io:
22
+ input:
23
+ schema:
24
+ type: object
25
+ output:
26
+ schema:
27
+ type: object
@@ -0,0 +1,42 @@
1
+ id: route-demo-reject-loop-non-ancestor
2
+ stages:
3
+ - id: a
4
+ entry: true
5
+ route:
6
+ - to: b
7
+ - to: c
8
+ system_prompt: A.
9
+ model: cursor/auto
10
+ io:
11
+ input:
12
+ schema:
13
+ type: object
14
+ output:
15
+ schema:
16
+ type: object
17
+ - id: b
18
+ route:
19
+ - type: loop
20
+ to: c
21
+ max_replays: 1
22
+ on_max_replays: require_continue
23
+ replay_session: resume
24
+ system_prompt: B.
25
+ model: cursor/auto
26
+ io:
27
+ input:
28
+ schema:
29
+ type: object
30
+ output:
31
+ schema:
32
+ type: object
33
+ - id: c
34
+ system_prompt: C.
35
+ model: cursor/auto
36
+ io:
37
+ input:
38
+ schema:
39
+ type: object
40
+ output:
41
+ schema:
42
+ type: object
@@ -0,0 +1,26 @@
1
+ id: route-demo-reject-route-select-leaf
2
+ stages:
3
+ - id: decide
4
+ entry: true
5
+ route_select: one
6
+ route:
7
+ - to: only-branch
8
+ system_prompt: Decide.
9
+ model: cursor/auto
10
+ io:
11
+ input:
12
+ schema:
13
+ type: object
14
+ output:
15
+ schema:
16
+ type: object
17
+ - id: only-branch
18
+ system_prompt: Only branch.
19
+ model: cursor/auto
20
+ io:
21
+ input:
22
+ schema:
23
+ type: object
24
+ output:
25
+ schema:
26
+ type: object