@kontourai/flow-agents 3.11.0 → 3.12.1

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 (254) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build/src/builder-flow-run-adapter.d.ts +1 -0
  3. package/build/src/builder-flow-run-adapter.js +2 -0
  4. package/build/src/builder-flow-runtime.d.ts +5 -0
  5. package/build/src/builder-flow-runtime.js +90 -68
  6. package/build/src/builder-gate-action-envelope.d.ts +152 -0
  7. package/build/src/builder-gate-action-envelope.js +368 -0
  8. package/build/src/cli/public-contracts.d.ts +139 -0
  9. package/build/src/cli/public-contracts.js +37 -0
  10. package/build/src/cli/workflow-sidecar.js +9 -13
  11. package/build/src/cli/workflow.d.ts +1 -0
  12. package/build/src/cli/workflow.js +49 -12
  13. package/build/src/continuation-driver.d.ts +40 -3
  14. package/build/src/continuation-driver.js +361 -412
  15. package/build/src/continuation-persistence.d.ts +4 -0
  16. package/build/src/continuation-persistence.js +296 -0
  17. package/build/src/continuation-validation.d.ts +9 -0
  18. package/build/src/continuation-validation.js +169 -0
  19. package/build/src/flow-kit/action-metadata.d.ts +28 -0
  20. package/build/src/flow-kit/action-metadata.js +162 -0
  21. package/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  22. package/build/src/flow-kit/action-repository-validation.js +237 -0
  23. package/build/src/flow-kit/validate.d.ts +2 -14
  24. package/build/src/flow-kit/validate.js +18 -345
  25. package/build/src/index.d.ts +4 -2
  26. package/build/src/index.js +2 -1
  27. package/dist/base/build/package.json +1 -1
  28. package/dist/base/build/src/builder-flow-run-adapter.d.ts +1 -0
  29. package/dist/base/build/src/builder-flow-run-adapter.js +2 -0
  30. package/dist/base/build/src/builder-flow-runtime.d.ts +5 -0
  31. package/dist/base/build/src/builder-flow-runtime.js +90 -68
  32. package/dist/base/build/src/builder-gate-action-envelope.d.ts +152 -0
  33. package/dist/base/build/src/builder-gate-action-envelope.js +368 -0
  34. package/dist/base/build/src/cli/public-contracts.d.ts +139 -0
  35. package/dist/base/build/src/cli/public-contracts.js +37 -0
  36. package/dist/base/build/src/cli/workflow-sidecar.js +9 -13
  37. package/dist/base/build/src/cli/workflow.d.ts +1 -0
  38. package/dist/base/build/src/cli/workflow.js +49 -12
  39. package/dist/base/build/src/continuation-driver.d.ts +40 -3
  40. package/dist/base/build/src/continuation-driver.js +361 -412
  41. package/dist/base/build/src/continuation-persistence.d.ts +4 -0
  42. package/dist/base/build/src/continuation-persistence.js +296 -0
  43. package/dist/base/build/src/continuation-validation.d.ts +9 -0
  44. package/dist/base/build/src/continuation-validation.js +169 -0
  45. package/dist/base/build/src/flow-kit/action-metadata.d.ts +28 -0
  46. package/dist/base/build/src/flow-kit/action-metadata.js +162 -0
  47. package/dist/base/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  48. package/dist/base/build/src/flow-kit/action-repository-validation.js +237 -0
  49. package/dist/base/build/src/flow-kit/validate.d.ts +2 -14
  50. package/dist/base/build/src/flow-kit/validate.js +18 -345
  51. package/dist/base/build/src/index.d.ts +4 -2
  52. package/dist/base/build/src/index.js +2 -1
  53. package/dist/base/docs/migrations.md +5 -0
  54. package/dist/base/docs/public-workflow-cli.md +41 -5
  55. package/dist/base/docs/spec/builder-flow-runtime.md +117 -0
  56. package/dist/base/evals/integration/test_builder_step_producers.sh +60 -21
  57. package/dist/base/evals/integration/test_bundle_install.sh +15 -15
  58. package/dist/base/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  59. package/dist/base/install.sh +1 -1
  60. package/dist/base/kits/builder/kit.json +88 -14
  61. package/dist/claude-code/build/package.json +1 -1
  62. package/dist/claude-code/build/src/builder-flow-run-adapter.d.ts +1 -0
  63. package/dist/claude-code/build/src/builder-flow-run-adapter.js +2 -0
  64. package/dist/claude-code/build/src/builder-flow-runtime.d.ts +5 -0
  65. package/dist/claude-code/build/src/builder-flow-runtime.js +90 -68
  66. package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +152 -0
  67. package/dist/claude-code/build/src/builder-gate-action-envelope.js +368 -0
  68. package/dist/claude-code/build/src/cli/public-contracts.d.ts +139 -0
  69. package/dist/claude-code/build/src/cli/public-contracts.js +37 -0
  70. package/dist/claude-code/build/src/cli/workflow-sidecar.js +9 -13
  71. package/dist/claude-code/build/src/cli/workflow.d.ts +1 -0
  72. package/dist/claude-code/build/src/cli/workflow.js +49 -12
  73. package/dist/claude-code/build/src/continuation-driver.d.ts +40 -3
  74. package/dist/claude-code/build/src/continuation-driver.js +361 -412
  75. package/dist/claude-code/build/src/continuation-persistence.d.ts +4 -0
  76. package/dist/claude-code/build/src/continuation-persistence.js +296 -0
  77. package/dist/claude-code/build/src/continuation-validation.d.ts +9 -0
  78. package/dist/claude-code/build/src/continuation-validation.js +169 -0
  79. package/dist/claude-code/build/src/flow-kit/action-metadata.d.ts +28 -0
  80. package/dist/claude-code/build/src/flow-kit/action-metadata.js +162 -0
  81. package/dist/claude-code/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  82. package/dist/claude-code/build/src/flow-kit/action-repository-validation.js +237 -0
  83. package/dist/claude-code/build/src/flow-kit/validate.d.ts +2 -14
  84. package/dist/claude-code/build/src/flow-kit/validate.js +18 -345
  85. package/dist/claude-code/build/src/index.d.ts +4 -2
  86. package/dist/claude-code/build/src/index.js +2 -1
  87. package/dist/claude-code/docs/migrations.md +5 -0
  88. package/dist/claude-code/docs/public-workflow-cli.md +41 -5
  89. package/dist/claude-code/docs/spec/builder-flow-runtime.md +117 -0
  90. package/dist/claude-code/evals/integration/test_builder_step_producers.sh +60 -21
  91. package/dist/claude-code/evals/integration/test_bundle_install.sh +15 -15
  92. package/dist/claude-code/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  93. package/dist/claude-code/install.sh +1 -1
  94. package/dist/claude-code/kits/builder/kit.json +88 -14
  95. package/dist/codex/build/package.json +1 -1
  96. package/dist/codex/build/src/builder-flow-run-adapter.d.ts +1 -0
  97. package/dist/codex/build/src/builder-flow-run-adapter.js +2 -0
  98. package/dist/codex/build/src/builder-flow-runtime.d.ts +5 -0
  99. package/dist/codex/build/src/builder-flow-runtime.js +90 -68
  100. package/dist/codex/build/src/builder-gate-action-envelope.d.ts +152 -0
  101. package/dist/codex/build/src/builder-gate-action-envelope.js +368 -0
  102. package/dist/codex/build/src/cli/public-contracts.d.ts +139 -0
  103. package/dist/codex/build/src/cli/public-contracts.js +37 -0
  104. package/dist/codex/build/src/cli/workflow-sidecar.js +9 -13
  105. package/dist/codex/build/src/cli/workflow.d.ts +1 -0
  106. package/dist/codex/build/src/cli/workflow.js +49 -12
  107. package/dist/codex/build/src/continuation-driver.d.ts +40 -3
  108. package/dist/codex/build/src/continuation-driver.js +361 -412
  109. package/dist/codex/build/src/continuation-persistence.d.ts +4 -0
  110. package/dist/codex/build/src/continuation-persistence.js +296 -0
  111. package/dist/codex/build/src/continuation-validation.d.ts +9 -0
  112. package/dist/codex/build/src/continuation-validation.js +169 -0
  113. package/dist/codex/build/src/flow-kit/action-metadata.d.ts +28 -0
  114. package/dist/codex/build/src/flow-kit/action-metadata.js +162 -0
  115. package/dist/codex/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  116. package/dist/codex/build/src/flow-kit/action-repository-validation.js +237 -0
  117. package/dist/codex/build/src/flow-kit/validate.d.ts +2 -14
  118. package/dist/codex/build/src/flow-kit/validate.js +18 -345
  119. package/dist/codex/build/src/index.d.ts +4 -2
  120. package/dist/codex/build/src/index.js +2 -1
  121. package/dist/codex/docs/migrations.md +5 -0
  122. package/dist/codex/docs/public-workflow-cli.md +41 -5
  123. package/dist/codex/docs/spec/builder-flow-runtime.md +117 -0
  124. package/dist/codex/evals/integration/test_builder_step_producers.sh +60 -21
  125. package/dist/codex/evals/integration/test_bundle_install.sh +15 -15
  126. package/dist/codex/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  127. package/dist/codex/install.sh +1 -1
  128. package/dist/codex/kits/builder/kit.json +88 -14
  129. package/dist/kiro/build/package.json +1 -1
  130. package/dist/kiro/build/src/builder-flow-run-adapter.d.ts +1 -0
  131. package/dist/kiro/build/src/builder-flow-run-adapter.js +2 -0
  132. package/dist/kiro/build/src/builder-flow-runtime.d.ts +5 -0
  133. package/dist/kiro/build/src/builder-flow-runtime.js +90 -68
  134. package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +152 -0
  135. package/dist/kiro/build/src/builder-gate-action-envelope.js +368 -0
  136. package/dist/kiro/build/src/cli/public-contracts.d.ts +139 -0
  137. package/dist/kiro/build/src/cli/public-contracts.js +37 -0
  138. package/dist/kiro/build/src/cli/workflow-sidecar.js +9 -13
  139. package/dist/kiro/build/src/cli/workflow.d.ts +1 -0
  140. package/dist/kiro/build/src/cli/workflow.js +49 -12
  141. package/dist/kiro/build/src/continuation-driver.d.ts +40 -3
  142. package/dist/kiro/build/src/continuation-driver.js +361 -412
  143. package/dist/kiro/build/src/continuation-persistence.d.ts +4 -0
  144. package/dist/kiro/build/src/continuation-persistence.js +296 -0
  145. package/dist/kiro/build/src/continuation-validation.d.ts +9 -0
  146. package/dist/kiro/build/src/continuation-validation.js +169 -0
  147. package/dist/kiro/build/src/flow-kit/action-metadata.d.ts +28 -0
  148. package/dist/kiro/build/src/flow-kit/action-metadata.js +162 -0
  149. package/dist/kiro/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  150. package/dist/kiro/build/src/flow-kit/action-repository-validation.js +237 -0
  151. package/dist/kiro/build/src/flow-kit/validate.d.ts +2 -14
  152. package/dist/kiro/build/src/flow-kit/validate.js +18 -345
  153. package/dist/kiro/build/src/index.d.ts +4 -2
  154. package/dist/kiro/build/src/index.js +2 -1
  155. package/dist/kiro/docs/migrations.md +5 -0
  156. package/dist/kiro/docs/public-workflow-cli.md +41 -5
  157. package/dist/kiro/docs/spec/builder-flow-runtime.md +117 -0
  158. package/dist/kiro/evals/integration/test_builder_step_producers.sh +60 -21
  159. package/dist/kiro/evals/integration/test_bundle_install.sh +15 -15
  160. package/dist/kiro/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  161. package/dist/kiro/install.sh +1 -1
  162. package/dist/kiro/kits/builder/kit.json +88 -14
  163. package/dist/opencode/build/package.json +1 -1
  164. package/dist/opencode/build/src/builder-flow-run-adapter.d.ts +1 -0
  165. package/dist/opencode/build/src/builder-flow-run-adapter.js +2 -0
  166. package/dist/opencode/build/src/builder-flow-runtime.d.ts +5 -0
  167. package/dist/opencode/build/src/builder-flow-runtime.js +90 -68
  168. package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +152 -0
  169. package/dist/opencode/build/src/builder-gate-action-envelope.js +368 -0
  170. package/dist/opencode/build/src/cli/public-contracts.d.ts +139 -0
  171. package/dist/opencode/build/src/cli/public-contracts.js +37 -0
  172. package/dist/opencode/build/src/cli/workflow-sidecar.js +9 -13
  173. package/dist/opencode/build/src/cli/workflow.d.ts +1 -0
  174. package/dist/opencode/build/src/cli/workflow.js +49 -12
  175. package/dist/opencode/build/src/continuation-driver.d.ts +40 -3
  176. package/dist/opencode/build/src/continuation-driver.js +361 -412
  177. package/dist/opencode/build/src/continuation-persistence.d.ts +4 -0
  178. package/dist/opencode/build/src/continuation-persistence.js +296 -0
  179. package/dist/opencode/build/src/continuation-validation.d.ts +9 -0
  180. package/dist/opencode/build/src/continuation-validation.js +169 -0
  181. package/dist/opencode/build/src/flow-kit/action-metadata.d.ts +28 -0
  182. package/dist/opencode/build/src/flow-kit/action-metadata.js +162 -0
  183. package/dist/opencode/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  184. package/dist/opencode/build/src/flow-kit/action-repository-validation.js +237 -0
  185. package/dist/opencode/build/src/flow-kit/validate.d.ts +2 -14
  186. package/dist/opencode/build/src/flow-kit/validate.js +18 -345
  187. package/dist/opencode/build/src/index.d.ts +4 -2
  188. package/dist/opencode/build/src/index.js +2 -1
  189. package/dist/opencode/docs/migrations.md +5 -0
  190. package/dist/opencode/docs/public-workflow-cli.md +41 -5
  191. package/dist/opencode/docs/spec/builder-flow-runtime.md +117 -0
  192. package/dist/opencode/evals/integration/test_builder_step_producers.sh +60 -21
  193. package/dist/opencode/evals/integration/test_bundle_install.sh +15 -15
  194. package/dist/opencode/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  195. package/dist/opencode/install.sh +1 -1
  196. package/dist/opencode/kits/builder/kit.json +88 -14
  197. package/dist/pi/build/package.json +1 -1
  198. package/dist/pi/build/src/builder-flow-run-adapter.d.ts +1 -0
  199. package/dist/pi/build/src/builder-flow-run-adapter.js +2 -0
  200. package/dist/pi/build/src/builder-flow-runtime.d.ts +5 -0
  201. package/dist/pi/build/src/builder-flow-runtime.js +90 -68
  202. package/dist/pi/build/src/builder-gate-action-envelope.d.ts +152 -0
  203. package/dist/pi/build/src/builder-gate-action-envelope.js +368 -0
  204. package/dist/pi/build/src/cli/public-contracts.d.ts +139 -0
  205. package/dist/pi/build/src/cli/public-contracts.js +37 -0
  206. package/dist/pi/build/src/cli/workflow-sidecar.js +9 -13
  207. package/dist/pi/build/src/cli/workflow.d.ts +1 -0
  208. package/dist/pi/build/src/cli/workflow.js +49 -12
  209. package/dist/pi/build/src/continuation-driver.d.ts +40 -3
  210. package/dist/pi/build/src/continuation-driver.js +361 -412
  211. package/dist/pi/build/src/continuation-persistence.d.ts +4 -0
  212. package/dist/pi/build/src/continuation-persistence.js +296 -0
  213. package/dist/pi/build/src/continuation-validation.d.ts +9 -0
  214. package/dist/pi/build/src/continuation-validation.js +169 -0
  215. package/dist/pi/build/src/flow-kit/action-metadata.d.ts +28 -0
  216. package/dist/pi/build/src/flow-kit/action-metadata.js +162 -0
  217. package/dist/pi/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  218. package/dist/pi/build/src/flow-kit/action-repository-validation.js +237 -0
  219. package/dist/pi/build/src/flow-kit/validate.d.ts +2 -14
  220. package/dist/pi/build/src/flow-kit/validate.js +18 -345
  221. package/dist/pi/build/src/index.d.ts +4 -2
  222. package/dist/pi/build/src/index.js +2 -1
  223. package/dist/pi/docs/migrations.md +5 -0
  224. package/dist/pi/docs/public-workflow-cli.md +41 -5
  225. package/dist/pi/docs/spec/builder-flow-runtime.md +117 -0
  226. package/dist/pi/evals/integration/test_builder_step_producers.sh +60 -21
  227. package/dist/pi/evals/integration/test_bundle_install.sh +15 -15
  228. package/dist/pi/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  229. package/dist/pi/install.sh +1 -1
  230. package/dist/pi/kits/builder/kit.json +88 -14
  231. package/docs/migrations.md +5 -0
  232. package/docs/public-workflow-cli.md +41 -5
  233. package/docs/spec/builder-flow-runtime.md +117 -0
  234. package/evals/integration/test_builder_step_producers.sh +60 -21
  235. package/evals/integration/test_bundle_install.sh +15 -15
  236. package/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  237. package/kits/builder/kit.json +88 -14
  238. package/package.json +1 -1
  239. package/src/builder-flow-run-adapter.ts +3 -0
  240. package/src/builder-flow-runtime.ts +73 -46
  241. package/src/builder-gate-action-envelope.ts +531 -0
  242. package/src/cli/builder-flow-runtime.test.mjs +289 -58
  243. package/src/cli/continuation-driver.test.mjs +542 -24
  244. package/src/cli/kit-metadata-security.test.mjs +161 -8
  245. package/src/cli/public-contracts.ts +41 -0
  246. package/src/cli/workflow-sidecar.ts +9 -13
  247. package/src/cli/workflow.ts +48 -12
  248. package/src/continuation-driver.ts +466 -378
  249. package/src/continuation-persistence.ts +228 -0
  250. package/src/continuation-validation.ts +137 -0
  251. package/src/flow-kit/action-metadata.ts +155 -0
  252. package/src/flow-kit/action-repository-validation.ts +192 -0
  253. package/src/flow-kit/validate.ts +19 -326
  254. package/src/index.ts +17 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.12.1](https://github.com/kontourai/flow-agents/compare/v3.12.0...v3.12.1) (2026-07-13)
4
+
5
+
6
+ ### Fixes
7
+
8
+ * bind gate-action requirements to gates ([#608](https://github.com/kontourai/flow-agents/issues/608)) ([b1e9ad1](https://github.com/kontourai/flow-agents/commit/b1e9ad1a03ba1b88e09d6ace156e33c010bc6848))
9
+
10
+ ## [3.12.0](https://github.com/kontourai/flow-agents/compare/v3.11.0...v3.12.0) (2026-07-13)
11
+
12
+
13
+ ### Features
14
+
15
+ * add canonical gate action envelopes ([#605](https://github.com/kontourai/flow-agents/issues/605)) ([a7cc3e5](https://github.com/kontourai/flow-agents/commit/a7cc3e553bf03ec47a008424c3d2f7693432286b))
16
+
3
17
  ## [3.11.0](https://github.com/kontourai/flow-agents/compare/v3.10.0...v3.11.0) (2026-07-13)
4
18
 
5
19
 
@@ -62,6 +62,7 @@ export interface BuilderFlowRunResult {
62
62
  attachedEvidence: FlowEvidenceEntry[];
63
63
  outcomes: GateOutcome[];
64
64
  manifest: JsonObject;
65
+ config: JsonObject;
65
66
  freshnessTransitions: JsonObject[];
66
67
  }
67
68
  export interface BuilderBuildRunResult extends Omit<BuilderFlowRunResult, "definitionId"> {
@@ -109,6 +109,7 @@ export async function evaluateBuilderFlowRun(input) {
109
109
  attachedEvidence,
110
110
  outcomes: evaluated.outcomes,
111
111
  manifest: evaluated.manifest,
112
+ config: evaluated.config,
112
113
  freshnessTransitions: evaluated.freshness_transitions,
113
114
  };
114
115
  }
@@ -174,6 +175,7 @@ function resultFromRun(run, runId) {
174
175
  attachedEvidence: [],
175
176
  outcomes: [],
176
177
  manifest: run.manifest,
178
+ config: run.config,
177
179
  freshnessTransitions: [],
178
180
  };
179
181
  }
@@ -1,3 +1,4 @@
1
+ import { type GateActionEnvelope, type GateActionProgressSnapshot } from "./builder-gate-action-envelope.js";
1
2
  import { type BuilderFlowId, type BuilderFlowRunResult } from "./builder-flow-run-adapter.js";
2
3
  type AnyRecord = Record<string, any>;
3
4
  export interface BuilderFlowSessionInput {
@@ -15,6 +16,10 @@ export interface BuilderFlowSessionResult {
15
16
  projectRoot: string;
16
17
  run: BuilderFlowRunResult;
17
18
  projection: AnyRecord;
19
+ /** Ephemeral adapter context; deliberately excluded from durable state.json projection. */
20
+ gateActionEnvelope: GateActionEnvelope | null;
21
+ /** Canonical progress observation, retained even when terminal runs emit no action envelope. */
22
+ progressSnapshot: GateActionProgressSnapshot;
18
23
  attached: boolean;
19
24
  }
20
25
  export declare function startBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
@@ -2,11 +2,11 @@ import * as fs from "node:fs";
2
2
  import { execFileSync } from "node:child_process";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import * as path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
5
  import { isDeepStrictEqual } from "node:util";
7
6
  import { flowAgentsPackageVersion } from "./lib/package-version.js";
8
7
  import { pinnedFlowAgentsCommand } from "./lib/pinned-cli-command.js";
9
- import { expectationsForGate, lifecycleRequestMatches, openGates, } from "@kontourai/flow";
8
+ import { deriveBuilderGateActionEnvelope, deriveBuilderGateActionProgressSnapshot } from "./builder-gate-action-envelope.js";
9
+ import { evaluateGate, expectationsForGate, lifecycleRequestMatches, openGates, } from "@kontourai/flow";
10
10
  import { assertAuthorizationUnused, loadBuilderLifecycleAuthorization, readAuthorizationConsumption, recordAuthorizationConsumed } from "./builder-lifecycle-authority.js";
11
11
  import { assignmentFilePath, performLocalReleaseUnderLock, readLocalAssignmentStatus, resolveCurrentAssignmentActor, withSubjectLock } from "./cli/assignment-provider.js";
12
12
  import { BUILDER_BUILD_FLOW_ID, BuilderBuildRunInputError, cancelBuilderFlowRun, evaluateBuilderFlowRun, loadBuilderFlowRun, pauseBuilderFlowRun, resumeBuilderFlowRun, startBuilderFlowRun, } from "./builder-flow-run-adapter.js";
@@ -61,13 +61,15 @@ export async function recoverBuilderFlowSession(input) {
61
61
  runId: context.slug,
62
62
  });
63
63
  assertRunSubjectBinding(run, subject);
64
- const projection = projectFlowRun(context, run, sidecarSnapshot.state);
64
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
65
65
  writeProjection(context, projection, sidecarSnapshot.raw, "recovery");
66
66
  return {
67
67
  sessionDir: context.sessionDir,
68
68
  projectRoot: context.projectRoot,
69
69
  run,
70
70
  projection,
71
+ gateActionEnvelope,
72
+ progressSnapshot,
71
73
  attached: false,
72
74
  };
73
75
  }
@@ -77,11 +79,14 @@ export async function inspectBuilderFlowSession(input) {
77
79
  const subject = workflowSubject(sidecarSnapshot.state);
78
80
  const run = await loadBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
79
81
  assertRunSubjectBinding(run, subject);
82
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
80
83
  return {
81
84
  sessionDir: context.sessionDir,
82
85
  projectRoot: context.projectRoot,
83
86
  run,
84
- projection: projectFlowRun(context, run, sidecarSnapshot.state),
87
+ projection,
88
+ gateActionEnvelope,
89
+ progressSnapshot,
85
90
  attached: false,
86
91
  };
87
92
  }
@@ -102,10 +107,10 @@ export async function cancelBuilderFlowSession(input) {
102
107
  reason: `canonical Flow run canceled by ${prepared.authorization.request.authority.request_ref}`,
103
108
  tolerateNoActiveClaim: true,
104
109
  });
105
- const projection = projectFlowRun(prepared.context, changed, prepared.sidecarSnapshot.state);
110
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(prepared.context, changed, prepared.sidecarSnapshot.state);
106
111
  writeProjection(prepared.context, projection, prepared.sidecarSnapshot.raw, "cancellation projection");
107
112
  recordAuthorizationConsumed(prepared.context.artifactRoot, prepared.authorization);
108
- return { sessionDir: prepared.context.sessionDir, projectRoot: prepared.context.projectRoot, run: changed, projection, attached: false, assignmentReleased: released !== null, idempotent: changed.idempotent };
113
+ return { sessionDir: prepared.context.sessionDir, projectRoot: prepared.context.projectRoot, run: changed, projection, gateActionEnvelope, progressSnapshot, attached: false, assignmentReleased: released !== null, idempotent: changed.idempotent };
109
114
  });
