@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.
- package/.github/workflows/ci.yml +12 -0
- package/CHANGELOG.md +32 -0
- package/CONTEXT.md +67 -1
- package/README.md +4 -0
- package/build/src/cli/assignment-provider.d.ts +188 -0
- package/build/src/cli/assignment-provider.js +193 -51
- package/build/src/cli/workflow-sidecar.d.ts +16 -6
- package/build/src/cli/workflow-sidecar.js +492 -45
- package/build/src/lib/flow-resolver.d.ts +12 -6
- package/build/src/lib/flow-resolver.js +30 -14
- package/build/src/tools/validate-source-tree.js +2 -1
- package/context/contracts/assignment-provider-contract.md +10 -1
- package/context/contracts/execution-contract.md +78 -0
- package/context/contracts/probe-docs-write-contract.md +187 -0
- package/context/scripts/hooks/config-protection.js +24 -4
- package/context/scripts/hooks/lib/config-protection-remedies.js +9 -0
- package/context/scripts/hooks/stop-goal-fit.js +262 -5
- package/context/scripts/hooks/workflow-steering.js +42 -0
- package/docs/adr/0001-flow-agents-consumes-flow.md +2 -0
- package/docs/adr/0002-flow-kits-as-extension-unit.md +2 -0
- package/docs/adr/0003-flow-agents-coordinates-kits-and-adapters.md +2 -0
- package/docs/adr/0004-gates-expect-surface-claims.md +2 -0
- package/docs/adr/0005-kubernetes-inspired-resource-contracts.md +2 -0
- package/docs/adr/0006-typescript-first-source-policy.md +2 -0
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0007-skill-audit.md +2 -0
- package/docs/adr/0008-kit-operation-boundary.md +2 -0
- package/docs/adr/0009-canonical-hook-core-kit-boundary.md +2 -0
- package/docs/adr/0010-workflow-trust-state-as-hachure-bundle.md +2 -0
- package/docs/adr/0011-mcp-posture.md +2 -0
- package/docs/adr/0012-agent-coordination-as-liveness-claims.md +2 -0
- package/docs/adr/0013-context-lifecycle.md +2 -0
- package/docs/adr/0014-core-vs-domain-kit-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +2 -0
- package/docs/adr/0016-three-hard-boundary-model.md +2 -0
- package/docs/adr/0017-anti-gaming-trust-security-model.md +2 -0
- package/docs/adr/0018-freeze-local-shell-heuristics.md +2 -0
- package/docs/adr/0019-kit-dependency-ownership.md +2 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +2 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +3 -1
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +113 -0
- package/docs/adr/README.md +49 -0
- package/docs/adr/index.md +34 -0
- package/docs/decisions/agent-coordination.md +20 -0
- package/docs/decisions/anti-gaming-trust-security.md +20 -0
- package/docs/decisions/context-lifecycle.md +18 -0
- package/docs/decisions/core-domain-kit-boundary.md +18 -0
- package/docs/decisions/flow-flow-agents-boundary.md +18 -0
- package/docs/decisions/flow-kit.md +20 -0
- package/docs/decisions/flow-skill-kit-tool-boundary.md +20 -0
- package/docs/decisions/graph-knowledge-provider.md +63 -0
- package/docs/decisions/hook-core-kit-boundary.md +18 -0
- package/docs/decisions/index.md +19 -0
- package/docs/decisions/kit-dependency-ownership.md +18 -0
- package/docs/decisions/kit-operation-boundary.md +18 -0
- package/docs/decisions/knowledge-promote-sub-flow.md +59 -0
- package/docs/decisions/kontour-resource-contract.md +18 -0
- package/docs/decisions/mcp-posture.md +18 -0
- package/docs/decisions/three-hard-boundary-model.md +18 -0
- package/docs/decisions/trust-reconcile.md +20 -0
- package/docs/decisions/typescript-source-policy.md +48 -0
- package/docs/decisions/workflow-enforcement.md +18 -0
- package/docs/decisions/workflow-trust-state.md +20 -0
- package/docs/fixture-ownership.md +1 -1
- package/docs/workflow-usage-guide.md +1 -1
- package/evals/ci/run-baseline.sh +6 -0
- package/evals/fixtures/assignment-provider/hostile-effective-state.json +11 -0
- package/evals/integration/test_checkpoint_signing.sh +4 -3
- package/evals/integration/test_current_json_per_actor.sh +516 -0
- package/evals/integration/test_ensure_session_ownership_guard.sh +435 -0
- package/evals/integration/test_gate_lockdown.sh +46 -0
- package/evals/integration/test_model_routing_escalation.sh +145 -0
- package/evals/integration/test_publish_delivery.sh +14 -6
- package/evals/integration/test_pull_work_liveness_preflight.sh +6 -1
- package/evals/integration/test_stop_hook_release.sh +552 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +170 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +12 -3
- package/evals/run.sh +10 -0
- package/evals/static/test_knowledge_providers.sh +13 -4
- package/evals/static/test_model_routing_hints.sh +107 -0
- package/evals/static/test_workflow_skills.sh +15 -2
- package/kits/builder/skills/builder-shape/SKILL.md +10 -0
- package/kits/builder/skills/deliver/SKILL.md +69 -11
- package/kits/builder/skills/design-probe/SKILL.md +47 -0
- package/kits/builder/skills/execute-plan/SKILL.md +13 -0
- package/kits/builder/skills/fix-bug/SKILL.md +17 -0
- package/kits/builder/skills/idea-to-backlog/SKILL.md +10 -0
- package/kits/builder/skills/pickup-probe/SKILL.md +4 -4
- package/kits/builder/skills/plan-work/SKILL.md +9 -0
- package/kits/builder/skills/pull-work/SKILL.md +10 -0
- package/kits/builder/skills/review-work/SKILL.md +11 -0
- package/kits/builder/skills/tdd-workflow/SKILL.md +17 -0
- package/kits/builder/skills/verify-work/SKILL.md +11 -0
- package/kits/knowledge/adapters/default-store/index.js +147 -18
- package/kits/knowledge/adapters/flow-runner/index.js +912 -16
- package/kits/knowledge/adapters/obsidian-store/index.js +97 -14
- package/kits/knowledge/adapters/shared/codec.js +265 -0
- package/kits/knowledge/docs/README.md +121 -2
- package/kits/knowledge/docs/store-contract.md +517 -7
- package/kits/knowledge/evals/audit-freshness/suite.test.js +92 -1
- package/kits/knowledge/evals/consolidate-incremental/suite.test.js +494 -0
- package/kits/knowledge/evals/consolidation/suite.test.js +1 -1
- package/kits/knowledge/evals/contract-suite/suite.test.js +212 -0
- package/kits/knowledge/evals/freshness/suite.test.js +339 -0
- package/kits/knowledge/evals/inbound-references/suite.test.js +351 -0
- package/kits/knowledge/evals/retirement/suite.test.js +1 -1
- package/kits/knowledge/evals/supersede-propagation/suite.test.js +384 -0
- package/kits/knowledge/flows/promote.flow.json +84 -0
- package/kits/knowledge/kit.json +15 -0
- package/kits/knowledge/promote/distill.js +96 -0
- package/kits/knowledge/promote/fixtures/contradiction-registry/CONTEXT.md +7 -0
- package/kits/knowledge/promote/fixtures/contradiction-registry/docs/decisions/cache-eviction-policy.md +12 -0
- package/kits/knowledge/promote/fixtures/contradiction-registry/docs/decisions/cache-eviction.md +12 -0
- package/kits/knowledge/promote/fixtures/repo/CONTEXT.md +11 -0
- package/kits/knowledge/promote/fixtures/repo/docs/decisions/index.md +9 -0
- package/kits/knowledge/promote/fixtures/repo/docs/decisions/liveness-claim.md +12 -0
- package/kits/knowledge/promote/fixtures/session/acceptance.json +9 -0
- package/kits/knowledge/promote/fixtures/session/agents/tool-planner/events.jsonl +1 -0
- package/kits/knowledge/promote/fixtures/session/agents/tool-verifier/events.jsonl +1 -0
- package/kits/knowledge/promote/fixtures/session/agents/tool-worker-1-1/events.jsonl +1 -0
- package/kits/knowledge/promote/fixtures/session/kontourai-flow-agents-287--deliver.md +47 -0
- package/kits/knowledge/promote/fixtures/session/learning.json +35 -0
- package/kits/knowledge/promote/fixtures/session/state.json +19 -0
- package/kits/knowledge/promote/health.js +137 -0
- package/kits/knowledge/promote/index.js +176 -0
- package/kits/knowledge/promote/ingest.js +103 -0
- package/kits/knowledge/promote/lib.js +132 -0
- package/kits/knowledge/promote/link.js +84 -0
- package/kits/knowledge/promote/promote.test.js +174 -0
- package/kits/knowledge/providers/conformance/suite.test.js +18 -0
- package/kits/knowledge/providers/index.js +1 -0
- package/kits/knowledge/providers/neo4j/connection.js +121 -0
- package/kits/knowledge/providers/neo4j/cypher.js +190 -0
- package/kits/knowledge/providers/neo4j/fake-driver.js +123 -0
- package/kits/knowledge/providers/neo4j/fixtures/spike-ground-truth.json +29 -0
- package/kits/knowledge/providers/neo4j/graph-queries.js +210 -0
- package/kits/knowledge/providers/neo4j/index.js +280 -0
- package/kits/knowledge/providers/neo4j/integration.test.js +122 -0
- package/kits/knowledge/providers/neo4j/neo4j.test.js +219 -0
- package/kits/knowledge/providers/neo4j/sync.js +235 -0
- package/package.json +4 -2
- package/schemas/workflow-handoff.schema.json +6 -0
- package/scripts/README.md +1 -0
- package/scripts/ci/mint-attestation.js +33 -6
- package/scripts/ci/trust-reconcile.js +144 -26
- package/scripts/freeze-adrs.mjs +364 -0
- package/scripts/hooks/config-protection.js +24 -4
- package/scripts/hooks/evidence-capture.js +4 -1
- package/scripts/hooks/lib/config-protection-remedies.js +9 -0
- package/scripts/hooks/lib/current-pointer.js +123 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +75 -35
- package/scripts/hooks/stop-goal-fit.js +262 -5
- package/scripts/hooks/workflow-steering.js +42 -0
- package/scripts/statusline/flow-agents-statusline.js +3 -1
- package/src/cli/assignment-provider.ts +239 -59
- package/src/cli/workflow-sidecar.ts +529 -43
- package/src/lib/flow-resolver.ts +35 -14
- package/src/tools/validate-source-tree.ts +2 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -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 {};
|