@kontourai/flow-agents 3.5.0 → 3.7.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 (111) hide show
  1. package/.github/workflows/ci.yml +4 -0
  2. package/CHANGELOG.md +15 -0
  3. package/build/src/builder-flow-run-adapter.d.ts +32 -3
  4. package/build/src/builder-flow-run-adapter.js +113 -20
  5. package/build/src/builder-flow-runtime.d.ts +26 -3
  6. package/build/src/builder-flow-runtime.js +502 -49
  7. package/build/src/builder-lifecycle-authority.d.ts +35 -0
  8. package/build/src/builder-lifecycle-authority.js +219 -0
  9. package/build/src/cli/assignment-provider.d.ts +14 -7
  10. package/build/src/cli/assignment-provider.js +128 -65
  11. package/build/src/cli/builder-run.js +46 -9
  12. package/build/src/cli/workflow-artifact-cleanup-audit.js +3 -0
  13. package/build/src/cli/workflow-sidecar.d.ts +30 -3
  14. package/build/src/cli/workflow-sidecar.js +825 -99
  15. package/build/src/cli/workflow.d.ts +2 -0
  16. package/build/src/cli/workflow.js +769 -0
  17. package/build/src/cli.js +2 -0
  18. package/build/src/flow-kit/validate.d.ts +17 -0
  19. package/build/src/flow-kit/validate.js +340 -2
  20. package/build/src/index.d.ts +4 -0
  21. package/build/src/index.js +7 -5
  22. package/build/src/lib/observed-command.d.ts +7 -0
  23. package/build/src/lib/observed-command.js +100 -0
  24. package/build/src/lib/package-version.d.ts +2 -0
  25. package/build/src/lib/package-version.js +13 -0
  26. package/build/src/lib/pinned-cli-command.d.ts +6 -0
  27. package/build/src/lib/pinned-cli-command.js +21 -0
  28. package/build/src/tools/generate-context-map.js +5 -3
  29. package/context/contracts/artifact-contract.md +1 -1
  30. package/context/scripts/hooks/config-protection.js +8 -1
  31. package/context/scripts/hooks/lib/config-protection-remedies.js +3 -0
  32. package/context/scripts/hooks/lib/kit-catalog.js +1 -1
  33. package/context/scripts/hooks/stop-goal-fit.js +79 -10
  34. package/docs/context-map.md +24 -20
  35. package/docs/developer-architecture.md +1 -1
  36. package/docs/public-workflow-cli.md +132 -0
  37. package/docs/skills-map.md +51 -27
  38. package/docs/spec/builder-flow-runtime.md +78 -40
  39. package/docs/workflow-usage-guide.md +110 -38
  40. package/evals/ci/run-baseline.sh +2 -0
  41. package/evals/fixtures/hook-influence/cases.json +2 -2
  42. package/evals/integration/test_builder_entry_enforcement.sh +57 -45
  43. package/evals/integration/test_builder_step_producers.sh +297 -6
  44. package/evals/integration/test_bundle_install.sh +258 -55
  45. package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
  46. package/evals/integration/test_current_json_per_actor.sh +12 -0
  47. package/evals/integration/test_dual_emit_flow_step.sh +62 -43
  48. package/evals/integration/test_flowdef_session_activation.sh +145 -25
  49. package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
  50. package/evals/integration/test_gate_lockdown.sh +3 -5
  51. package/evals/integration/test_goal_fit_hook.sh +60 -2
  52. package/evals/integration/test_liveness_verdict.sh +14 -17
  53. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
  54. package/evals/integration/test_public_workflow_cli.sh +573 -0
  55. package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
  56. package/evals/integration/test_sidecar_field_preservation.sh +36 -11
  57. package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
  58. package/evals/integration/test_workflow_steering_hook.sh +15 -38
  59. package/evals/run.sh +2 -0
  60. package/evals/static/test_builder_skill_coherence.sh +247 -0
  61. package/evals/static/test_library_exports.sh +5 -2
  62. package/evals/static/test_workflow_skills.sh +13 -325
  63. package/kits/builder/flows/build.flow.json +22 -0
  64. package/kits/builder/flows/shape.flow.json +9 -9
  65. package/kits/builder/kit.json +70 -16
  66. package/kits/builder/skills/builder-shape/SKILL.md +75 -75
  67. package/kits/builder/skills/continue-work/SKILL.md +45 -106
  68. package/kits/builder/skills/deliver/SKILL.md +96 -442
  69. package/kits/builder/skills/design-probe/SKILL.md +40 -139
  70. package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
  71. package/kits/builder/skills/execute-plan/SKILL.md +54 -125
  72. package/kits/builder/skills/fix-bug/SKILL.md +42 -132
  73. package/kits/builder/skills/gate-review/SKILL.md +60 -211
  74. package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
  75. package/kits/builder/skills/learning-review/SKILL.md +63 -170
  76. package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
  77. package/kits/builder/skills/plan-work/SKILL.md +51 -185
  78. package/kits/builder/skills/pull-work/SKILL.md +136 -485
  79. package/kits/builder/skills/release-readiness/SKILL.md +66 -107
  80. package/kits/builder/skills/review-work/SKILL.md +89 -176
  81. package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
  82. package/kits/builder/skills/verify-work/SKILL.md +101 -113
  83. package/package.json +2 -2
  84. package/schemas/builder-lifecycle-authorization.schema.json +57 -0
  85. package/schemas/lifecycle-authority-keys.schema.json +25 -0
  86. package/schemas/workflow-state.schema.json +1 -1
  87. package/scripts/hooks/config-protection.js +8 -1
  88. package/scripts/hooks/lib/config-protection-remedies.js +3 -0
  89. package/scripts/hooks/lib/kit-catalog.js +1 -1
  90. package/scripts/hooks/stop-goal-fit.js +79 -10
  91. package/src/builder-flow-run-adapter.ts +156 -23
  92. package/src/builder-flow-runtime.ts +535 -53
  93. package/src/builder-lifecycle-authority.ts +218 -0
  94. package/src/cli/assignment-provider-lock.test.mjs +83 -0
  95. package/src/cli/assignment-provider.ts +91 -22
  96. package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
  97. package/src/cli/builder-flow-runtime.test.mjs +597 -8
  98. package/src/cli/builder-run.ts +54 -9
  99. package/src/cli/kit-metadata-security.test.mjs +232 -6
  100. package/src/cli/public-api.test.mjs +15 -0
  101. package/src/cli/workflow-artifact-cleanup-audit.ts +3 -0
  102. package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
  103. package/src/cli/workflow-sidecar.ts +748 -99
  104. package/src/cli/workflow.ts +708 -0
  105. package/src/cli.ts +2 -0
  106. package/src/flow-kit/validate.ts +320 -2
  107. package/src/index.ts +20 -5
  108. package/src/lib/observed-command.ts +96 -0
  109. package/src/lib/package-version.ts +15 -0
  110. package/src/lib/pinned-cli-command.ts +23 -0
  111. package/src/tools/generate-context-map.ts +5 -3
