@kontourai/flow-agents 2.3.0 → 3.0.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/CODEOWNERS +16 -0
- package/.github/workflows/ci.yml +44 -0
- package/.github/workflows/trust-reconcile.yml +62 -4
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +62 -0
- package/CONTEXT.md +35 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/assignment-provider.d.ts +1 -0
- package/build/src/cli/assignment-provider.js +748 -0
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
- package/build/src/cli/effective-assignment-provider-settings.js +125 -0
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +27 -7
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +938 -168
- package/build/src/cli.js +6 -0
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +24 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +40 -7
- package/context/contracts/assignment-provider-contract.md +239 -0
- package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
- package/context/contracts/decision-registry-contract.md +265 -0
- package/context/contracts/delivery-contract.md +3 -1
- package/context/contracts/execution-contract.md +25 -0
- package/context/contracts/governance-adapter-contract.md +2 -0
- package/context/contracts/knowledge-store-contract.md +197 -0
- package/context/contracts/planning-contract.md +4 -1
- package/context/contracts/review-contract.md +7 -3
- package/context/contracts/sandbox-policy.md +2 -0
- package/context/contracts/standing-directives.md +13 -0
- package/context/contracts/verification-contract.md +11 -1
- package/context/contracts/work-item-contract.md +3 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/context/settings/assignment-provider-settings.json +33 -0
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +10 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +17 -0
- package/docs/decisions/knowledge-store-provider.md +51 -0
- package/docs/decisions/model-routing.md +63 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/decisions/standing-directives.md +66 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +4 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +3 -2
- package/docs/workflow-usage-guide.md +260 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +71 -1
- package/evals/fixtures/assignment-provider/actor-a.json +6 -0
- package/evals/fixtures/assignment-provider/actor-b.json +6 -0
- package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
- package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
- package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
- package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_assignment_provider_github.sh +318 -0
- package/evals/integration/test_assignment_provider_local_file.sh +222 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +23 -6
- package/evals/integration/test_pull_work_assignment_join.sh +132 -0
- package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +37 -13
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +11 -10
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +32 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
- package/evals/static/test_knowledge_providers.sh +23 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +32 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +148 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/knowledge/kit.json +35 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
- package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
- package/kits/knowledge/providers/conformance/suite.test.js +125 -0
- package/kits/knowledge/providers/git-repo/index.js +236 -0
- package/kits/knowledge/providers/health/health-pass.test.js +99 -0
- package/kits/knowledge/providers/health/index.js +153 -0
- package/kits/knowledge/providers/index.js +24 -0
- package/kits/knowledge/providers/lib/model.js +91 -0
- package/kits/knowledge/providers/lib/schema-validate.js +119 -0
- package/kits/knowledge/providers/markdown-vault/index.js +169 -0
- package/kits/knowledge/providers/work-item/index.js +204 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +11 -5
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/assignment-provider-settings.schema.json +125 -0
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/knowledge/edge.schema.json +54 -0
- package/schemas/knowledge/health-report.schema.json +45 -0
- package/schemas/knowledge/node.schema.json +49 -0
- package/schemas/knowledge/proposal.schema.json +53 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +957 -103
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/assignment-provider.ts +845 -0
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/effective-assignment-provider-settings.ts +112 -0
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +27 -7
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +933 -168
- package/src/cli.ts +6 -0
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +24 -1
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
* Workflow Steering Hook
|
|
4
4
|
*
|
|
5
5
|
* Injects phase-transition reminders after use_subagent calls complete and
|
|
6
|
-
*
|
|
6
|
+
* re-grounds the active workflow state at the start of every user turn and on
|
|
7
|
+
* SessionStart. SessionStart fires after context compaction and on resume, so
|
|
8
|
+
* re-injecting the goal/phase/next-step there is what makes an in-flight goal
|
|
9
|
+
* survive context loss instead of relying on the model voluntarily re-reading
|
|
10
|
+
* the sidecar.
|
|
7
11
|
*
|
|
8
12
|
* Non-blocking — always exits 0.
|
|
9
13
|
*/
|
|
@@ -12,6 +16,9 @@
|
|
|
12
16
|
|
|
13
17
|
const fs = require('fs');
|
|
14
18
|
const path = require('path');
|
|
19
|
+
const { readLivenessEvents, freshHolders } = require('./lib/liveness-read');
|
|
20
|
+
const { resolveActor } = require('./lib/actor-identity');
|
|
21
|
+
const { flowAgentsArtifactRootsForRead } = require('./lib/local-artifact-paths');
|
|
15
22
|
|
|
16
23
|
const STEERING = {
|
|
17
24
|
'tool-planner': [
|
|
@@ -96,7 +103,8 @@ function readJson(file) {
|
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
function latestWorkflowState(root) {
|
|
99
|
-
const states =
|
|
106
|
+
const states = flowAgentsArtifactRootsForRead(root)
|
|
107
|
+
.flatMap(artifactRoot => walkStateFiles(artifactRoot))
|
|
100
108
|
.map(file => {
|
|
101
109
|
let stat;
|
|
102
110
|
try { stat = fs.statSync(file); } catch { return null; }
|
|
@@ -198,6 +206,169 @@ function contextMapSteering(root) {
|
|
|
198
206
|
].join(' ');
|
|
199
207
|
}
|
|
200
208
|
|
|
209
|
+
function promptText(input) {
|
|
210
|
+
const candidates = [
|
|
211
|
+
input && input.prompt,
|
|
212
|
+
input && input.user_prompt,
|
|
213
|
+
input && input.message,
|
|
214
|
+
input && input.text,
|
|
215
|
+
input && input.tool_input && input.tool_input.prompt,
|
|
216
|
+
];
|
|
217
|
+
for (const candidate of candidates) {
|
|
218
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate;
|
|
219
|
+
}
|
|
220
|
+
return '';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function looksLikeBuilderWork(text) {
|
|
224
|
+
const normalized = safeStateText(text, 2000).toLowerCase();
|
|
225
|
+
if (!normalized) return false;
|
|
226
|
+
const readOnlyIntent = /\b(read[- ]only|review[- ]only|no (source |code |file )?(changes?|edits?|modifications?)|do not (modify|edit|change|write|fix|implement|touch)|don't (modify|edit|change|write|fix|implement|touch)|dont (modify|edit|change|write|fix|implement|touch))\b/.test(normalized);
|
|
227
|
+
if (readOnlyIntent) return false;
|
|
228
|
+
const questionOnlyIntent = /^(what|which|who|when|where|why|how)\b/.test(normalized);
|
|
229
|
+
if (questionOnlyIntent) return false;
|
|
230
|
+
const noCodeQuestion = /\b(explain|describe|summari[sz]e|what is|how does|how do i|why does|review|critique)\b/.test(normalized)
|
|
231
|
+
&& !/\b(build|create|implement|ship|deliver|fix|debug|refactor|add|update|change|modify|wire|migrate|install|scaffold|write|code)\b/.test(normalized);
|
|
232
|
+
if (noCodeQuestion) return false;
|
|
233
|
+
const verificationOnlyIntent = /\b(validate|test|verify|check)\b/.test(normalized)
|
|
234
|
+
&& !/\b(build|create|implement|ship|deliver|fix|debug|refactor|add|update|change|modify|wire|migrate|install|scaffold|write|code)\b/.test(normalized);
|
|
235
|
+
if (verificationOnlyIntent) return false;
|
|
236
|
+
const hasWorkVerb = /\b(build|create|implement|ship|deliver|fix|debug|refactor|add|update|change|modify|wire|migrate|install|scaffold|write|code)\b/.test(normalized);
|
|
237
|
+
const hasWorkObject = /\b(api|endpoint|component|feature|bug|failing test|regression|integration|hook|script|cli|config|schema|migration)\b/.test(normalized);
|
|
238
|
+
const hasRequestLanguage = /\b(can you|please|let's|lets|need|should|make|ensure|support|add|update|fix|work on)\b/.test(normalized);
|
|
239
|
+
return hasWorkVerb || (hasWorkObject && hasRequestLanguage);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function builderWorkflowSteering(input) {
|
|
243
|
+
if (!looksLikeBuilderWork(promptText(input))) return '';
|
|
244
|
+
return [
|
|
245
|
+
'BUILDER WORKFLOW ROUTE: this user prompt looks like coding/build work.',
|
|
246
|
+
'Builder lifecycle: shape raw ideas -> build selected work -> publish verified branch/PR -> learn correction feedback.',
|
|
247
|
+
'Before source edits or implementation commands, activate Builder Kit delivery workflow.',
|
|
248
|
+
'If the user explicitly requested TDD, activate `tdd-workflow`; otherwise activate `deliver` and keep the session on `builder.build`.',
|
|
249
|
+
'Use `npm run workflow:sidecar -- ensure-session --flow-id builder.build ...` when the repo provides the sidecar writer.',
|
|
250
|
+
'After local verification, continue to publish/release-readiness and learning-review; do not treat local verification as terminal delivery.',
|
|
251
|
+
'Do not bypass plan-work -> execute-plan -> review-work -> verify-work for coding tasks; direct implementation is only acceptable when the user explicitly asks for no workflow or explanation-only help.',
|
|
252
|
+
].join(' ');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Compose the RESUME block for SessionStart.
|
|
257
|
+
*
|
|
258
|
+
* Reads trust.bundle, handoff.json, and the liveness stream beside state.json;
|
|
259
|
+
* all reads are fail-open (errors → skip that section, never throw).
|
|
260
|
+
*
|
|
261
|
+
* Returns a multi-line string starting with "RESUME: <slug> status:<s> phase:<p>"
|
|
262
|
+
* or '' if the current state has status 'done', 'archived', or 'accepted'.
|
|
263
|
+
*
|
|
264
|
+
* @param {string} root Repository root
|
|
265
|
+
* @param {{ file: string, payload: object }} current Latest active state entry
|
|
266
|
+
* @returns {string}
|
|
267
|
+
*/
|
|
268
|
+
function resumeSteering(root, current) {
|
|
269
|
+
try {
|
|
270
|
+
const state = current.payload;
|
|
271
|
+
const workflowDir = path.dirname(current.file);
|
|
272
|
+
const slug = state.task_slug || path.basename(workflowDir);
|
|
273
|
+
const next = state.next_action || {};
|
|
274
|
+
|
|
275
|
+
if (next.status === 'done' || state.status === 'archived' || state.status === 'accepted') return '';
|
|
276
|
+
|
|
277
|
+
const lines = [];
|
|
278
|
+
|
|
279
|
+
// Header line
|
|
280
|
+
lines.push(`RESUME: ${slug} status:${safeStateText(state.status, 60)} phase:${safeStateText(state.phase, 60)}`);
|
|
281
|
+
|
|
282
|
+
// Full next action (240-char display path, not the 80-char normalization)
|
|
283
|
+
const nextSummary = next.summary ? safeStateText(next.summary, 240) : 'none';
|
|
284
|
+
lines.push(`Next action: ${nextSummary}`);
|
|
285
|
+
|
|
286
|
+
// Plan artifact path
|
|
287
|
+
let planPath = 'not found';
|
|
288
|
+
try {
|
|
289
|
+
const artifactPaths = Array.isArray(state.artifact_paths) ? state.artifact_paths : [];
|
|
290
|
+
const planEntry = artifactPaths.find(p => typeof p === 'string' && p.endsWith('--plan-work.md'));
|
|
291
|
+
if (planEntry) {
|
|
292
|
+
planPath = planEntry;
|
|
293
|
+
} else {
|
|
294
|
+
const candidate = path.join(workflowDir, `${slug}--plan-work.md`);
|
|
295
|
+
if (fs.existsSync(candidate)) planPath = candidate;
|
|
296
|
+
}
|
|
297
|
+
} catch { /* skip */ }
|
|
298
|
+
lines.push(`Plan: ${planPath}`);
|
|
299
|
+
|
|
300
|
+
// Handoff: next_steps[0] and blockers
|
|
301
|
+
let nextStep = 'none';
|
|
302
|
+
let blockers = 'none';
|
|
303
|
+
try {
|
|
304
|
+
const handoff = readJson(path.join(workflowDir, 'handoff.json'));
|
|
305
|
+
if (handoff) {
|
|
306
|
+
const steps = Array.isArray(handoff.next_steps) ? handoff.next_steps : [];
|
|
307
|
+
if (steps.length > 0) nextStep = safeStateText(String(steps[0]), 240);
|
|
308
|
+
const bArr = Array.isArray(handoff.blockers) ? handoff.blockers : [];
|
|
309
|
+
if (bArr.length > 0) blockers = bArr.map(b => safeStateText(String(b), 120)).join(', ');
|
|
310
|
+
}
|
|
311
|
+
} catch { /* skip */ }
|
|
312
|
+
lines.push(`Next step: ${nextStep}`);
|
|
313
|
+
lines.push(`Blockers: ${blockers}`);
|
|
314
|
+
|
|
315
|
+
// Trust bundle
|
|
316
|
+
try {
|
|
317
|
+
const bundle = readJson(path.join(workflowDir, 'trust.bundle'));
|
|
318
|
+
if (bundle) {
|
|
319
|
+
const claims = Array.isArray(bundle.claims) ? bundle.claims : [];
|
|
320
|
+
let verified = 0;
|
|
321
|
+
let disputed = 0;
|
|
322
|
+
const unresolved = [];
|
|
323
|
+
for (const claim of claims) {
|
|
324
|
+
if (!claim || typeof claim !== 'object') continue;
|
|
325
|
+
const status = String(claim.status || '');
|
|
326
|
+
if (status === 'verified') {
|
|
327
|
+
verified++;
|
|
328
|
+
} else if (status === 'disputed' || status === 'unknown') {
|
|
329
|
+
disputed++;
|
|
330
|
+
unresolved.push(claim);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const total = claims.length;
|
|
334
|
+
lines.push(`Trust: ${verified} verified / ${disputed} disputed / ${total} total`);
|
|
335
|
+
for (const claim of unresolved) {
|
|
336
|
+
const id = safeStateText(String(claim.id || ''), 120);
|
|
337
|
+
const st = safeStateText(String(claim.status || ''), 30);
|
|
338
|
+
lines.push(` - ${id} (${st}) → npm run workflow:sidecar -- claim ${id} ${workflowDir}`);
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
lines.push('Trust: no trust data available');
|
|
342
|
+
}
|
|
343
|
+
} catch { /* skip */ }
|
|
344
|
+
|
|
345
|
+
// Liveness advisory
|
|
346
|
+
try {
|
|
347
|
+
const resolved = resolveActor(process.env);
|
|
348
|
+
const selfActor = resolved.actor || 'local';
|
|
349
|
+
const events = flowAgentsArtifactRootsForRead(root)
|
|
350
|
+
.flatMap(artifactRoot => readLivenessEvents(path.join(artifactRoot, 'liveness', 'events.jsonl')));
|
|
351
|
+
if (events.length > 0) {
|
|
352
|
+
// selfActor (for exclusion matching) stays raw here; only the display strings pushed
|
|
353
|
+
// into `lines` are sanitized below, since holders come from the shared multi-writer
|
|
354
|
+
// liveness stream and must be treated as untrusted display input (#287 fix iteration 1).
|
|
355
|
+
const holders = freshHolders(events, slug, selfActor, Date.now());
|
|
356
|
+
for (const h of holders) {
|
|
357
|
+
lines.push(`[LIVENESS WARNING: another agent appears live on this work: actor ${safeStateText(h.actor)}, last seen ${h.lastAt}]`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
lines.push(`ACTOR: ${safeStateText(selfActor)} (${resolved.source})`);
|
|
361
|
+
} catch { /* skip */ }
|
|
362
|
+
|
|
363
|
+
// Pull-work route hint
|
|
364
|
+
lines.push('To continue: resume this work. Or run pull-work to assess WIP and start new/parallel work.');
|
|
365
|
+
|
|
366
|
+
return lines.join('\n');
|
|
367
|
+
} catch {
|
|
368
|
+
return '';
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
201
372
|
function run(rawInput) {
|
|
202
373
|
try {
|
|
203
374
|
const input = JSON.parse(rawInput);
|
|
@@ -217,9 +388,31 @@ function run(rawInput) {
|
|
|
217
388
|
shouldAppendWorkflowContext = hints.length > 0;
|
|
218
389
|
}
|
|
219
390
|
|
|
220
|
-
if (event === 'UserPromptSubmit'
|
|
221
|
-
|
|
222
|
-
|
|
391
|
+
if ((event === 'UserPromptSubmit' || event === 'SessionStart') && current) {
|
|
392
|
+
const stateHint = stateSteering(root);
|
|
393
|
+
if (stateHint) {
|
|
394
|
+
hints.push(stateNeedsAmbientSteering(current.payload)
|
|
395
|
+
? 'WORKFLOW STATE ATTENTION: current sidecars show unresolved workflow state at turn start.'
|
|
396
|
+
: 'WORKFLOW STATE: an active task is in progress — re-ground the recorded goal and resume the next step before doing anything else.');
|
|
397
|
+
hints.push(stateHint);
|
|
398
|
+
const contextHint = contextMapSteering(root);
|
|
399
|
+
if (contextHint) hints.push(contextHint);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (event === 'UserPromptSubmit') {
|
|
404
|
+
const builderHint = builderWorkflowSteering(input);
|
|
405
|
+
if (builderHint) {
|
|
406
|
+
hints.push(builderHint);
|
|
407
|
+
const contextHint = contextMapSteering(root);
|
|
408
|
+
if (contextHint) hints.push(contextHint);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// SessionStart only: append the RESUME block for richer situational awareness
|
|
413
|
+
if (event === 'SessionStart' && current) {
|
|
414
|
+
const resumeBlock = resumeSteering(root, current);
|
|
415
|
+
if (resumeBlock) hints.push(resumeBlock);
|
|
223
416
|
}
|
|
224
417
|
|
|
225
418
|
if (shouldAppendWorkflowContext) {
|
|
@@ -247,4 +440,17 @@ if (require.main === module) {
|
|
|
247
440
|
});
|
|
248
441
|
}
|
|
249
442
|
|
|
250
|
-
module.exports = {
|
|
443
|
+
module.exports = {
|
|
444
|
+
run,
|
|
445
|
+
stateSteering,
|
|
446
|
+
critiqueSteering,
|
|
447
|
+
contextMapSteering,
|
|
448
|
+
latestWorkflowState,
|
|
449
|
+
findRepoRoot,
|
|
450
|
+
safeStateText,
|
|
451
|
+
stateNeedsAmbientSteering,
|
|
452
|
+
resumeSteering,
|
|
453
|
+
promptText,
|
|
454
|
+
looksLikeBuilderWork,
|
|
455
|
+
builderWorkflowSteering,
|
|
456
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schemas/assignment-provider-settings.schema.json",
|
|
3
|
+
"schema_version": "1.0",
|
|
4
|
+
"projects": [
|
|
5
|
+
{
|
|
6
|
+
"project": {
|
|
7
|
+
"repo": {
|
|
8
|
+
"owner": "kontourai",
|
|
9
|
+
"name": "flow-agents",
|
|
10
|
+
"url": "https://github.com/kontourai/flow-agents"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"provider": {
|
|
14
|
+
"kind": "github",
|
|
15
|
+
"repo": {
|
|
16
|
+
"owner": "kontourai",
|
|
17
|
+
"name": "flow-agents",
|
|
18
|
+
"url": "https://github.com/kontourai/flow-agents"
|
|
19
|
+
},
|
|
20
|
+
"capabilities": ["assignees", "labels", "comments"]
|
|
21
|
+
},
|
|
22
|
+
"policy": {
|
|
23
|
+
"label_name": "agent:claimed",
|
|
24
|
+
"claim_comment_marker": "<!-- flow-agents:assignment-claim -->",
|
|
25
|
+
"human_assignee_policy": {
|
|
26
|
+
"behavior": "ask_first",
|
|
27
|
+
"idle_threshold_days": 3
|
|
28
|
+
},
|
|
29
|
+
"comment_refresh_on_phase_transition": false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -7,6 +7,8 @@ title: "ADR 0007: Flow / Skill / Kit / Tool Boundary"
|
|
|
7
7
|
**Date:** 2026-06-15
|
|
8
8
|
**Status:** Accepted
|
|
9
9
|
|
|
10
|
+
> **Cross-Kit Skill Sharing resolved by [ADR 0019](./0019-kit-dependency-ownership.md) (2026-07-01).** The "Cross-Kit Skill Sharing: DEFERRED" question below is resolved: the npm-dependency-style model (Kit B declares a peer dependency on Kit A and consumes its skills by reference) is adopted at the Flow Agents extension layer via a `kit.json` `dependencies` field. The single-kit-ownership principle recorded here still stands; only the deferral is lifted.
|
|
11
|
+
|
|
10
12
|
---
|
|
11
13
|
|
|
12
14
|
## Context
|
|
@@ -97,6 +97,41 @@ The broader boundary reconciliation (issue #174) is phased:
|
|
|
97
97
|
|
|
98
98
|
**Invariant that must survive migration (#183 Finding 2):** `WorkflowRun.status.conditions` are writable summaries; the gate re-derives from Hachure claims via Surface; `conditions[].evidenceRefs` cite claim IDs. **Do not fuse Resource and claim** — the separation (a friendly mutable surface over an un-gameable derived core) is the architecture.
|
|
99
99
|
|
|
100
|
+
### Status update (2026-07-01) — Tier 2 Phase 3 landed and hardened
|
|
101
|
+
|
|
102
|
+
**Phase 3 ("hooks") of the Tier 2 migration has landed — this is not an unfinished step.**
|
|
103
|
+
PRs #204–#209 (P-a through P-d, ADR 0016 Abstraction A) implemented the FlowDefinition →
|
|
104
|
+
enforcement bridge: P-a, a shared `src/lib/flow-resolver.ts` resolver
|
|
105
|
+
(`resolveActiveFlowStep`) that turns `(active_flow_id, active_step_id)` into a gate's
|
|
106
|
+
`expects[]`; P-b, declared-claim producers (`record-gate-claim` stamps kit-namespaced
|
|
107
|
+
claims per the active FlowDefinition's gate); P-c, gate enforcement in
|
|
108
|
+
`scripts/hooks/stop-goal-fit.js` reading `activeFlowStep.gateExpects[]` to select claims by
|
|
109
|
+
declared `claimType`; and P-d, `phase_map`-driven `advance-state --flow-definition` plus
|
|
110
|
+
retirement of the `-legacy` dual-emit shadow, so a live FlowDefinition-driven session emits
|
|
111
|
+
only kit-namespaced claims.
|
|
112
|
+
|
|
113
|
+
**It was then red-teamed in PR #215, which found the literal end-state unsafe.** The literal
|
|
114
|
+
Abstraction A text — declared-only enforcement, no `workflow.*` fallback — composed into a
|
|
115
|
+
HIGH-severity (OWASP A01/A04) gate-bypass chain: a forged `current.json` pointing at an
|
|
116
|
+
agent-authored `.flow.json` with an empty `expects: []` made the pure if/else selection logic
|
|
117
|
+
return `false` for every claim, silently skipping all re-derivation, tamper-detection, and
|
|
118
|
+
high/critical enforcement. PR #215 closed this by replacing the if/else with a **permanent
|
|
119
|
+
union-enforcement floor** — `workflow.*` claims are *always* enforced alongside whatever a
|
|
120
|
+
declared FlowDefinition adds, never instead of it — plus an empty-`expects[]`
|
|
121
|
+
`gate misconfiguration:` `HARD_BLOCK`. **This union floor and HARD_BLOCK are an intentional,
|
|
122
|
+
tested departure from Abstraction A's literal "instead of" wording, not an unfinished step
|
|
123
|
+
toward it, and must not be "completed" by removing them** (see ADR 0016 and ADR 0018, which
|
|
124
|
+
independently forbids adding new local `config-protection.js` patterns for this class of
|
|
125
|
+
vector and routes new self-tamper/kill-switch findings to Layer 4 instead).
|
|
126
|
+
|
|
127
|
+
**The one gap this left named and open — kit FlowDefinition files
|
|
128
|
+
(`kits/*/flows/*.flow.json`) had no CODEOWNERS coverage, so a narrowed-but-nonempty
|
|
129
|
+
`expects[]` edit had no owner-review trip-wire — is closed as of 2026-07-01, per ADR 0018
|
|
130
|
+
Decision #2** (a self-tamper/kill-switch vector routes to Layer 4 — CODEOWNERS + a required
|
|
131
|
+
regression test — not a new `config-protection.js` matcher). This closes the last open item
|
|
132
|
+
from this Reassessment's Phase 3; Phases 4–6 (resume/evals, retire sidecars, Flow kernel)
|
|
133
|
+
remain scoped as described above.
|
|
134
|
+
|
|
100
135
|
## Consequences
|
|
101
136
|
|
|
102
137
|
- **No bespoke trust-bundle schema validator in flow-agents.** Surface is the canonical
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "ADR 0019: Kit Dependency Ownership"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ADR 0019: Kit Dependency Ownership
|
|
6
|
+
|
|
7
|
+
**Date:** 2026-07-01
|
|
8
|
+
**Status:** Accepted
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
ADR 0007 ("Flow / Skill / Kit / Tool Boundary") left one question explicitly open under **Cross-Kit Skill Sharing: DEFERRED**: can a skill be shared across kits, and if so, how is that dependency declared and enforced? The motivating case is concrete and already live in this repository — the Builder Kit's `learning-review` skill invokes the Knowledge Kit's `knowledge-capture` skill (`kits/knowledge/skills/knowledge-capture/SKILL.md`) for durable knowledge storage. Today that cross-kit call is undeclared: nothing validates that Knowledge is present when Builder is installed or activated, so the dependency fails silently at agent-invocation time rather than loudly at install/activate time.
|
|
15
|
+
|
|
16
|
+
ADR 0007 named the leading candidate: *"an npm-dependency model: Kit B declares a peer dependency on Kit A and invokes Kit A's skills as a consumer, without absorbing them into Kit B's skill list."* It deferred adoption "until a concrete cross-kit case requires it." That case is now required, so this ADR resolves the deferral.
|
|
17
|
+
|
|
18
|
+
The open design question is **ownership**: does a cross-kit `dependencies` field belong in the Flow-owned container schema (`@kontourai/flow`'s `flow-kit-container.schema.json`), or in the Flow Agents extension layer?
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
**Kit `dependencies` lives entirely in the Flow Agents extension layer. No `@kontourai/flow` schema or code change is required or planned.**
|
|
25
|
+
|
|
26
|
+
The `dependencies` field is a `kit.json` array of `{ kit_id, reason? }` entries validated and enforced exclusively by Flow Agents code:
|
|
27
|
+
|
|
28
|
+
- **Shape** (`src/flow-kit/validate.ts` `parseKitDependencies`, wired into `validateKitRepository`): each entry must be an object with a kebab-case `kit_id` (`^[a-z][a-z0-9-]*$`), no self-reference, and no duplicate `kit_id`. `reason` is an optional string. Shape errors are hard errors at `flow-agents kit install` / `inspect` / `validate` time.
|
|
29
|
+
- **Install-time presence** (`src/cli/kit.ts`): a non-blocking warning is printed when a declared dependency is absent from the destination's **local** registry. This check is deliberately scoped to the local registry only (not the built-in catalog) — an accepted v1 limitation, documented, not hidden.
|
|
30
|
+
- **Activation-time presence** (`src/runtime-adapters.ts`): a **hard error** (non-zero exit) when a declared `kit_id` is absent from the union of built-in catalog kits and locally-installed kits at activation time.
|
|
31
|
+
|
|
32
|
+
### Grounding: why the extension layer, not Flow
|
|
33
|
+
|
|
34
|
+
Three independent lines of evidence put `dependencies` on the Flow Agents side of the boundary:
|
|
35
|
+
|
|
36
|
+
1. **The container schema already permits it, agent-blind.** `@kontourai/flow`'s `flow-kit-container.schema.json` declares `"additionalProperties": true` and states that *"Consumer products (such as Flow Agents) may define additional asset-class fields as extensions; unknown top-level fields are consumer extensions and core validation ignores-but-permits them."* A `dependencies` array is schema-legal in Flow today with zero Flow-side change. Flow's `validateKitContainer` only enforces `schema_version` / `id` / `name` / `flows`; it never touches unknown top-level fields.
|
|
37
|
+
|
|
38
|
+
2. **ADR 0008's Dividing Test lands it on Flow Agents.** ADR 0008 asks: *"Does the operation need to INTERPRET the agent extension (what a skill or adapter MEANS), or only the container ... Container-only → Flow. Extension-interpreting → Flow Agents."* A kit-to-kit dependency exists **only** because one kit's *skill* invokes another kit's *skill* — that is interpreting what a skill means, squarely on the Flow Agents side of the line. Flow's gate / FlowDefinition engine has no concept of "kit A needs kit B" and needs none to evaluate gates.
|
|
39
|
+
|
|
40
|
+
3. **There is an existing precedent for exactly this pattern.** `src/flow-kit/validate.ts` already derives K0/K1/K2 conformance and consumer targets purely from Flow Agents-owned code reading the same `kit.json` that Flow validates agent-blind. `dependencies` follows the identical pattern: a new Flow Agents-recognized (not Flow-recognized) metadata field, added to a `KNOWN_METADATA_FIELDS` allowlist so it is never misreported as an unknown third-party extension namespace.
|
|
41
|
+
|
|
42
|
+
### First declared dependency
|
|
43
|
+
|
|
44
|
+
`kits/builder/kit.json` declares `dependencies: [{ "kit_id": "knowledge", "reason": "learning-review invokes knowledge-capture ... for durable knowledge storage" }]`, making the previously-implicit Builder→Knowledge relationship explicit and enforceable.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Consequences
|
|
49
|
+
|
|
50
|
+
- **Single-repo change.** Because no cross-repo change is needed, there is no cross-repo prerequisite: everything lands in one `flow-agents` change. The Flow container contract is untouched.
|
|
51
|
+
- **Install stays non-blocking; activation is the hard gate.** Keeping install-time checks advisory avoids breaking a consumer repo that has forked/customized `kits/catalog.json`; activation-time enforcement is where a genuinely-missing dependency fails loudly. This split is itself documented in `docs/kit-authoring-guide.md`.
|
|
52
|
+
- **`dependencies` is metadata, not a K-level input.** It is presence/metadata, not evaluable-gate content, so it does NOT participate in K0/K1/K2 conformance scoring.
|
|
53
|
+
- **Not a package manager.** `dependencies` declares and validates presence; it does not fetch, resolve version ranges, or order installs. Version-range resolution and transitive-dependency graphs remain out of scope (a possible future extension, still extension-layer-owned by this decision).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## References
|
|
58
|
+
|
|
59
|
+
- [ADR 0007: Flow / Skill / Kit / Tool Boundary](./0007-flow-skill-kit-tool-boundary.md) — resolves its "Cross-Kit Skill Sharing: DEFERRED" question by adopting the npm-dependency-style model at the Flow Agents extension layer.
|
|
60
|
+
- [ADR 0008: Kit Operation Boundary](./0008-kit-operation-boundary.md) — the "Dividing Test" that locates extension-interpreting operations in Flow Agents.
|
|
61
|
+
- `@kontourai/flow`'s `flow-kit-container.schema.json` (`additionalProperties: true`, "ignores-but-permits" consumer extensions) and `validateKitContainer`.
|
|
62
|
+
- `src/flow-kit/validate.ts` (`parseKitDependencies`, `KNOWN_METADATA_FIELDS`, `deriveKitTargets`), `src/cli/kit.ts` (install-time warning), `src/runtime-adapters.ts` (activation-time enforcement).
|