110
115
  }
111
116
  export async function releaseBuilderFlowAssignment(input) {
@@ -114,7 +119,8 @@ export async function releaseBuilderFlowAssignment(input) {
114
119
  const prepared = prepareAgentLifecycleChange(input, context);
115
120
  const run = await loadBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
116
121
  const released = performLocalReleaseUnderLock(context.artifactRoot, context.slug, prepared.actor, { actorKey: prepared.actorKey, reason: input.reason });
117
- return { sessionDir: context.sessionDir, projectRoot: context.projectRoot, run, projection: prepared.sidecarSnapshot.state, attached: false, assignmentReleased: released !== null };
122
+ const { progressSnapshot } = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
123
+ return { sessionDir: context.sessionDir, projectRoot: context.projectRoot, run, projection: prepared.sidecarSnapshot.state, gateActionEnvelope: null, progressSnapshot, attached: false, assignmentReleased: released !== null };
118
124
  });
119
125
  }
120
126
  export async function archiveBuilderFlowSession(input) {
@@ -151,12 +157,15 @@ export async function archiveBuilderFlowSession(input) {
151
157
  clearCurrentPointers(prepared.context.artifactRoot, prepared.context.slug);
152
158
  recordAuthorizationConsumed(prepared.context.artifactRoot, prepared.authorization);
153
159
  }
160
+ const { progressSnapshot } = projectFlowRun(prepared.context, run, prepared.sidecarSnapshot.state);
154
161
  fs.renameSync(prepared.context.sessionDir, archiveDir);
155
162
  return {
156
163
  sessionDir: archiveDir,
157
164
  projectRoot: prepared.context.projectRoot,
158
165
  run,
159
166
  projection: archivedState,
167
+ gateActionEnvelope: null,
168
+ progressSnapshot,
160
169
  attached: false,
161
170
  archiveDir,
162
171
  };
@@ -173,13 +182,15 @@ async function changeBuilderFlowSessionLifecycle(input, operation) {
173
182
  runId: context.slug,
174
183
  request: { reason: input.reason, authority: { kind: "operator_request", actor: prepared.actorKey, request_ref: `flow-agents://assignment/${context.slug}/${operation}/${at}`, requested_at: at } },
175
184
  });
