@kontourai/flow-agents 3.0.0 → 3.2.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 (158) hide show
  1. package/.github/workflows/ci.yml +12 -0
  2. package/CHANGELOG.md +32 -0
  3. package/CONTEXT.md +67 -1
  4. package/README.md +4 -0
  5. package/build/src/cli/assignment-provider.d.ts +188 -0
  6. package/build/src/cli/assignment-provider.js +193 -51
  7. package/build/src/cli/workflow-sidecar.d.ts +16 -6
  8. package/build/src/cli/workflow-sidecar.js +492 -45
  9. package/build/src/lib/flow-resolver.d.ts +12 -6
  10. package/build/src/lib/flow-resolver.js +30 -14
  11. package/build/src/tools/validate-source-tree.js +2 -1
  12. package/context/contracts/assignment-provider-contract.md +10 -1
  13. package/context/contracts/execution-contract.md +78 -0
  14. package/context/contracts/probe-docs-write-contract.md +187 -0
  15. package/context/scripts/hooks/config-protection.js +24 -4
  16. package/context/scripts/hooks/lib/config-protection-remedies.js +9 -0
  17. package/context/scripts/hooks/stop-goal-fit.js +262 -5
  18. package/context/scripts/hooks/workflow-steering.js +42 -0
  19. package/docs/adr/0001-flow-agents-consumes-flow.md +2 -0
  20. package/docs/adr/0002-flow-kits-as-extension-unit.md +2 -0
  21. package/docs/adr/0003-flow-agents-coordinates-kits-and-adapters.md +2 -0
  22. package/docs/adr/0004-gates-expect-surface-claims.md +2 -0
  23. package/docs/adr/0005-kubernetes-inspired-resource-contracts.md +2 -0
  24. package/docs/adr/0006-typescript-first-source-policy.md +2 -0
  25. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  26. package/docs/adr/0007-skill-audit.md +2 -0
  27. package/docs/adr/0008-kit-operation-boundary.md +2 -0
  28. package/docs/adr/0009-canonical-hook-core-kit-boundary.md +2 -0
  29. package/docs/adr/0010-workflow-trust-state-as-hachure-bundle.md +2 -0
  30. package/docs/adr/0011-mcp-posture.md +2 -0
  31. package/docs/adr/0012-agent-coordination-as-liveness-claims.md +2 -0
  32. package/docs/adr/0013-context-lifecycle.md +2 -0
  33. package/docs/adr/0014-core-vs-domain-kit-boundary.md +2 -0
  34. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +2 -0
  35. package/docs/adr/0016-three-hard-boundary-model.md +2 -0
  36. package/docs/adr/0017-anti-gaming-trust-security-model.md +2 -0
  37. package/docs/adr/0018-freeze-local-shell-heuristics.md +2 -0
  38. package/docs/adr/0019-kit-dependency-ownership.md +2 -0
  39. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +2 -0
  40. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +3 -1
  41. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +113 -0
  42. package/docs/adr/README.md +49 -0
  43. package/docs/adr/index.md +34 -0
  44. package/docs/decisions/agent-coordination.md +20 -0
  45. package/docs/decisions/anti-gaming-trust-security.md +20 -0
  46. package/docs/decisions/context-lifecycle.md +18 -0
  47. package/docs/decisions/core-domain-kit-boundary.md +18 -0
  48. package/docs/decisions/flow-flow-agents-boundary.md +18 -0
  49. package/docs/decisions/flow-kit.md +20 -0
  50. package/docs/decisions/flow-skill-kit-tool-boundary.md +20 -0
  51. package/docs/decisions/graph-knowledge-provider.md +63 -0
  52. package/docs/decisions/hook-core-kit-boundary.md +18 -0
  53. package/docs/decisions/index.md +19 -0
  54. package/docs/decisions/kit-dependency-ownership.md +18 -0
  55. package/docs/decisions/kit-operation-boundary.md +18 -0
  56. package/docs/decisions/knowledge-promote-sub-flow.md +59 -0
  57. package/docs/decisions/kontour-resource-contract.md +18 -0
  58. package/docs/decisions/mcp-posture.md +18 -0
  59. package/docs/decisions/three-hard-boundary-model.md +18 -0
  60. package/docs/decisions/trust-reconcile.md +20 -0
  61. package/docs/decisions/typescript-source-policy.md +48 -0
  62. package/docs/decisions/workflow-enforcement.md +18 -0
  63. package/docs/decisions/workflow-trust-state.md +20 -0
  64. package/docs/fixture-ownership.md +1 -1
  65. package/docs/workflow-usage-guide.md +1 -1
  66. package/evals/ci/run-baseline.sh +6 -0
  67. package/evals/fixtures/assignment-provider/hostile-effective-state.json +11 -0
  68. package/evals/integration/test_checkpoint_signing.sh +4 -3
  69. package/evals/integration/test_current_json_per_actor.sh +516 -0
  70. package/evals/integration/test_ensure_session_ownership_guard.sh +435 -0
  71. package/evals/integration/test_gate_lockdown.sh +46 -0
  72. package/evals/integration/test_model_routing_escalation.sh +145 -0
  73. package/evals/integration/test_publish_delivery.sh +14 -6
  74. package/evals/integration/test_pull_work_liveness_preflight.sh +6 -1
  75. package/evals/integration/test_stop_hook_release.sh +552 -0
  76. package/evals/integration/test_trust_reconcile_negatives.sh +170 -0
  77. package/evals/integration/test_workflow_sidecar_writer.sh +12 -3
  78. package/evals/run.sh +10 -0
  79. package/evals/static/test_knowledge_providers.sh +13 -4
  80. package/evals/static/test_model_routing_hints.sh +107 -0
  81. package/evals/static/test_workflow_skills.sh +15 -2
  82. package/kits/builder/skills/builder-shape/SKILL.md +10 -0
  83. package/kits/builder/skills/deliver/SKILL.md +69 -11
  84. package/kits/builder/skills/design-probe/SKILL.md +47 -0
  85. package/kits/builder/skills/execute-plan/SKILL.md +13 -0
  86. package/kits/builder/skills/fix-bug/SKILL.md +17 -0
  87. package/kits/builder/skills/idea-to-backlog/SKILL.md +10 -0
  88. package/kits/builder/skills/pickup-probe/SKILL.md +4 -4
  89. package/kits/builder/skills/plan-work/SKILL.md +9 -0
  90. package/kits/builder/skills/pull-work/SKILL.md +10 -0
  91. package/kits/builder/skills/review-work/SKILL.md +11 -0
  92. package/kits/builder/skills/tdd-workflow/SKILL.md +17 -0
  93. package/kits/builder/skills/verify-work/SKILL.md +11 -0
  94. package/kits/knowledge/adapters/default-store/index.js +147 -18
  95. package/kits/knowledge/adapters/flow-runner/index.js +912 -16
  96. package/kits/knowledge/adapters/obsidian-store/index.js +97 -14
  97. package/kits/knowledge/adapters/shared/codec.js +265 -0
  98. package/kits/knowledge/docs/README.md +121 -2
  99. package/kits/knowledge/docs/store-contract.md +517 -7
  100. package/kits/knowledge/evals/audit-freshness/suite.test.js +92 -1
  101. package/kits/knowledge/evals/consolidate-incremental/suite.test.js +494 -0
  102. package/kits/knowledge/evals/consolidation/suite.test.js +1 -1
  103. package/kits/knowledge/evals/contract-suite/suite.test.js +212 -0
  104. package/kits/knowledge/evals/freshness/suite.test.js +339 -0
  105. package/kits/knowledge/evals/inbound-references/suite.test.js +351 -0
  106. package/kits/knowledge/evals/retirement/suite.test.js +1 -1
  107. package/kits/knowledge/evals/supersede-propagation/suite.test.js +384 -0
  108. package/kits/knowledge/flows/promote.flow.json +84 -0
  109. package/kits/knowledge/kit.json +15 -0
  110. package/kits/knowledge/promote/distill.js +96 -0
  111. package/kits/knowledge/promote/fixtures/contradiction-registry/CONTEXT.md +7 -0
  112. package/kits/knowledge/promote/fixtures/contradiction-registry/docs/decisions/cache-eviction-policy.md +12 -0
  113. package/kits/knowledge/promote/fixtures/contradiction-registry/docs/decisions/cache-eviction.md +12 -0
  114. package/kits/knowledge/promote/fixtures/repo/CONTEXT.md +11 -0
  115. package/kits/knowledge/promote/fixtures/repo/docs/decisions/index.md +9 -0
  116. package/kits/knowledge/promote/fixtures/repo/docs/decisions/liveness-claim.md +12 -0
  117. package/kits/knowledge/promote/fixtures/session/acceptance.json +9 -0
  118. package/kits/knowledge/promote/fixtures/session/agents/tool-planner/events.jsonl +1 -0
  119. package/kits/knowledge/promote/fixtures/session/agents/tool-verifier/events.jsonl +1 -0
  120. package/kits/knowledge/promote/fixtures/session/agents/tool-worker-1-1/events.jsonl +1 -0
  121. package/kits/knowledge/promote/fixtures/session/kontourai-flow-agents-287--deliver.md +47 -0
  122. package/kits/knowledge/promote/fixtures/session/learning.json +35 -0
  123. package/kits/knowledge/promote/fixtures/session/state.json +19 -0
  124. package/kits/knowledge/promote/health.js +137 -0
  125. package/kits/knowledge/promote/index.js +176 -0
  126. package/kits/knowledge/promote/ingest.js +103 -0
  127. package/kits/knowledge/promote/lib.js +132 -0
  128. package/kits/knowledge/promote/link.js +84 -0
  129. package/kits/knowledge/promote/promote.test.js +174 -0
  130. package/kits/knowledge/providers/conformance/suite.test.js +18 -0
  131. package/kits/knowledge/providers/index.js +1 -0
  132. package/kits/knowledge/providers/neo4j/connection.js +121 -0
  133. package/kits/knowledge/providers/neo4j/cypher.js +190 -0
  134. package/kits/knowledge/providers/neo4j/fake-driver.js +123 -0
  135. package/kits/knowledge/providers/neo4j/fixtures/spike-ground-truth.json +29 -0
  136. package/kits/knowledge/providers/neo4j/graph-queries.js +210 -0
  137. package/kits/knowledge/providers/neo4j/index.js +280 -0
  138. package/kits/knowledge/providers/neo4j/integration.test.js +122 -0
  139. package/kits/knowledge/providers/neo4j/neo4j.test.js +219 -0
  140. package/kits/knowledge/providers/neo4j/sync.js +235 -0
  141. package/package.json +4 -2
  142. package/schemas/workflow-handoff.schema.json +6 -0
  143. package/scripts/README.md +1 -0
  144. package/scripts/ci/mint-attestation.js +33 -6
  145. package/scripts/ci/trust-reconcile.js +144 -26
  146. package/scripts/freeze-adrs.mjs +364 -0
  147. package/scripts/hooks/config-protection.js +24 -4
  148. package/scripts/hooks/evidence-capture.js +4 -1
  149. package/scripts/hooks/lib/config-protection-remedies.js +9 -0
  150. package/scripts/hooks/lib/current-pointer.js +123 -0
  151. package/scripts/hooks/lib/liveness-heartbeat.js +75 -35
  152. package/scripts/hooks/stop-goal-fit.js +262 -5
  153. package/scripts/hooks/workflow-steering.js +42 -0
  154. package/scripts/statusline/flow-agents-statusline.js +3 -1
  155. package/src/cli/assignment-provider.ts +239 -59
  156. package/src/cli/workflow-sidecar.ts +529 -43
  157. package/src/lib/flow-resolver.ts +35 -14
  158. package/src/tools/validate-source-tree.ts +2 -1