@@ -137,7 +137,7 @@ Canonical vocabulary:
137
137
 
138
138
  | Field | Values |
139
139
  | --- | --- |
140
- | `state.status` | `new`, `planning`, `planned`, `in_progress`, `blocked`, `verifying`, `verified`, `needs_decision`, `not_verified`, `failed`, `delivered`, `accepted`, `archived` |
140
+ | `state.status` | `new`, `planning`, `planned`, `in_progress`, `blocked`, `verifying`, `verified`, `needs_decision`, `not_verified`, `failed`, `delivered`, `canceled`, `accepted`, `archived` |
141
141
  | `state.phase` | `idea`, `backlog`, `pickup`, `planning`, `execution`, `verification`, `goal_fit`, `evidence`, `release`, `learning`, `done` |
142
142
  | `next_action.status` | `continue`, `needs_user`, `blocked`, `done` |
143
143
  | `acceptance.criteria[].status` | `pending`, `pass`, `fail`, `not_verified`, `accepted_gap` |
@@ -120,6 +120,13 @@ function checkProtectedPathPattern(filePath) {
120
120
  };
121
121
  }
122
122
 
123
+ if (/(?:^|\/)\.flow-agents\/lifecycle-authority-keys\.json$/.test(norm)) {
124
+ return {
125
+ name: '.flow-agents/lifecycle-authority-keys.json',
126
+ reason: 'an agent could replace the pinned lifecycle authority key and forge cancellation authority',
127
+ };
128
+ }
129
+
123
130
  // .kontourai/flow-agents/current.json — an agent could forge active_flow_id / active_step_id
124
131
  // to route the gate to a permissive or empty-expects FlowDefinition.
125
132
  // SAFE: the workflow CLI writes current.json via fs (writeJson → fs.writeFileSync),