176
- const projection = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
185
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
177
186
  writeProjection(context, projection, prepared.sidecarSnapshot.raw, `${operation} projection`);
178
187
  return {
179
188
  sessionDir: context.sessionDir,
180
189
  projectRoot: context.projectRoot,
181
190
  run,
182
191
  projection,
192
+ gateActionEnvelope,
193
+ progressSnapshot,
183
194
  attached: false,
184
195
  };
185
196
  });
@@ -277,7 +288,7 @@ async function syncAndProject(context, initial, sidecarSnapshot) {
277
288
  const snapshot = stageTrustBundleSnapshot(context);
278
289
  try {
279
290
  const rawBundle = JSON.parse(snapshot.raw.toString("utf8"));
280
- const gateEvidence = await bundleGateEvidence(rawBundle, gates[0], run.state, run.state.subject, context.projectRoot, manifestEvidence(run.manifest));
291
+ const gateEvidence = await bundleGateEvidence(rawBundle, gates[0], run.state, run.state.subject, context.projectRoot, manifestEvidence(run.manifest), run.config);
281
292
  if (gateEvidence) {
282
293
  const alreadyAttached = manifestEvidence(run.manifest).some((entry) => entry.gate_id === gates[0].id
283
294
  && entry.sha256 === snapshot.sha256
@@ -309,16 +320,28 @@ async function syncAndProject(context, initial, sidecarSnapshot) {
309
320
  removeTrustBundleSnapshot(snapshot);
310
321
  }
311
322
  }
312
- const projection = projectFlowRun(context, run, sidecarSnapshot.state);
323
+ if (!attached && gates.length === 1 && gateCanPassWithoutNewEvidence(run, gates[0])) {
324
+ run = await evaluateBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
325
+ }
326
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
313
327
  writeProjection(context, projection, sidecarSnapshot.raw, "projection");
314
328
  return {
315
329
  sessionDir: context.sessionDir,
316
330
  projectRoot: context.projectRoot,
317
331
  run,
318
332
  projection,
333
+ gateActionEnvelope,
334
+ progressSnapshot,
319
335
  attached,
320
336
  };
321
337
  }
338
+ function gateCanPassWithoutNewEvidence(run, gate) {
339
+ const definition = JSON.parse(fs.readFileSync(path.join(run.dir, "definition.json"), "utf8"));
340
+ const expectations = expectationsForGate(gate, run.config);
341
+ const outcome = evaluateGate(definition, run.state, run.manifest, gate.id, run.config);
342
+ return outcome.status === "pass"
343
+ && (typeof outcome.accepted_exception_id === "string" || expectations.every((expectation) => !expectation.required));
344
+ }
322
345
  function assertRunSubjectBinding(run, subject) {
323
346
  if (run.state.subject !== subject) {
324
347
  throw new BuilderBuildRunInputError("flow_run.state.subject", "must match the selected Work Item");
@@ -382,10 +405,10 @@ function persistedFlowId(state) {
382
405
  function openGatesForResult(run) {
383
406
  return openGates(JSON.parse(fs.readFileSync(path.join(run.dir, "definition.json"), "utf8")), run.state);
384
407
  }
385
- async function bundleGateEvidence(bundle, gate, state, subject, projectRoot, manifest) {
408
+ async function bundleGateEvidence(bundle, gate, state, subject, projectRoot, manifest, config) {
386
409
  if (!isRecord(bundle) || !Array.isArray(bundle.claims))
387
410
  return null;
388
- const expectations = expectationsForGate(gate);
411
+ const expectations = expectationsForGate(gate, config);
389
412
  const visit = currentGateVisit(state, String(gate.step));
390
413
  const enteredAt = visit.enteredAt;
391
414
  const synchronizedAt = Date.now();
@@ -762,17 +785,32 @@ function projectFlowRun(context, run, sidecar) {
762
785
  const canceled = run.state.status === "canceled";
763
786
  const needsDecision = run.state.status === "needs_decision";
764
787
  const failed = run.state.status === "failed";
765
- const action = complete || paused || canceled || needsDecision || failed ? { skills: [], operations: [] } : stepAction(run.definitionId, run.state.current_step);
766
- if (!action) {
767
- throw new BuilderBuildRunInputError("kit.flow_step_actions", `does not declare Builder step ${run.state.current_step}`);
768
- }
769
- const required = gates.flatMap((gate) => expectationsForGate(gate)
788
+ const progressSnapshot = deriveBuilderGateActionProgressSnapshot({
789
+ sessionDir: context.sessionDir,
790
+ projectRoot: context.projectRoot,
791
+ run,
792
+ definition: definition,
793
+ });
794
+ const envelope = complete || paused || canceled || needsDecision || failed
795
+ ? null
796
+ : deriveBuilderGateActionEnvelope({
797
+ sessionDir: context.sessionDir,
798
+ projectRoot: context.projectRoot,
799
+ run,
800
+ definition: definition,
801
+ });
802
+ const action = envelope ? {
803
+ skills: envelope.action.skills.map((skill) => skill.id),
804
+ operations: envelope.action.operations,
805
+ } : { skills: [], operations: [] };
806
+ const required = gates.flatMap((gate) => expectationsForGate(gate, run.config)
770
807
  .filter((expectation) => expectation.required)
771
808
  .map((expectation) => `${expectation.id} (${expectation.bundle_claim.claimType}/${expectation.bundle_claim.subjectType ?? "any"})`));
772
- const skills = action?.skills ?? [];
773
- const operations = action?.operations ?? [];
809
+ const skills = action.skills;
810
+ const operations = action.operations;
774
811
  const syncCommand = pinnedFlowAgentsCommand(flowAgentsPackageVersion(), ["workflow", "status", "--session-dir", `.kontourai/flow-agents/${context.slug}`, "--json"]);
775
812
  const routeBack = latestRouteBack(run.state);
813
+ const externalCapability = envelope?.stop_condition.external_capability;
776
814
  const skillText = skills.length ? `Activate ${skills.map((skill) => `\`${skill}\``).join(" then ")}.` : "No Builder skill is required.";
777
815
  const operationText = operations.length ? ` Perform ${operations.map((operation) => `\`${operation}\``).join(" then ")}.` : "";
778
816
  const gateText = gates.length
@@ -791,32 +829,40 @@ function projectFlowRun(context, run, sidecar) {
791
829
  ? { status: "blocked", summary: "Canonical Flow requires an external decision before continuation." }
792
830
  : failed
793
831
  ? { status: "failed", summary: "Canonical Flow run failed; no continuation turn is allowed." }
794
- : {
795
- status: "continue",
796
- summary: `Flow step \`${run.state.current_step}\`: ${skillText}${operationText} ${gateText}${routeText} Then synchronize the recorded evidence.`,
797
- skills,
798
- operations,
799
- command: syncCommand,
800
- };
832
+ : externalCapability
833
+ ? {
834
+ status: "blocked",
835
+ summary: `Flow step \`${run.state.current_step}\` is waiting for external capability \`${externalCapability.capability}\`. Flow Agents has no authenticated executor and cannot record provider completion.`,
836
+ skills,
837
+ operations,
838
+ external_capability: externalCapability,
839
+ }
840
+ : {
841
+ status: "continue",
842
+ summary: `Flow step \`${run.state.current_step}\`: ${skillText}${operationText} ${gateText}${routeText} Then synchronize the recorded evidence.`,
843
+ skills,
844
+ operations,
845
+ command: syncCommand,
846
+ };
801
847
  const phase = phaseForStep(definition.phase_map, run.state.current_step) ?? sidecar.phase;
802
- return {
803
- ...sidecar,
804
- status: complete ? "delivered" : canceled ? "canceled" : failed ? "failed" : (paused || needsDecision) ? "blocked" : (run.state.transitions.length > 0 ? "in_progress" : sidecar.status),
805
- phase: complete || canceled || failed ? "done" : phase,
806
- updated_at: run.state.updated_at,
807
- flow_run: {
808
- run_id: run.runId,
809
- definition_id: run.definitionId,
810
- definition_version: run.definitionVersion,
811
- status: run.state.status,
812
- current_step: run.state.current_step,
813
- run_ref: path.relative(context.projectRoot, run.dir),
814
- open_gate_ids: gates.map((gate) => gate.id),
815
- ...(typeof routeBack?.attempt === "number" ? { route_back_attempt: routeBack.attempt } : {}),
816
- ...(typeof routeBack?.max_attempts === "number" ? { route_back_max_attempts: routeBack.max_attempts } : {}),
817
- },
818
- next_action: nextAction,
819
- };
848
+ return { gateActionEnvelope: envelope, progressSnapshot, projection: {
849
+ ...sidecar,
850
+ status: complete ? "delivered" : canceled ? "canceled" : failed ? "failed" : (paused || needsDecision) ? "blocked" : (run.state.transitions.length > 0 ? "in_progress" : sidecar.status),
851
+ phase: complete || canceled || failed ? "done" : phase,
852
+ updated_at: run.state.updated_at,
853
+ flow_run: {
854
+ run_id: run.runId,
855
+ definition_id: run.definitionId,
856
+ definition_version: run.definitionVersion,
857
+ status: run.state.status,
858
+ current_step: run.state.current_step,
859
+ run_ref: path.relative(context.projectRoot, run.dir),
860
+ open_gate_ids: gates.map((gate) => gate.id),
861
+ ...(typeof routeBack?.attempt === "number" ? { route_back_attempt: routeBack.attempt } : {}),
862
+ ...(typeof routeBack?.max_attempts === "number" ? { route_back_max_attempts: routeBack.max_attempts } : {}),
863
+ },
864
+ next_action: nextAction,
865
+ } };
820
866
  }
821
867
  function writeProjection(context, projection, expectedStateRaw, operation) {
822
868
  const prepared = prepareProjectionWrites(context, projection, expectedStateRaw, operation);
@@ -964,20 +1010,6 @@ function writeExistingFileNoFollow(file, content) {
964
1010
  fs.closeSync(descriptor);
965
1011
  }
966
1012
  }
967
- function stepAction(flowId, stepId) {
968
- const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot(), "kits", "builder", "kit.json"), "utf8"));
969
- const actions = Array.isArray(manifest.flow_step_actions) ? manifest.flow_step_actions : [];
970
- const action = actions.find((candidate) => isRecord(candidate)
971
- && candidate.flow_id === flowId
972
- && candidate.step_id === stepId);
973
- if (!isRecord(action) || !Array.isArray(action.skills) || !action.skills.every((skill) => typeof skill === "string")) {
974
- return null;
975
- }
976
- const operations = Array.isArray(action.operations) && action.operations.every((operation) => typeof operation === "string")
977
- ? action.operations
978
- : [];
979
- return { skills: action.skills, operations };
980
- }
981
1013
  function phaseForStep(phaseMap, stepId) {
982
1014
  if (!isRecord(phaseMap))
983
1015
  return stepId === "design-probe" ? "pickup" : null;
@@ -987,16 +1019,6 @@ function latestRouteBack(state) {
987
1019
  const outcomes = Array.isArray(state.gate_outcomes) ? state.gate_outcomes : [];
988
1020
  return [...outcomes].reverse().find((outcome) => isRecord(outcome) && outcome.status === "route-back") ?? null;
989
1021
  }
990
- function packageRoot() {
991
- let directory = path.dirname(fileURLToPath(import.meta.url));
992
- while (!fs.existsSync(path.join(directory, "package.json"))) {
993
- const parent = path.dirname(directory);
994
- if (parent === directory)
995
- throw new Error("unable to locate Flow Agents package root");
996
- directory = parent;
997
- }
998
- return directory;
999
- }
1000
1022
  function isRunNotFound(error) {
1001
1023
  return isRecord(error) && (error.code === "flow.run_location.not_found"
1002
1024
  || (typeof error.message === "string" && error.message.includes("flow.run_location.not_found")));
@@ -0,0 +1,152 @@
1
+ import { type FlowRunState } from "@kontourai/flow";
2
+ import { PUBLIC_OPERATION_CONTRACTS } from "./cli/public-contracts.js";
3
+ type AnyRecord = Record<string, unknown>;
4
+ export type GateActionInterfaceParameter = {
5
+ name: string;
6
+ flag: string;
7
+ required: boolean;
8
+ allowed_values?: string[];
9
+ repeatable?: boolean;
10
+ required_when?: {
11
+ parameter: string;
12
+ equals: string;
13
+ };
14
+ };
15
+ export type GateActionWorkflowMutation = {
16
+ expectation_id: string;
17
+ interface: "workflow.evidence" | "workflow.critique";
18
+ package: {
19
+ name: "@kontourai/flow-agents";
20
+ version: string;
21
+ };
22
+ command: "flow-agents";
23
+ argv: string[];
24
+ parameters: GateActionInterfaceParameter[];
25
+ };
26
+ export type GateActionPublicMutation = GateActionWorkflowMutation | {
27
+ expectation_id: string;
28
+ interface: "operation";
29
+ operation: string;
30
+ protocol: (typeof PUBLIC_OPERATION_CONTRACTS)[keyof typeof PUBLIC_OPERATION_CONTRACTS];
31
+ completion: {
32
+ status: "external_verification_required";
33
+ executable_by_flow_agents: false;
34
+ gate_evidence_interface: null;
35
+ };
36
+ };
37
+ export type GateActionEnvelope = {
38
+ schema_version: "2.0";
39
+ flow: {
40
+ run_id: string;
41
+ definition_id: string;
42
+ definition_version: string;
43
+ status: string;
44
+ current_step: string;
45
+ gate_ids: string[];
46
+ };
47
+ gate: {
48
+ requirements: Array<{
49
+ id: string;
50
+ gate_id: string;
51
+ required: boolean;
52
+ description: string;
53
+ claim_type: string;
54
+ subject_type: string | null;
55
+ status: "satisfied" | "accepted_exception" | "unresolved";
56
+ }>;
57
+ unresolved_requirement_ids: string[];
58
+ accepted_exceptions: Array<{
59
+ gate_id: string;
60
+ exception_id: string;
61
+ }>;
62
+ };
63
+ action: {
64
+ skills: Array<{
65
+ id: string;
66
+ package: {
67
+ name: "@kontourai/flow-agents";
68
+ version: string;
69
+ };
70
+ /** Stable package-relative source path, bound to package version and SHA-256. */
71
+ path: string;
72
+ sha256: string;
73
+ }>;
74
+ operations: string[];
75
+ declared_artifacts: string[];
76
+ declared_evidence: string[];
77
+ implementation_allowed: boolean;
78
+ };
79
+ public_interfaces: {
80
+ status: {
81
+ command: string;
82
+ };
83
+ mutations: GateActionPublicMutation[];
84
+ };
85
+ stop_condition: {
86
+ kind: "one_turn";
87
+ scope: {
88
+ run_id: string;
89
+ current_step: string;
90
+ gate_ids: string[];
91
+ current_gate_only: true;
92
+ };
93
+ required: {
94
+ skill_ids: string[];
95
+ artifact_refs: string[];
96
+ unresolved_evidence_ids: string[];
97
+ };
98
+ sequence: ["activate_required_skills", "produce_declared_artifacts", "record_bound_evidence", "synchronize_canonical_flow", "return_adapter_result"];
99
+ after: "return_adapter_result";
100
+ synchronize_canonical_flow: true;
101
+ adapter_evidence_is_gate_evidence: false;
102
+ external_capability?: {
103
+ status: "waiting";
104
+ operation: string;
105
+ capability: string;
106
+ completion: "external_verification_required";
107
+ };
108
+ };
109
+ progress: {
110
+ canonical_evidence: string[];
111
+ observed_artifacts: string[];
112
+ prior_turn?: GateActionPriorProgress;
113
+ };
114
+ };
115
+ export type GateActionProgressSnapshot = Pick<GateActionEnvelope["progress"], "canonical_evidence" | "observed_artifacts"> & {
116
+ current_step: string;
117
+ /** Optional for compatibility with snapshots persisted before terminal status capture. */
118
+ canonical_status?: string;
119
+ };
120
+ export type GateActionPriorProgress = {
121
+ step_advanced: boolean;
122
+ evidence_added: string[];
123
+ artifact_changes: string[];
124
+ no_progress: boolean;
125
+ consecutive_no_progress: number;
126
+ stagnation: "none" | "possible" | "stagnant";
127
+ };
128
+ export type BuilderGateActionEnvelopeInput = {
129
+ sessionDir: string;
130
+ projectRoot: string;
131
+ run: {
132
+ runId: string;
133
+ definitionId: string;
134
+ definitionVersion: string;
135
+ state: FlowRunState;
136
+ manifest: AnyRecord;
137
+ config: AnyRecord;
138
+ };
139
+ definition: AnyRecord;
140
+ };
141
+ /** Derive bounded adapter context without trusting adapter telemetry. */
142
+ export declare function deriveBuilderGateActionEnvelope(input: BuilderGateActionEnvelopeInput): GateActionEnvelope;
143
+ /**
144
+ * Canonical progress is useful after a run becomes terminal, when no adapter
145
+ * action envelope may be emitted. Keep this deliberately separate from the
146
+ * request-only envelope so terminal snapshots cannot be mistaken for work.
147
+ */
148
+ export declare function deriveBuilderGateActionProgressSnapshot(input: BuilderGateActionEnvelopeInput): GateActionProgressSnapshot;
149
+ export declare function gateActionProgressSnapshot(envelope: GateActionEnvelope): GateActionProgressSnapshot;
150
+ export declare function withGateActionPriorProgress(envelope: GateActionEnvelope, priorTurn: GateActionPriorProgress): GateActionEnvelope;
151
+ export declare function observeBuilderArtifactsForProgress(sessionDir: string, artifacts: string[]): string[];
152
+ export {};