@@ -157,10 +157,22 @@ jobs:
157
157
  continue-on-error: true
158
158
  run: bash evals/ci/run-baseline.sh --check assignment-provider-github-integration
159
159
 
160
+ - name: Stop hook release-with-handoff integration
161
+ continue-on-error: true
162
+ run: bash evals/ci/run-baseline.sh --check stop-hook-release-with-handoff-integration
163
+
160
164
  - name: Pull work assignment join integration
161
165
  continue-on-error: true
162
166
  run: bash evals/ci/run-baseline.sh --check pull-work-assignment-join-integration
163
167
 
168
+ - name: Ensure-session ownership guard integration
169
+ continue-on-error: true
170
+ run: bash evals/ci/run-baseline.sh --check ensure-session-ownership-guard-integration
171
+
172
+ - name: Current.json per-actor integration
173
+ continue-on-error: true
174
+ run: bash evals/ci/run-baseline.sh --check current-json-per-actor-integration
175
+
164
176
  - name: Finalize CI evidence
165
177
  if: always()
166
178
  run: bash evals/ci/run-baseline.sh --finalize
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.2.0](https://github.com/kontourai/flow-agents/compare/v3.1.0...v3.2.0) (2026-07-04)
4
+
5
+
6
+ ### Features
7
+
8
+ * **builder:** per-step model-routing hints + escalate-on-gate-failure ladder ([#376](https://github.com/kontourai/flow-agents/issues/376)) ([8182dc6](https://github.com/kontourai/flow-agents/commit/8182dc66da10f3bfd731aef93d7cbd38b63ddd06))
9
+ * **knowledge:** inbound-reference integrity check, fail closed ([#340](https://github.com/kontourai/flow-agents/issues/340)) ([02932ab](https://github.com/kontourai/flow-agents/commit/02932abec98fcc43ae3755d2281697e21c7451a6))
10
+ * **knowledge:** incremental append-mode consolidate (Closes [#343](https://github.com/kontourai/flow-agents/issues/343)) ([9b972f5](https://github.com/kontourai/flow-agents/commit/9b972f5bf9d7a41d1de4af23d5e27619db3b1635))
11
+ * **knowledge:** incremental append-mode consolidate, regenerate snapshot from records ([#343](https://github.com/kontourai/flow-agents/issues/343)) ([32cc263](https://github.com/kontourai/flow-agents/commit/32cc263aedc4c3727b144ced24872bc102a13383))
12
+ * **knowledge:** record-carried freshness + Hachure-aligned status semantics ([#341](https://github.com/kontourai/flow-agents/issues/341)) ([32ff45e](https://github.com/kontourai/flow-agents/commit/32ff45eb9244fa1879a0b32784e95e5e5c80de71))
13
+
14
+
15
+ ### Fixes
16
+
17
+ * **delivery:** per-session delivery paths so concurrent deliveries stop contending ([#379](https://github.com/kontourai/flow-agents/issues/379)) ([fedf4db](https://github.com/kontourai/flow-agents/commit/fedf4db5c41c7e45dcf9db949176be076131a09e))
18
+ * **delivery:** per-session delivery paths so concurrent deliveries stop contending ([#379](https://github.com/kontourai/flow-agents/issues/379)) ([a03026f](https://github.com/kontourai/flow-agents/commit/a03026fccf940da2129a3b82e979443c37b87456))
19
+
20
+ ## [3.1.0](https://github.com/kontourai/flow-agents/compare/v3.0.0...v3.1.0) (2026-07-04)
21
+
22
+
23
+ ### Features
24
+
25
+ * **docs:** probe docs-write contract — vocabulary + decision deltas ([#311](https://github.com/kontourai/flow-agents/issues/311)) ([#371](https://github.com/kontourai/flow-agents/issues/371)) ([867c3b5](https://github.com/kontourai/flow-agents/commit/867c3b5b645c896e5df6886177171b05e73e8fa9))
26
+ * **knowledge:** neo4j knowledge-store provider — Cypher-backed [#317](https://github.com/kontourai/flow-agents/issues/317) interface (opt-in default) ([#373](https://github.com/kontourai/flow-agents/issues/373)) ([2ef2523](https://github.com/kontourai/flow-agents/commit/2ef2523cc65a5e56dec8dcbf84edc3718cfe190c))
27
+ * **knowledge:** promote sub-flow — ingest→distill→link→health (flow within a flow) ([#313](https://github.com/kontourai/flow-agents/issues/313)) ([#372](https://github.com/kontourai/flow-agents/issues/372)) ([b345d89](https://github.com/kontourai/flow-agents/commit/b345d89873c99f65f00d0fe8ede6a8702b1a2b43))
28
+ * **knowledge:** stable record identity — short-id prefix + slug aliases ([#339](https://github.com/kontourai/flow-agents/issues/339)) ([ff54bc7](https://github.com/kontourai/flow-agents/commit/ff54bc74f893321f13276cd147d500f91e1fc133))
29
+
30
+
31
+ ### Documentation
32
+
33
+ * **adr:** ADR freeze cutover + liveness coordination experiment ([#332](https://github.com/kontourai/flow-agents/issues/332)) ([#368](https://github.com/kontourai/flow-agents/issues/368)) ([2c845b8](https://github.com/kontourai/flow-agents/commit/2c845b81675db02622fee8fa1efa6aa197ce96c0))
34
+
3
35
  ## [3.0.0](https://github.com/kontourai/flow-agents/compare/v2.4.0...v3.0.0) (2026-07-04)
4
36
 
5
37
 
package/CONTEXT.md CHANGED
@@ -66,6 +66,16 @@ _Avoid_: Graph database as the generic term (the model is provider-independent;
66
66
  A configured implementation of the knowledge-store capability behind the Knowledge Graph model. Providers expose a read interface (nodes, edges, query-by-type) and a proposals-only write interface (proposeWrite returns a proposal, never mutating a human-curated store). The reference providers are markdown-vault (the Obsidian-shaped vault), git-repo (decision registry, CONTEXT.md vocabulary, learnings), and work-item (GitHub issues as a source/sink adapter). See context/contracts/knowledge-store-contract.md.
67
67
  _Avoid_: Knowledge adapter when contrasting the provider interface with a single store adapter
68
68
 
69
+ ### Graph Knowledge Provider
70
+
71
+ The owner's opt-in Neo4j-backed Knowledge Store Provider (the `neo4j` provider). A queryable materialized view of the Knowledge Graph, synced from the file/work-item providers with idempotent MERGE semantics — the file stores stay the source of truth and the write side stays proposals-only. Selected via `KNOWLEDGE_PROVIDER=neo4j`; degrades to the file providers when no Neo4j is reachable. The file providers remain the portfolio default; the graph is a personal default only. See docs/decisions/graph-knowledge-provider.md.
72
+ _Avoid_: Graph database as the default store (it is opt-in and a view, not the source of truth)
73
+
74
+ ### Knowledge Promote Sub-Flow
75
+
76
+ The Knowledge Kit's codebase-facing pipeline (the "flow within a flow") that a delivered session's promotion runs through: ingest the session artifacts, distill schema-valid draft decision/vocabulary/learning deltas, link their provenance (PR, merge SHA, session archive, touched topics), and health-check the registry for contradictions with a merge-repair proposal. It is proposals-only — every output is a draft under the session's proposals directory that the promote step applies; the sub-flow never writes docs directly. Invokable standalone and composable from the Builder promote step. See docs/decisions/knowledge-promote-sub-flow.md.
77
+ _Avoid_: Promotion gate as a synonym (the gate is the recorded promote claim; this is the assisted pipeline)
78
+
69
79
  ### Kontour Resource Contract
70
80
 
71
81
  A versioned Kontour record shape for durable machine-readable configuration, scope, run state, evidence, provider output, and cross-product interchange. Kontour Resource Contracts are the default for new pre-public durable contracts unless a product records why a native shape is clearer.
@@ -225,7 +235,7 @@ A reason code for a Gate that cannot be evaluated or cannot pass because a requi
225
235
 
226
236
  ### Probe
227
237
 
228
- A Builder Kit Alignment Gate that explores context, challenges assumptions, and records aligned decisions before the process continues. A Probe asks one question at a time, recommends an answer, and uses repository context before asking when the answer can be discovered.
238
+ A Builder Kit Alignment Gate that explores context, challenges assumptions, and records aligned decisions before the process continues. A Probe asks one question at a time, recommends an answer, and uses repository context before asking when the answer can be discovered. As understanding crystallizes, a Probe writes it into durable docs in the same motion: a vocabulary delta into this glossary and a decision delta into the Decision Registry, per [context/contracts/probe-docs-write-contract.md](context/contracts/probe-docs-write-contract.md).
229
239
  _Avoid_: Grill, interrogation
230
240
 
231
241
  ### Flow
@@ -328,6 +338,62 @@ The Console overview for global setup, registered projects, cross-project usage,
328
338
 
329
339
  The shared tool layer used by the Console, CLI, AI agents, and automation. The Control API owns operations such as reading effective settings, explaining provider resolution, testing provider health, previewing config changes, writing config, inspecting workflow state, and reporting usage or eval outcomes.
330
340
 
341
+ ### Workflow trust state
342
+
343
+ The trust bundle a workflow gate reads to decide whether to advance — claims, evidence, verification events, and derived status expressed as a Hachure Trust Bundle — so gates consume inspectable trust state rather than raw tool output. Provenance lives in frozen ADRs; the subject is open in the Decision Registry as [docs/decisions/workflow-trust-state.md](docs/decisions/workflow-trust-state.md).
344
+
345
+ ### TypeScript-first source policy
346
+
347
+ The policy that Kontour product and runtime source defaults to TypeScript, with narrow JavaScript/MJS exceptions (config/tooling, generated assets, thin launchers, fixtures, historical artifacts) and staged per-repo migration for existing non-TypeScript source. Ratified in the Decision Registry as [docs/decisions/typescript-source-policy.md](docs/decisions/typescript-source-policy.md).
348
+
349
+ ### Flow / Skill / Kit / Tool boundary
350
+
351
+ The layering that separates a Flow (workflow semantics) from a Skill (agent-facing procedure), a Flow Kit (installable bundle), and a Tool (an executable operation), so each concern has one home and does not leak into the others. Subject open in the Decision Registry as [docs/decisions/flow-skill-kit-tool-boundary.md](docs/decisions/flow-skill-kit-tool-boundary.md).
352
+
353
+ ### Kit operation boundary
354
+
355
+ The rule for what a kit-owned operation may do versus what belongs to the core, keeping kit operations scoped to their capability and free of core enforcement responsibilities. Subject open in the Decision Registry as [docs/decisions/kit-operation-boundary.md](docs/decisions/kit-operation-boundary.md).
356
+
357
+ ### Hook core/kit boundary
358
+
359
+ The division between canonical hook behavior owned by the core and hook contributions owned by kits, so enforcement hooks have a single authoritative implementation. Subject open in the Decision Registry as [docs/decisions/hook-core-kit-boundary.md](docs/decisions/hook-core-kit-boundary.md).
360
+
361
+ ### MCP posture
362
+
363
+ Flow Agents' stance on the Model Context Protocol: enforcement stays in hooks, Surface owns any MCP projection, and no MCP configuration is auto-injected into a runtime. Subject open in the Decision Registry as [docs/decisions/mcp-posture.md](docs/decisions/mcp-posture.md).
364
+
365
+ ### Agent coordination
366
+
367
+ How concurrent agents avoid stepping on each other's work, modeled as Hachure liveness claims plus assignment leases with stale-claim takeover, so a work item's holder is advisory-visible and reclaimable when stale. Subject open in the Decision Registry as [docs/decisions/agent-coordination.md](docs/decisions/agent-coordination.md).
368
+
369
+ ### Context lifecycle
370
+
371
+ The lifecycle of an agent's working context — workflow-boundary compaction, freshness-gated reuse, and the split between durable learnings and ephemeral context — so context is refreshed rather than silently stale. Subject open in the Decision Registry as [docs/decisions/context-lifecycle.md](docs/decisions/context-lifecycle.md).
372
+
373
+ ### Core vs domain kit boundary
374
+
375
+ The generic/kit boundary that keeps the Flow Agents core domain-agnostic while domain behavior lives in kits, so the core carries no kit-specific knowledge. Subject open in the Decision Registry as [docs/decisions/core-domain-kit-boundary.md](docs/decisions/core-domain-kit-boundary.md).
376
+
377
+ ### Flow / Flow Agents boundary
378
+
379
+ The reconciled division of responsibility between Flow (the workflow engine consumed for enforcement) and Flow Agents (the product that consumes it), so each owns a distinct layer without duplicating the other. Subject open in the Decision Registry as [docs/decisions/flow-flow-agents-boundary.md](docs/decisions/flow-flow-agents-boundary.md).
380
+
381
+ ### Three-hard-boundary model
382
+
383
+ The FlowDefinition-driven, kit-agnostic model that names the three hard boundaries the core enforces, unifying the individual boundary decisions into one architecture. Subject open in the Decision Registry as [docs/decisions/three-hard-boundary-model.md](docs/decisions/three-hard-boundary-model.md).
384
+
385
+ ### Anti-gaming trust security
386
+
387
+ The layered-defense trust security model that assumes the local agent can be gamed and anchors enforcement in an external CI check, freezing the local shell-parsing heuristics and routing new enforcement to the CI anchor. Subject open in the Decision Registry as [docs/decisions/anti-gaming-trust-security.md](docs/decisions/anti-gaming-trust-security.md).
388
+
389
+ ### Kit dependency ownership
390
+
391
+ The rule for which layer owns a kit's runtime dependencies, keeping dependency declaration and installation with the kit that needs them rather than the core. Subject open in the Decision Registry as [docs/decisions/kit-dependency-ownership.md](docs/decisions/kit-dependency-ownership.md).
392
+
393
+ ### Trust-reconcile and delivery reconciliation
394
+
395
+ The CI-anchored reconciliation of a session's trust claims against a manifest — classifying command, session-local, and attested claims, honoring governed waivers — and the fail-closed delivery reconciliation that blocks publication on unreconciled residue unless an exemption is recorded. Subject open in the Decision Registry as [docs/decisions/trust-reconcile.md](docs/decisions/trust-reconcile.md).
396
+
331
397
  ### Model Routing
332
398
 
333
399
  The policy that maps a delegate role name (such as `delegate-mechanical`, `delegate-implementation`, `delegate-design`, `orchestrator`, `extraction-default`) to a specific `model@provider` ref. Model Routing is data, not code: it lives in `.datum/config.json` (read by the `@kontourai/datum` registry, schema `datum.schema.json`) and never in generated files or per-agent frontmatter. The orchestrator resolves the role at delegation time (`datum resolve <role> --json`) and passes the resolved model explicitly when spawning each delegate. See [context/contracts/execution-contract.md](context/contracts/execution-contract.md) § Delegation: Model Routing and [docs/decisions/model-routing.md](docs/decisions/model-routing.md).
package/README.md CHANGED
@@ -217,6 +217,10 @@ See [Repository Structure](docs/repository-structure.md) for the canonical map.
217
217
  - `kits/`, `schemas/`, `packaging/`, `evals/`, `docs/`, and `integrations/` hold Flow Kit assets, contracts, package metadata, evals, durable docs, and optional integrations.
218
218
  - `dist/`, `build/`, and `_site/` are generated output. Local `.kontourai/`, `.flow-agents/`, `.codex/`, `.claude/`, telemetry, promptfoo, Veritas, and cache directories stay ignored; durable outcomes belong in docs, source, schemas, or provider records.
219
219
 
220
+ ## Graph provider (opt-in)
221
+
222
+ The Knowledge Kit ships an optional `neo4j` graph provider — the owner's opt-in personal default, while the file providers remain the portfolio default. It is a queryable **materialized view** synced from the file/work-item stores (which stay the source of truth), with Cypher-backed health/query verbs when selected and graceful degradation to the file providers when no Neo4j is reachable (never a hard dependency). Opt in with `KNOWLEDGE_PROVIDER=neo4j` and see [Graph provider (opt-in)](kits/knowledge/docs/README.md#graph-provider-opt-in) for the `docker run` one-liner, env vars, sync command, and an example Cypher session.
223
+
220
224
  ## Documentation
221
225
 
222
226
  The [GitHub Pages site](https://kontourai.github.io/flow-agents/) is the product overview and quickstart. The repository docs are the developer reference for contracts, workflow behavior, evals, and integration boundaries. For the gate semantics underneath — definitions, runs, evidence, route-back — read the [Kontour Flow documentation](https://kontourai.github.io/flow/).
@@ -1 +1,189 @@
1
+ export type ActorStruct = {
2
+ runtime: string;
3
+ session_id: string;
4
+ host: string;
5
+ human?: string | null;
6
+ };
7
+ type AssignmentClaimRecordStatus = "claimed" | "released" | "superseded";
8
+ type AssignmentAuditEntry = {
9
+ at: string;
10
+ transition: "claim" | "release" | "supersede";
11
+ from_actor?: ActorStruct | null;
12
+ to_actor?: ActorStruct | null;
13
+ reason?: string;
14
+ };
15
+ /**
16
+ * The versioned claim-record shape from the contract doc's "Versioned claim-record format"
17
+ * section (Design Decision 2). `schema_version` is bumped only on an incompatible change, per
18
+ * artifact-contract.md's existing sidecar rule.
19
+ *
20
+ * `actor_key` (F1 fix, fix-plan iteration 1, HIGH — additive field, schema_version unchanged):
21
+ * the canonical `resolveActor(env).actor` string for the claiming actor — the SAME flat/bare
22
+ * token every other tool (`liveness whoami`, `liveness claim --actor`, per-actor current.json,
23
+ * pull-work's `--self-actor`) already uses. Optional so every pre-fix record and every #290 eval
24
+ * fixture with no `actor_key` still parses; `computeEffectiveState` falls back to
25
+ * `serializeActor(record.actor)` (today's behavior) whenever it's absent. Present, it is the ONLY
26
+ * correct self-recognition/liveness-join key — see computeEffectiveState's holderActorKey.
27
+ */
28
+ export type AssignmentClaimRecord = {
29
+ schema_version: "1.0";
30
+ role: "AssignmentClaimRecord";
31
+ subject_id: string;
32
+ actor: ActorStruct;
33
+ actor_key?: string;
34
+ claimed_at: string;
35
+ ttl_seconds: number;
36
+ branch: string;
37
+ artifact_dir: string;
38
+ status: AssignmentClaimRecordStatus;
39
+ audit_trail?: AssignmentAuditEntry[];
40
+ };
41
+ export type FreshHolder = {
42
+ actor: string;
43
+ lastAt: string;
44
+ ttlSeconds: number;
45
+ fresh: boolean;
46
+ };
47
+ export type EffectiveState = "held" | "reclaimable" | "human-held" | "free";
48
+ /** Provider-neutral assignment-layer read, before any liveness join (contract doc's status()). */
49
+ export type AssignmentStatus = {
50
+ subject_id: string;
51
+ provider: "local-file" | "github";
52
+ assignee: string | null;
53
+ record: AssignmentClaimRecord | null;
54
+ has_claim_label?: boolean;
55
+ };
56
+ export declare function assignmentFilePath(artifactRoot: string, subjectId: string): string;
57
+ export declare function readLocalRecord(artifactRoot: string, subjectId: string): AssignmentClaimRecord | null;
58
+ export declare function writeLocalRecord(artifactRoot: string, subjectId: string, record: AssignmentClaimRecord): void;
59
+ /**
60
+ * F1 fix (fix-plan iteration 1, CRITICAL): claimLocalFile/releaseLocalFile/supersedeLocalFile were
61
+ * a plain read -> compare-actor -> write with no lock, so two concurrently-launched OS processes
62
+ * could both read "no conflicting claim" before either wrote, and the second write would silently
63
+ * clobber the first with zero error and zero audit-trail entry for the loser (reproduced 29/40
64
+ * races against the built CLI). This mirrors the EXACT mechanism `withLock` already uses in
65
+ * workflow-sidecar.ts:908 for the same class of shared-state mutation — atomic `fs.mkdirSync`
66
+ * lockdir create as the mutual-exclusion primitive, EEXIST-spin with a staleness-reclaim check
67
+ * (a lock directory older than the stale threshold is presumed abandoned by a crashed process and
68
+ * is reclaimed rather than waited on forever) and a bounded deadline, `finally` rmSync release —
69
+ * as a small LOCAL helper (not a cross-import of that private function, which would pull the
70
+ * entire workflow-sidecar module in for one primitive). Deliberately synchronous (sleepSync's
71
+ * Atomics.wait spin, not setTimeout/await) so claim/release/supersede can stay sync `number`
72
+ * -returning functions and the CLI dispatcher (src/cli.ts, `number | Promise<number>`) does not
73
+ * need any ripple to async. On lock-acquire failure (any error other than a live contested lock,
74
+ * or a timeout waiting one out) this THROWS — never a silent no-op — "fail loud, never fail-open"
75
+ * (artifact-contract.md). Wrap the ENTIRE read-modify-write body (the existing-claim check AND
76
+ * the write) of all three local-file mutators in this, since all three mutate the same record
77
+ * file for a given subject.
78
+ */
79
+ export declare function withSubjectLock<T>(artifactRoot: string, subjectId: string, body: () => T): T;
80
+ /**
81
+ * The assignment ⋈ liveness join (contract doc's "assignment ⋈ liveness join" section, ADR 0021
82
+ * §1). Pure function: `{ assignment, freshHoldersList, selfActor, nowMs }` -> one of five
83
+ * effective states (held/reclaimable/human-held/free — "held" covers both the plain and
84
+ * assignment-lagging rows, matching the contract table's own repeated "held" label).
85
+ *
86
+ * The human-assignee gate (AC11, Design Decision 3) reads `record.actor.human` being *present*,
87
+ * never a username heuristic — an idle human assignment is always `human-held`, regardless of
88
+ * idle duration, and is never auto-reclaimable by this function.
89
+ *
90
+ * `nowMs` (F3 fix, fix-plan iteration 1) is the SAME resolved "now" the caller already threads
91
+ * into `freshHolders()` (the `--now` override, when passed, else `Date.now()`) — passing it
92
+ * through here too means `--now` deterministically governs idle_days as well as liveness
93
+ * freshness, rather than idle_days silently reading the real wall clock regardless of `--now`.
94
+ */
95
+ export declare function computeEffectiveState(assignment: AssignmentStatus, freshHoldersList: FreshHolder[], selfActor: string | undefined, nowMs: number): {
96
+ effective_state: EffectiveState;
97
+ reason: string;
98
+ holder?: {
99
+ actor?: string;
100
+ assignee?: string | null;
101
+ idle_days?: number | null;
102
+ last_at?: string;
103
+ };
104
+ };
105
+ /**
106
+ * Wave 1 (#291) extraction: the durable-write body previously inlined inside claimLocalFile's
107
+ * withSubjectLock() closure, now a parameter-driven pure function so ensure-session's ownership
108
+ * guard (workflow-sidecar.ts, Wave 2) can reuse the EXACT same claim logic — same-actor idempotent
109
+ * refresh, different-actor throw, atomic write under withSubjectLock — rather than reimplementing
110
+ * a second, parallel claim path. claimLocalFile (CLI wrapper, below) is now a thin
111
+ * parse-args/print-envelope shell around this.
112
+ */
113
+ export declare function performLocalClaim(artifactRoot: string, subjectId: string, actor: ActorStruct, opts: {
114
+ ttlSeconds: number;
115
+ branch: string;
116
+ artifactDir: string;
117
+ reason?: string;
118
+ actorKey?: string;
119
+ }): AssignmentClaimRecord;
120
+ /**
121
+ * Wave 1 (#292) extraction: the durable-write body previously inlined inside releaseLocalFile's
122
+ * withSubjectLock() closure, now a parameter-driven pure function so the Stop hook's non-terminal
123
+ * release lifecycle (scripts/hooks/stop-goal-fit.js, #292 Wave 2) can reuse the EXACT same release
124
+ * logic — actor-ownership verification, audit-trail append, atomic write under withSubjectLock —
125
+ * rather than reimplementing a second, parallel release path. releaseLocalFile (CLI wrapper,
126
+ * below) is now a thin parse-args/print-envelope shell around this, mirroring the
127
+ * performLocalSupersede/supersedeLocalFile extraction shape exactly.
128
+ *
129
+ * Two behaviors are deliberately DIFFERENT from a naive inline release, both required for the
130
+ * Stop hook's idempotent, actor-scoped lifecycle release (never for the interactive CLI, which
131
+ * keeps `tolerateNoActiveClaim` unset/false and therefore 100% of its prior throw-on-error shape):
132
+ *
133
+ * - `opts.tolerateNoActiveClaim === true` and there is no existing record, or the existing
134
+ * record's status is not `"claimed"`: return `null` (a tolerated no-op) instead of throwing
135
+ * "no active claim to release". This is the one deliberate idempotency change vs today's
136
+ * releaseLocalFile — a second release call (e.g. a double Stop event) must be a safe no-op.
137
+ * - `releasedBy` is provided and does not match the existing record's holder: never force-release
138
+ * a claim held by a different actor — return `null` (if tolerateNoActiveClaim) or throw
139
+ * (otherwise), same as the no-active-claim case. The comparison mirrors computeEffectiveState()'s
140
+ * `record.actor_key || helper.serializeActor(record.actor)` canonical-key preference EXACTLY
141
+ * (actor_key-first, falling back to serializeActor only when actor_key is absent) — the read
142
+ * path (status/effective-state) and this write path (release) must use the identical
143
+ * canonical-key comparison, or a claim written under an explicit-override actor (`actor_key`
144
+ * bare, e.g. `"canonical-x"`, but `serializeActor(record.actor)` a DIFFERENT triple, e.g.
145
+ * `"explicit-override:canonical-x:host"`) can be self-recognized by computeEffectiveState() yet
146
+ * fail to release here because the releaser's canonical key was compared against the wrong
147
+ * (re-derived, triple) form instead of the stored actor_key. Comparing two serializeActor()
148
+ * calls unconditionally — as a prior version of this function did — is NOT correct for override
149
+ * actors and reintroduces the exact #291 seam on the release path.
150
+ *
151
+ * Contract: when `releasedBy` is provided AND the existing record is `actor_key`-stamped,
152
+ * `opts.actorKey` is REQUIRED (the canonical `resolveActor(env).actor` string) — otherwise
153
+ * ownership cannot be verified. A caller that passes `releasedBy` without `opts.actorKey` against
154
+ * an `actor_key`-stamped record would have its ownership compared as
155
+ * `existing.actor_key` (bare canonical) vs `serializeActor(releasedBy)` (re-derived triple), which
156
+ * can NEVER match even for the legitimate holder — a silent-failure trap, not a real ownership
157
+ * check. This is refused loudly (see the guard at the top of the `releasedBy` branch below) rather
158
+ * than allowed to silently no-op or wrongly refuse.
159
+ */
160
+ export declare function performLocalRelease(artifactRoot: string, subjectId: string, releasedBy: ActorStruct | null, opts?: {
161
+ reason?: string;
162
+ actorKey?: string;
163
+ tolerateNoActiveClaim?: boolean;
164
+ }): AssignmentClaimRecord | null;
165
+ /**
166
+ * Wave 1 (#291) extraction: the durable-write body previously inlined inside supersedeLocalFile's
167
+ * withSubjectLock() closure, now a parameter-driven pure function so ensure-session's
168
+ * `--supersede-stale` takeover path (workflow-sidecar.ts, Wave 2) can reuse the EXACT same
169
+ * supersede logic — from-actor holder verification, ttl/branch/artifact_dir carry-forward,
170
+ * audit-trail append, atomic write under withSubjectLock — rather than reimplementing a second,
171
+ * parallel supersede path. supersedeLocalFile (CLI wrapper, below) is now a thin
172
+ * parse-args/print-envelope shell around this.
173
+ */
174
+ export declare function performLocalSupersede(artifactRoot: string, subjectId: string, fromActor: ActorStruct, toActor: ActorStruct, opts?: {
175
+ ttlSeconds?: number;
176
+ branch?: string;
177
+ artifactDir?: string;
178
+ reason?: string;
179
+ actorKey?: string;
180
+ }): AssignmentClaimRecord;
181
+ /**
182
+ * Wave 1 (#291) extraction: the local-file branch of statusCommand's assignment-layer read,
183
+ * mirrored exactly so ensure-session's ownership guard (workflow-sidecar.ts, Wave 2) derives an
184
+ * AssignmentStatus identically to the `assignment-provider status` CLI command — a single
185
+ * implementation, not a second parallel local-file read.
186
+ */
187
+ export declare function readLocalAssignmentStatus(artifactRoot: string, subjectId: string): AssignmentStatus;
1
188
  export declare function main(argv?: string[]): number;
189
+ export {};