@@ -426,7 +433,7 @@ function checkCommandForBypass(command) {
426
433
  */
427
434
  // #379: the delivery/ arms carry an optional (?:[^/]+\/)? segment so redirects/tee to the
428
435
  // per-session path delivery/<slug>/trust.bundle (+ checkpoint) are caught, not just the flat path.
429
- const REDIRECT_PROTECTED_RE = /(?:^|\/|~\/)(\.bash_profile|\.bashrc|\.profile|\.zprofile|\.zshrc)$|(?:^|\/)\.claude\/settings(?:\.local)?\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/current\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/current\/[^/]+\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/\.goal-fit-block-streak\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/[^/]+\/state\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/[^/]+\/trust\.bundle$|(?:^|\/)delivery\/(?:[^/]+\/)?trust\.bundle$|(?:^|\/)delivery\/(?:[^/]+\/)?trust\.checkpoint\.json$/;
436
+ const REDIRECT_PROTECTED_RE = /(?:^|\/|~\/)(\.bash_profile|\.bashrc|\.profile|\.zprofile|\.zshrc)$|(?:^|\/)\.claude\/settings(?:\.local)?\.json$|(?:^|\/)\.flow-agents\/lifecycle-authority-keys\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/current\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/current\/[^/]+\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/\.goal-fit-block-streak\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/[^/]+\/state\.json$|(?:^|\/)(?:\.kontourai\/flow-agents|\.flow-agents)\/[^/]+\/trust\.bundle$|(?:^|\/)delivery\/(?:[^/]+\/)?trust\.bundle$|(?:^|\/)delivery\/(?:[^/]+\/)?trust\.checkpoint\.json$/;
430
437
 
431
438
  /**
432
439
  * Return true when a token (an unquoted redirect target or tee argument) matches
@@ -20,6 +20,8 @@ const SANCTIONED_REMEDIES = {
20
20
  'There is no sanctioned automated writer for this file. Ask a human maintainer to edit it directly. Never disable this hook to make the write.',
21
21
  '.claude/settings.local.json':
22
22
  'There is no sanctioned automated writer for this file. Ask a human maintainer to edit it directly. Never disable this hook to make the write.',
23
+ '.flow-agents/lifecycle-authority-keys.json':
24
+ 'Only the trusted harness installer or a human maintainer may rotate lifecycle authority keys. Never let an agent replace this trust root.',
23
25
  '.kontourai/flow-agents/current.json':
24
26
  'Use `npm run workflow:sidecar -- ensure-session` (or `advance-state`), which writes this file for you. Never disable this hook to make the write.',
25
27
  '.kontourai/flow-agents/current/<actor>.json':
@@ -58,6 +60,7 @@ function remedyFor(name) {
58
60
  * basename 'trust.bundle') -- first match wins, deterministically.
59
61
  */
60
62
  const REMEDY_COMMAND_CANDIDATES = [
63
+ { name: '.flow-agents/lifecycle-authority-keys.json', needles: ['lifecycle-authority-keys.json'] },
61
64
  { name: 'delivery/trust.checkpoint.json', needles: ['delivery/trust.checkpoint.json', 'trust.checkpoint.json'] },
62
65
  { name: 'delivery/trust.bundle', needles: ['delivery/trust.bundle'] },
63
66
  { name: '.kontourai/flow-agents/<slug>/trust.bundle', needles: ['trust.bundle'] },
@@ -137,7 +137,7 @@ function renderKitSteering(trigger) {
137
137
  else lines.push(`Activate \`${defaultSkill}\`.`);
138
138
  }
139
139
  if (targetFlowId) {
140
- lines.push(`Keep the session on \`${targetFlowId}\` and use \`npm run workflow:sidecar -- ensure-session --flow-id ${targetFlowId} ...\` when the repo provides the sidecar writer.`);
140
+ lines.push(`Keep the session on \`${targetFlowId}\`. Use the public \`flow-agents workflow\` interface only when it supports that Flow and its Work Item binding; otherwise report an unsupported-runtime blocker. Never call the package-internal writer from skill guidance.`);
141
141
  }
142
142
  if (requiredSequence.length) {
143
143
  lines.push(`Do not bypass ${requiredSequence.join(' -> ')} for matching work.`);
@@ -77,7 +77,7 @@ const PRE_EXECUTION_PHASES = new Set(['idea', 'backlog', 'pickup', 'planning']);
77
77
  // Terminal tasks are complete — they must never gate a stop or count as "active".
78
78
  // A stale current.json pointing at one, or a graveyard of finished states, must
79
79
  // not block an unrelated session.
80
- const TERMINAL_STATUSES = new Set(['done', 'delivered', 'accepted', 'archived', 'complete', 'completed']);
80
+ const TERMINAL_STATUSES = new Set(['done', 'delivered', 'canceled', 'accepted', 'archived', 'complete', 'completed']);
81
81
 
82
82
  function isTerminalDeliveredState(state) {
83
83
  if (!state || typeof state !== 'object') return false;
@@ -1759,6 +1759,37 @@ function hasSidecarPresence(artifactDir) {
1759
1759
  return fs.existsSync(path.join(artifactDir, 'state.json')) || fs.existsSync(path.join(artifactDir, 'trust.bundle'));
1760
1760
  }
1761
1761
 
1762
+ function canonicalFlowState(root, artifactDir) {
1763
+ if (!artifactDir) return { state: null, error: null };
1764
+ const slug = path.basename(artifactDir);
1765
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) return { state: null, error: 'canonical Flow run slug is malformed' };
1766
+ const runDir = path.join(root, '.kontourai', 'flow', 'runs', slug);
1767
+ const components = [
1768
+ path.join(root, '.kontourai'),
1769
+ path.join(root, '.kontourai', 'flow'),
1770
+ path.join(root, '.kontourai', 'flow', 'runs'),
1771
+ runDir,
1772
+ ];
1773
+ try {
1774
+ for (const component of components) {
1775
+ const stat = fs.lstatSync(component);
1776
+ if (stat.isSymbolicLink() || !stat.isDirectory()) return { state: null, error: `canonical Flow run has an unsafe parent component: ${component}` };
1777
+ }
1778
+ const file = path.join(runDir, 'state.json');
1779
+ const stat = fs.lstatSync(file);
1780
+ if (stat.isSymbolicLink() || !stat.isFile()) return { state: null, error: 'canonical Flow state must be a non-symlink regular file' };
1781
+ const state = JSON.parse(fs.readFileSync(file, 'utf8'));
1782
+ if (!state || typeof state !== 'object' || Array.isArray(state)
1783
+ || typeof state.status !== 'string' || !state.status.trim()
1784
+ || typeof state.current_step !== 'string' || !state.current_step.trim()) {
1785
+ return { state: null, error: 'canonical Flow state is malformed' };
1786
+ }
1787
+ return { state, error: null };
1788
+ } catch (error) {
1789
+ return { state: null, error: `canonical Flow state is unavailable or malformed: ${safeOneLine(error && error.message || error, 120)}` };
1790
+ }
1791
+ }
1792
+
1762
1793
  // WS8 (AC10a): when current.json names a slug whose session directory does NOT exist,
1763
1794
  // return that slug so analyze() can log the staleness rather than silently falling back to
1764
1795
  // a global mtime scan that could resurface an abandoned/never-real session as active.
@@ -1871,7 +1902,7 @@ function missingBundleOrStateSignal(artifactDir, activeFlowStep) {
1871
1902
  //
1872
1903
  // Both are used in analyze() for blocking decisions AND in run() for the AC2
1873
1904
  // MAX_BLOCKS hard-block guard (preventing auto-release of hard blocks).
1874
- const HARD_BLOCK = /contradicts evidence\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \(ambiguous\)/;
1905
+ const HARD_BLOCK = /contradicts evidence\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \(ambiguous\)|canonical Flow (?:run remains active|state is unsafe or malformed)/;
1875
1906
  // FULL_BLOCK adds: workflow-state hygiene, surface-unavailable fail-closed, missing log.
1876
1907
  const FULL_BLOCK = /status:|Definition Of Done|Goal Fit|sidecar validation:|contradicts evidence\.json|workflow state|evidence verdict|evidence check|NOT_VERIFIED gap|critique status|critique open|next action|caught false-completion|NOT_VERIFIED —|command-log integrity check FAILED|gate misconfiguration:|surface unavailable —|expected capture log is missing|exit-code-laundered|malformed-evidence|NOT_VERIFIED \(ambiguous\)/;
1877
1908
 
@@ -1897,7 +1928,31 @@ async function analyze(root, now = Date.now()) {
1897
1928
  artifacts = artifacts.filter(a => a && hasSidecarPresence(path.dirname(a.file)));
1898
1929
  }
1899
1930
 
1900
- if (artifacts.length === 0) return { warnings: [], blocking: false, latestArtifactDir: null };
1931
+ const scopedCanonicalFlow = canonicalFlowState(root, scoped);
1932
+ const scopedState = scoped ? readJsonFile(path.join(scoped, 'state.json')) : null;
1933
+ const scopedProjectedActive = Boolean(scopedState && scopedState.flow_run && normalizedStatus(scopedState.flow_run.status) === 'active');
1934
+ if (scopedProjectedActive && scopedCanonicalFlow.error) {
1935
+ return {
1936
+ warnings: [`workflow state: canonical Flow state is unsafe or malformed for the active scoped session: ${scopedCanonicalFlow.error}. Resolve the canonical run before stopping.`],
1937
+ blocking: true,
1938
+ activeFlowRun: true,
1939
+ latestArtifactDir: scoped,
1940
+ gatePrefix: '[stop-gate]',
1941
+ };
1942
+ }
1943
+ if (artifacts.length === 0) {
1944
+ if (normalizedStatus(scopedCanonicalFlow.state?.status) === 'active') {
1945
+ const activeStep = safeOneLine(scopedCanonicalFlow.state.current_step || 'unknown', 80);
1946
+ return {
1947
+ warnings: [`workflow state: canonical Flow run remains active at step ${activeStep}; complete or explicitly cancel the run before stopping.`],
1948
+ blocking: true,
1949
+ activeFlowRun: true,
1950
+ latestArtifactDir: scoped,
1951
+ gatePrefix: '[stop-gate]',
1952
+ };
1953
+ }
1954
+ return { warnings: [], blocking: false, activeFlowRun: false, latestArtifactDir: null };
1955
+ }
1901
1956
 
1902
1957
  const latest = artifacts[0];
1903
1958
  const latestArtifactDir = path.dirname(latest.file);
@@ -1965,14 +2020,25 @@ async function analyze(root, now = Date.now()) {
1965
2020
  // Use module-scope HARD_BLOCK / FULL_BLOCK (defined above analyze()).
1966
2021
  // pre-execution/terminal tasks: only HARD_BLOCK signals cause a block.
1967
2022
  // execution-onward tasks: FULL_BLOCK signals cause a block.
1968
- const activeFlowRun = gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active';
2023
+ const canonicalFlow = canonicalFlowState(root, latestArtifactDir);
2024
+ const activeProjectedFlow = gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active';
2025
+ const unsafeActiveCanonical = Boolean(activeProjectedFlow && canonicalFlow.error);
2026
+ if (unsafeActiveCanonical) {
2027
+ warnings.push(`workflow state: canonical Flow state is unsafe or malformed for the active scoped session: ${canonicalFlow.error}. Resolve the canonical run before stopping.`);
2028
+ }
2029
+ const activeFlowRun = normalizedStatus(canonicalFlow.state?.status) === 'active'
2030
+ || (gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active');
2031
+ if (activeFlowRun && !warnings.some(w => /canonical Flow run remains active/.test(w))) {
2032
+ const activeStep = safeOneLine(canonicalFlow.state?.current_step || gateState?.flow_run?.current_step || 'unknown', 80);
2033
+ warnings.push(`workflow state: canonical Flow run remains active at step ${activeStep}; complete or explicitly cancel the run before stopping.`);
2034
+ }
1969
2035
  const blockRe = ((preExecution && !activeFlowRun) || terminal) ? HARD_BLOCK : FULL_BLOCK;
1970
- const blocking = warnings.some(w => {
2036
+ const blocking = activeFlowRun || warnings.some(w => {
1971
2037
  // Capture cross-reference warn-mode notes never block (operator opted out).
1972
2038
  if (/\[backstop in warn mode — not blocking\]/.test(w)) return false;
1973
2039
  return blockRe.test(w);
1974
2040
  });
1975
- return { warnings, blocking, preExecution, gatePrefix: gateLabel(activeFlowStep), latestArtifactDir };
2041
+ return { warnings, blocking, activeFlowRun, preExecution, gatePrefix: gateLabel(activeFlowStep), latestArtifactDir };
1976
2042
  }
1977
2043
 
1978
2044
  /**
@@ -2220,8 +2286,9 @@ function releaseOnNonTerminalStop(root, artifactDir) {
2220
2286
 
2221
2287
  const state = readJsonFile(path.join(artifactDir, 'state.json'));
2222
2288
  if (!state) return; // AC5: no state.json — nothing to gate a release decision on.
2223
- if (state.flow_run && normalizedStatus(state.flow_run.status) === 'active') {
2224
- process.stderr.write(`[Hook] Goal Fit: stop-hook release skipped for active Flow run "${safeOneLine(state.flow_run.run_id || state.task_slug || 'unknown', 80)}"; continuation remains governed by Flow state.\n`);
2289
+ const canonicalFlow = canonicalFlowState(root, artifactDir);
2290
+ if (normalizedStatus(canonicalFlow.state?.status) === 'active' || (state.flow_run && normalizedStatus(state.flow_run.status) === 'active')) {
2291
+ process.stderr.write(`[Hook] Goal Fit: stop-hook release skipped for active Flow run "${safeOneLine(state.flow_run?.run_id || state.task_slug || path.basename(artifactDir), 80)}"; continuation remains governed by Flow state.\n`);
2225
2292
  return;
2226
2293
  }
2227
2294
 
@@ -2367,7 +2434,7 @@ async function run(rawInput) {
2367
2434
  // with runtime-constructed paths or by modifying the warning
2368
2435
  // text so the hash changes. The real anchor is external (signed checkpoints + human
2369
2436
  // review). This raises the cost of the burn-through-the-counter escape vector.
2370
- const isHardBlock = result.warnings.some(w => {
2437
+ const isHardBlock = result.activeFlowRun || result.warnings.some(w => {
2371
2438
  if (/\[backstop in warn mode — not blocking\]/.test(w)) return false;
2372
2439
  return HARD_BLOCK.test(w);
2373
2440
  });
@@ -2375,7 +2442,9 @@ async function run(rawInput) {
2375
2442
  // Do NOT clear the streak — keep accumulating so the same hard block stays visible.
2376
2443
  return {
2377
2444
  stdout: rawInput,
2378
- stderr: `${message}\n${gatePrefix} max-blocks reached but the block is a caught false-completion / integrity failure — not auto-releasing; requires a real fix or operator override.`,
2445
+ stderr: result.activeFlowRun
2446
+ ? `${message}\n${gatePrefix} max-blocks reached but canonical Flow remains active — not auto-releasing; complete or explicitly cancel the run.`
2447
+ : `${message}\n${gatePrefix} max-blocks reached but the block is a caught false-completion / integrity failure — not auto-releasing; requires a real fix or operator override.`,
2379
2448
  exitCode: 2,
2380
2449
  };
2381
2450
  }
@@ -40,8 +40,10 @@ Generated by `npm run context-map`. Regenerate after changing agents, skills, sc
40
40
  | Static suite | bash evals/run.sh static |
41
41
  | Integration suite | bash evals/run.sh integration |
42
42
  | Workflow artifacts | npm run workflow:validate-artifacts -- --require-sidecars --require-critique .kontourai/flow-agents/<slug> |
43
- | Workflow sidecars | npm run workflow:sidecar -- --help |
44
- | Claim lookup | npm run workflow:sidecar -- claim <id> <dir> |
43
+ | Workflow control | flow-agents workflow --help |
44
+ | Workflow status | flow-agents workflow status --session-dir .kontourai/flow-agents/<slug> --json |
45
+ | Workflow critique | flow-agents workflow critique --session-dir .kontourai/flow-agents/<slug> --verdict <pass|fail|not_verified> --summary <text> |
46
+ | Workflow verification | flow-agents workflow evidence --session-dir .kontourai/flow-agents/<slug> --expectation tests-evidence --status <pass|fail|not_verified> --command "bash evals/static/test_builder_skill_coherence.sh" --criterion-json '{"id":"AC-1","status":"pass","evidence_refs":[{"kind":"command","excerpt":"bash evals/static/test_builder_skill_coherence.sh","summary":"Exact substantive command run for AC-1."}]}' --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/<slug>/<slug>--plan-work.md","summary":"Reviewable criterion mapping."}' |
45
47
  | Context map drift | npm run context-map:check |
46
48
  | Bundle build | npm run build:bundles |
47
49
  | Skill drift check | flow-agents skill-drift-check |
@@ -54,8 +56,10 @@ Machine-readable workflow state lives beside Markdown artifacts in `.kontourai/f
54
56
  | --- | --- | --- |
55
57
  | assignment-provider-settings.schema.json | Flow Agents Assignment Provider Settings | https://flow-agents.dev/schemas/assignment-provider-settings.schema.json |
56
58
  | backlog-provider-settings.schema.json | Flow Agents Backlog Provider Settings | https://flow-agents.dev/schemas/backlog-provider-settings.schema.json |
59
+ | builder-lifecycle-authorization.schema.json | Builder Lifecycle Authorization | https://kontourai.dev/schemas/builder-lifecycle-authorization.schema.json |
57
60
  | decision-record.schema.json | Flow Agents Decision Record | https://flow-agents.dev/schemas/decision-record.schema.json |
58
61
  | flow-agents-settings.schema.json | Flow Agents Settings | https://flow-agents.dev/schemas/flow-agents-settings.schema.json |
62
+ | lifecycle-authority-keys.schema.json | Lifecycle Authority Key Registry | https://kontourai.dev/schemas/lifecycle-authority-keys.schema.json |
59
63
  | workflow-acceptance.schema.json | Flow Agents Workflow Acceptance | https://flow-agents.dev/schemas/workflow-acceptance.schema.json |
60
64
  | workflow-critique.schema.json | Flow Agents Workflow Critique | https://flow-agents.dev/schemas/workflow-critique.schema.json |
61
65
  | workflow-evidence.schema.json | Flow Agents Workflow Evidence | https://flow-agents.dev/schemas/workflow-evidence.schema.json |
@@ -64,26 +68,26 @@ Machine-readable workflow state lives beside Markdown artifacts in `.kontourai/f
64
68
  | workflow-release.schema.json | Flow Agents Workflow Release Readiness | https://flow-agents.dev/schemas/workflow-release.schema.json |
65
69
  | workflow-state.schema.json | Flow Agents Workflow State | https://flow-agents.dev/schemas/workflow-state.schema.json |
66
70
 
67
- Primary tools: `npm run workflow:sidecar`, `npm run workflow:validate-artifacts`, `scripts/hooks/stop-goal-fit.js`, and `scripts/hooks/workflow-steering.js`.
71
+ Primary tools: public `flow-agents workflow`, `trust.bundle`, artifact validation, `scripts/hooks/stop-goal-fit.js`, and `scripts/hooks/workflow-steering.js`. The package-internal writer is not an agent or consumer interface.
68
72
 
69
73
  ## Workflow Skills
70
74
 
71
75
  | Skill | Source | When To Load |
72
76
  | --- | --- | --- |
73
- | continue-work | kits/builder/skills/continue-work/SKILL.md | Advance a multi-slice work item to its next increment via a fresh-context handoff. Use when one or more slices of a multi-slice issue have landed and the next undone slice should be built. Routes the next slice through pull-work + pickup... |
74
- | deliver | kits/builder/skills/deliver/SKILL.md | Delivery workflow selected work to delivered code. Ensures pull-work + pickup-probe preflight, then chains plan-work execute-plan review-work verify-work → loop on failure without requiring user interaction between cleanly determ... |
75
- | evidence-gate | kits/builder/skills/evidence-gate/SKILL.md | Evaluate whether completed work is trustworthy enough for human review, merge, or release. Use after implementation, verify-work, provider checks, CI, or remediation to map acceptance criteria to evidence, inspect scope integrity, classi... |
76
- | execute-plan | kits/builder/skills/execute-plan/SKILL.md | Parallel execution primitive plan artifact path to implemented code via tool-worker (x4). Reads plan directly. Updates session file between waves. |
77
- | fix-bug | kits/builder/skills/fix-bug/SKILL.md | Bug fix orchestrator diagnose plan-work execute-plan → review-work verify-work loop. Diagnosis phase is unique to bugs, then chains the same primitives. |
78
- | gate-review | kits/builder/skills/gate-review/SKILL.md | Enumerate gate fires and suspected misses from the session's Hachure trust.bundle, classify each as correct/false_block/missed_block using Surface's resolveInquiry to produce canonical InquiryRecords, route findings to learning-review, a... |
79
- | idea-to-backlog | kits/builder/skills/idea-to-backlog/SKILL.md | Turn raw product or technical ideas into shaped, prioritized, executable GitHub issue backlog. Use for idea intake, ideation, product shaping, spike/prototype decisions, PRD-like feature briefs, prioritization, and backlog creation befor... |
80
- | learning-review | kits/builder/skills/learning-review/SKILL.md | Capture post-merge, post-deploy, or post-incident learnings and feed them back into backlog, workflow skills, tests, docs, or knowledge. Use after release readiness, post-deploy checks, retrospectives, failed gates, or repeated workflow... |
81
- | plan-work | kits/builder/skills/plan-work/SKILL.md | Code planning primitive goal + directory to structured execution plan. Delegates to tool-planner. No resume, no ideation. |
82
- | pull-work | kits/builder/skills/pull-work/SKILL.md | Select ready GitHub issues from the executable backlog and prepare them for implementation. Use when choosing what to work on next, reviewing a kanban-style issue board, enforcing WIP limits, grouping issues, deciding worktree isolation,... |
83
- | release-readiness | kits/builder/skills/release-readiness/SKILL.md | Decide whether evidence-backed work is ready to merge, release, deploy, or hold. Use after evidence-gate PASS, before merge/release/deploy, and for post-deploy verification planning. |
84
- | review-work | kits/builder/skills/review-work/SKILL.md | Review primitive - run report-only code, security, dependency, architecture/standards, and IaC/policy critique before verification; records findings through the critique artifact/sink, currently critique.json locally. |
85
- | tdd-workflow | kits/builder/skills/tdd-workflow/SKILL.md | Test-driven development RED → GREEN → REFACTOR with git checkpoints. Wraps plan-work execute-plan review-work verify-work with test-first constraints and coverage gates. |
86
- | verify-work | kits/builder/skills/verify-work/SKILL.md | Verification primitive session file path to structured evidence verdict via tool-verifier + tool-playwright. Reads acceptance criteria from plan artifact. |
77
+ | continue-work | kits/builder/skills/continue-work/SKILL.md | Explicit Builder Kit continuation extension. Prepares a fresh-context handoff for the next unfinished increment of a multi-slice Work Item. |
78
+ | deliver | kits/builder/skills/deliver/SKILL.md | Builder Kit build entrypoint. Starts or continues a selected Work Item through builder.build by composing the build primitives without owning their step evidence. |
79
+ | evidence-gate | kits/builder/skills/evidence-gate/SKILL.md | Assess whether verification evidence and scope integrity support merge review. Produces a confidence report and Builder merge-readiness evidence. |
80
+ | execute-plan | kits/builder/skills/execute-plan/SKILL.md | Execution primitive that turns a structured plan into implemented scope through tool-worker delegation. |
81
+ | fix-bug | kits/builder/skills/fix-bug/SKILL.md | Bug-fix profile for builder.build. Adds disciplined diagnosis and regression-focused verification without replacing the build primitives. |
82
+ | gate-review | kits/builder/skills/gate-review/SKILL.md | Explicit advisory extension for reviewing apparent workflow gate blocks or misses from a completed trust bundle. |
83
+ | idea-to-backlog | kits/builder/skills/idea-to-backlog/SKILL.md | Turn raw product or technical ideas into a shaped, prioritized, provider-neutral executable backlog before implementation starts. |
84
+ | learning-review | kits/builder/skills/learning-review/SKILL.md | Capture delivery decisions, outcomes, and routed follow-up. Records Builder publish-learn learning evidence in trust.bundle. |
85
+ | plan-work | kits/builder/skills/plan-work/SKILL.md | Code planning primitive that turns a goal and directory into a structured implementation plan. |
86
+ | pull-work | kits/builder/skills/pull-work/SKILL.md | Select ready provider-backed work and prepare a bounded implementation handoff. |
87
+ | release-readiness | kits/builder/skills/release-readiness/SKILL.md | Make a provider-neutral merge, release, deploy, or hold decision. Records Builder publish-learn CI merge-readiness in trust.bundle. |
88
+ | review-work | kits/builder/skills/review-work/SKILL.md | Report-only critique before Builder verification. Records a critique slice through the public workflow interface without claiming Flow completion. |
89
+ | tdd-workflow | kits/builder/skills/tdd-workflow/SKILL.md | Test-first profile for builder.build. Requires observable RED, GREEN, and appropriate REFACTOR evidence through the standard build primitives. |
90
+ | verify-work | kits/builder/skills/verify-work/SKILL.md | Report-only acceptance verification. Records command-backed Builder verification evidence in trust.bundle when bound to an active run. |
87
91
 
88
92
  ## Support Skills
89
93
 
@@ -91,14 +95,14 @@ Primary tools: `npm run workflow:sidecar`, `npm run workflow:validate-artifacts`
91
95
  | --- | --- | --- |
92
96
  | agentic-engineering | skills/agentic-engineering/SKILL.md | Eval-first execution, task decomposition, and cost-aware model routing for AI-driven development workflows. |
93
97
  | browser-test | skills/browser-test/SKILL.md | Headless browser automation via Playwright — screenshots, accessibility checks, form filling, UI testing, DOM inspection. |
94
- | builder-shape | kits/builder/skills/builder-shape/SKILL.md | Invoke Builder Kit shape from a raw idea or the current conversation context without requiring the user to name idea-to-backlog. Delegates shaping to idea-to-backlog, records the Builder Kit Flow Definition link, and stops at the backlog... |
98
+ | builder-shape | kits/builder/skills/builder-shape/SKILL.md | Builder Kit shaping entrypoint. Turns a raw idea into a provider-neutral, reviewable backlog proposal and stops before build selection unless the user explicitly continues. |
95
99
  | dependency-update | skills/dependency-update/SKILL.md | Analyze and upgrade project dependencies — latest versions, security vulnerabilities, actionable update plan across all package managers. |
96
- | design-probe | kits/builder/skills/design-probe/SKILL.md | Generic one-question-at-a-time design probing interview for turning unclear goals, designs, or workflow states into shared understanding before planning or execution. |
100
+ | design-probe | kits/builder/skills/design-probe/SKILL.md | Generic one-question-at-a-time design probe for turning unclear goals, designs, and handoffs into shared understanding. |
97
101
  | eval-rebuild | skills/eval-rebuild/SKILL.md | Project-specific build and install commands for the eval feedback loop. Injected into eval-builder agent. Replace this skill for different build systems. |
98
102
  | exemption-usage-review | kits/veritas-governance/skills/exemption-usage-review/SKILL.md | Periodic audit of standing delivery/DECLARED no-agent-delivery exemptions (ADR 0022 §3): lists every current exemption's scope, reason, approver, and age since declared_at, flags entries overdue for owner re-confirmation against a config... |
99
103
  | github-cli | skills/github-cli/SKILL.md | Interact with GitHub via gh CLI — PRs, issues, repos, releases, workflows, gists. |
100
104
  | knowledge-capture | kits/knowledge/skills/knowledge-capture/SKILL.md | Save durable knowledge, lightweight pointers, user corrections, decisions, lessons, relationship context, or source references into the knowledge base. Use when the user says save, remember, capture, file this, bookmark context, or when... |
101
- | pickup-probe | kits/builder/skills/pickup-probe/SKILL.md | Builder Kit work-item/docs/provider-grounded Probe specialization used at the design-probe flow step before plan-work. |
105
+ | pickup-probe | kits/builder/skills/pickup-probe/SKILL.md | Provider-grounded pickup probe used at the Builder design-probe step before planning. |
102
106
  | search-first | skills/search-first/SKILL.md | Research-before-coding workflow. Search for existing tools, libraries, and patterns before writing custom code. |
103
107
 
104
108
  ## Agents
@@ -108,7 +108,7 @@ flowchart TB
108
108
 
109
109
  **Current state:** The durable handoff surface is a pair of human-readable Markdown artifacts and machine-readable JSON sidecars under `.kontourai/flow-agents/<slug>/`. Verification, critique, release, and learning records are explicit artifacts rather than hidden chat memory.
110
110
 
111
- **Programmatic API (for native hosts):** The canonical sidecar writer/validator is importable as a library, not only via the `flow-agents-workflow-sidecar` CLI. A host that records workflow evidence natively should import the package root rather than reimplement validated read / merge / write:
111
+ **Programmatic API (for native hosts):** The canonical Builder runtime and sidecar writer/validator remain importable from the package root so a native host does not reimplement validated workflow mutation. Agent-facing Kit guidance uses the public `flow-agents workflow` command so gate ownership, assignment checks, command observation, and projection happen through one portable interface:
112
112
 
113
113
  ```js
114
114
  import {
@@ -0,0 +1,132 @@
1
+ # Public Workflow CLI
2
+
3
+ Flow Agents exposes its supported consumer workflow surface through the primary package binary.
4
+ Consumer repositories do not need a `package.json`, a local dependency, or a repository-owned
5
+ writer script.
6
+
7
+ Use an exact package version from an isolated npm prefix. This prevents a repository-local
8
+ dependency with the same version from intercepting the command. Generated workflow actions and
9
+ doctor remediation include this isolation automatically:
10
+
11
+ ```bash
12
+ flow_agents() (
13
+ root=$(mktemp -d) || exit 1
14
+ trap 'rm -rf "$root"' EXIT HUP INT TERM
15
+ npm exec --yes --prefix "$root" \
16
+ --package=@kontourai/flow-agents@3.6.0 -- flow-agents "$@"
17
+ )
18
+
19
+ flow_agents workflow start \
20
+ --flow builder.build \
21
+ --work-item provider:work-item-123 \
22
+ --assignment-provider example-provider \
23
+ --effective-state-json .kontourai/flow-agents/provider-assignment.json
24
+
25
+ flow_agents workflow status --json
26
+
27
+ flow_agents workflow evidence \
28
+ --session-dir .kontourai/flow-agents/example \
29
+ --expectation implementation-plan \
30
+ --status pass \
31
+ --summary "Implementation plan recorded." \
32
+ --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/example/example--plan-work.md","summary":"Reviewed implementation plan with Definition Of Done and task-to-criterion mapping."}' \
33
+ --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/example/acceptance.json","summary":"Stable acceptance criteria and required evidence."}' \
34
+ --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/example/handoff.json","summary":"Execution handoff and next action."}'
35
+
36
+ flow_agents workflow critique \
37
+ --session-dir .kontourai/flow-agents/example \
38
+ --verdict pass \
39
+ --summary "Report-only review found no blocking findings." \
40
+ --artifact-ref ".kontourai/flow-agents/example/example--deliver.md" \
41
+ --lane-json '{"id":"code-review","status":"pass","summary":"The delivered implementation was reviewed.","evidence_refs":[{"kind":"artifact","file":".kontourai/flow-agents/example/example--deliver.md","summary":"Reviewed delivery report and changed scope."}]}'
42
+ ```
43
+
44
+ `builder.build` accepts the stable, human-readable Work Item reference emitted by the selected
45
+ provider adapter. Flow Agents persists that exact reference as the run subject; it does not infer
46
+ provider identity from a GitHub-shaped string. Pass the resolved `--assignment-provider`; non-local
47
+ providers also pass their standard assignment status result through `--effective-state-json`.
48
+ Flow Agents verifies that the current actor is the confirmed holder, retains that provider result
49
+ as selected-work evidence, and creates a local runtime lease mirror for atomic session mutation.
50
+ A direct local request can resume an existing bound session, but the public CLI does not invent a
51
+ provider or create an unresolvable local binding.
52
+
53
+ `builder.shape` uses a caller-supplied, safe slug. Derive it from a selected
54
+ title using lowercase ASCII words separated by single hyphens. Never inject raw
55
+ request text into a shell command or use it as a slug:
56
+
57
+ ```bash
58
+ flow_agents workflow start --flow builder.shape \
59
+ --task-slug onboarding-alerts \
60
+ --summary "Shape onboarding alerts into independently actionable slices."
61
+ flow_agents workflow status --session-dir .kontourai/flow-agents/onboarding-alerts --json
62
+ ```
63
+
64
+ For `tests-evidence`, supply one criterion object for every accepted criterion
65
+ and one or more substantive commands that were actually run. Repeat `--command`
66
+ when criteria require different checks. Every command needs a matching
67
+ top-level command reference, and every passing criterion must cite at least one
68
+ of those exact commands. A passing observation must also report a positive executed-test or
69
+ assertion count; a successful zero-test run is rejected. Do not use placeholders such as `true`
70
+ or a version command as behavior proof:
71
+
72
+ ```bash
73
+ flow_agents workflow evidence \
74
+ --session-dir .kontourai/flow-agents/example \
75
+ --expectation tests-evidence \
76
+ --status pass \
77
+ --command "npm test" \
78
+ --summary "The project test command passed for the implemented criterion." \
79
+ --evidence-ref-json '{"kind":"command","excerpt":"npm test","summary":"Exact substantive project test command recorded for this verification result."}' \
80
+ --criterion-json '{"id":"<criterion-id>","status":"pass","evidence_refs":[{"kind":"command","excerpt":"npm test","summary":"Exact substantive project test command run for this criterion."}]}' \
81
+ --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/example/example--plan-work.md","summary":"Accepted criterion and verification mapping."}'
82
+ ```
83
+
84
+ The public lifecycle verbs are `pause`, `resume`, `release`, `cancel`, and `archive`. Pause,
85
+ resume, and release require the current assignment actor and an explicit reason. `critique`
86
+ records the `clean-critique` claim but does not independently attach it to Flow or advance a gate. Cancel and
87
+ archive require a signed user/operator authorization file. Flow owns the canonical run
88
+ transition; Flow Agents validates assignment and request binding and projects the resulting run.
89
+ Critique derives reviewer identity from the calling runtime actor. An active
90
+ implementation assignment is required, and its actor cannot review its own
91
+ work; the delegated reviewer invokes the command directly under a distinct
92
+ identity. The public interface does not accept a caller-selected reviewer
93
+ label. Every critique includes an explicit verdict, at least one substantive
94
+ `--lane-json`, and local reviewed `--artifact-ref` values. Passing critiques
95
+ require every lane to pass; reviewed files and the workspace snapshot are
96
+ hashed into the stored review target so later implementation changes invalidate
97
+ stale clean critiques.
98
+
99
+ Current local runtime actor IDs provide coordination-level separation, not a
100
+ cryptographic identity guarantee. A policy that requires externally attested
101
+ reviewer identity must keep that assurance `NOT_VERIFIED` until the runtime
102
+ supplies a trusted delegation credential.
103
+
104
+ ```bash
105
+ flow_agents workflow pause --reason "Waiting for a decision"
106
+ flow_agents workflow resume --reason "Decision received"
107
+ flow_agents workflow release --reason "Handing work back"
108
+ flow_agents workflow cancel --authorization-file cancel.json
109
+ flow_agents workflow archive --authorization-file archive.json
110
+ ```
111
+
112
+ `workflow status` is read-only. It reads the actor-scoped current-session pointer, the projected
113
+ state, and the canonical Flow run without rewriting either store. Its `next_action` is freshly
114
+ derived from the canonical run, so a stale sidecar projection cannot misdirect recovery.
115
+
116
+ ## Compatibility Doctor
117
+
118
+ Run doctor through the exact isolated package helper defined above:
119
+
120
+ ```bash
121
+ flow_agents workflow doctor --json
122
+ ```
123
+
124
+ The report distinguishes the executing CLI from a repository-local dependency and reports the
125
+ workflow/writer contract, installed hook and writer package, active Kits, Builder Kit content,
126
+ Flow runtime and definition, workflow-state schema, and trust-bundle schema. Incompatible or
127
+ missing installed components produce a nonzero exit and an exact, version-pinned `init` command
128
+ that preserves the recorded runtime and active Kits.
129
+
130
+ The package may use lower-level writer modules internally. They are not a
131
+ supported consumer or skill surface. Consumer guidance and Builder skills use
132
+ `flow-agents workflow` exclusively.