@kontourai/flow-agents 3.6.0 → 3.8.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 (96) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/src/builder-flow-run-adapter.d.ts +22 -2
  3. package/build/src/builder-flow-run-adapter.js +93 -28
  4. package/build/src/builder-flow-runtime.d.ts +8 -3
  5. package/build/src/builder-flow-runtime.js +407 -51
  6. package/build/src/cli/assignment-provider.d.ts +4 -7
  7. package/build/src/cli/assignment-provider.js +80 -14
  8. package/build/src/cli/builder-run.js +14 -18
  9. package/build/src/cli/workflow-sidecar.d.ts +28 -4
  10. package/build/src/cli/workflow-sidecar.js +825 -103
  11. package/build/src/cli/workflow.js +301 -43
  12. package/build/src/flow-kit/validate.d.ts +17 -0
  13. package/build/src/flow-kit/validate.js +340 -2
  14. package/build/src/index.js +5 -5
  15. package/build/src/lib/observed-command.d.ts +7 -0
  16. package/build/src/lib/observed-command.js +100 -0
  17. package/build/src/tools/build-universal-bundles.js +53 -3
  18. package/build/src/tools/generate-context-map.js +5 -3
  19. package/context/scripts/hooks/lib/kit-catalog.js +1 -1
  20. package/context/scripts/hooks/stop-goal-fit.js +78 -9
  21. package/docs/context-map.md +22 -20
  22. package/docs/developer-architecture.md +1 -1
  23. package/docs/getting-started.md +9 -1
  24. package/docs/public-workflow-cli.md +76 -7
  25. package/docs/skills-map.md +51 -27
  26. package/docs/spec/builder-flow-runtime.md +75 -40
  27. package/docs/workflow-usage-guide.md +109 -42
  28. package/evals/fixtures/hook-influence/cases.json +2 -2
  29. package/evals/integration/test_builder_entry_enforcement.sh +52 -41
  30. package/evals/integration/test_builder_step_producers.sh +330 -6
  31. package/evals/integration/test_bundle_install.sh +318 -65
  32. package/evals/integration/test_bundle_lifecycle.sh +4 -6
  33. package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
  34. package/evals/integration/test_current_json_per_actor.sh +12 -0
  35. package/evals/integration/test_dual_emit_flow_step.sh +62 -43
  36. package/evals/integration/test_flowdef_session_activation.sh +145 -25
  37. package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
  38. package/evals/integration/test_gate_lockdown.sh +3 -5
  39. package/evals/integration/test_goal_fit_hook.sh +60 -2
  40. package/evals/integration/test_install_merge.sh +18 -8
  41. package/evals/integration/test_liveness_verdict.sh +14 -17
  42. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
  43. package/evals/integration/test_public_workflow_cli.sh +334 -14
  44. package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
  45. package/evals/integration/test_sidecar_field_preservation.sh +36 -11
  46. package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
  47. package/evals/integration/test_workflow_steering_hook.sh +15 -38
  48. package/evals/run.sh +2 -0
  49. package/evals/static/test_builder_skill_coherence.sh +247 -0
  50. package/evals/static/test_library_exports.sh +5 -2
  51. package/evals/static/test_universal_bundles.sh +44 -1
  52. package/evals/static/test_workflow_skills.sh +13 -325
  53. package/kits/builder/flows/build.flow.json +22 -0
  54. package/kits/builder/flows/shape.flow.json +9 -9
  55. package/kits/builder/kit.json +70 -16
  56. package/kits/builder/skills/builder-shape/SKILL.md +75 -75
  57. package/kits/builder/skills/continue-work/SKILL.md +45 -106
  58. package/kits/builder/skills/deliver/SKILL.md +96 -442
  59. package/kits/builder/skills/design-probe/SKILL.md +40 -139
  60. package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
  61. package/kits/builder/skills/execute-plan/SKILL.md +54 -125
  62. package/kits/builder/skills/fix-bug/SKILL.md +42 -132
  63. package/kits/builder/skills/gate-review/SKILL.md +60 -211
  64. package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
  65. package/kits/builder/skills/learning-review/SKILL.md +63 -170
  66. package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
  67. package/kits/builder/skills/plan-work/SKILL.md +51 -185
  68. package/kits/builder/skills/pull-work/SKILL.md +136 -485
  69. package/kits/builder/skills/release-readiness/SKILL.md +66 -107
  70. package/kits/builder/skills/review-work/SKILL.md +89 -176
  71. package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
  72. package/kits/builder/skills/verify-work/SKILL.md +101 -113
  73. package/package.json +2 -2
  74. package/packaging/README.md +1 -1
  75. package/scripts/README.md +1 -1
  76. package/scripts/hooks/lib/kit-catalog.js +1 -1
  77. package/scripts/hooks/stop-goal-fit.js +78 -9
  78. package/scripts/install-codex-home.sh +63 -23
  79. package/scripts/install-owned-files.js +18 -2
  80. package/src/builder-flow-run-adapter.ts +118 -32
  81. package/src/builder-flow-runtime.ts +426 -64
  82. package/src/cli/assignment-provider-lock.test.mjs +83 -0
  83. package/src/cli/assignment-provider.ts +75 -14
  84. package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
  85. package/src/cli/builder-flow-runtime.test.mjs +436 -18
  86. package/src/cli/builder-run.ts +3 -9
  87. package/src/cli/kit-metadata-security.test.mjs +232 -6
  88. package/src/cli/public-api.test.mjs +15 -0
  89. package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
  90. package/src/cli/workflow-sidecar.ts +746 -103
  91. package/src/cli/workflow.ts +288 -41
  92. package/src/flow-kit/validate.ts +320 -2
  93. package/src/index.ts +6 -5
  94. package/src/lib/observed-command.ts +96 -0
  95. package/src/tools/build-universal-bundles.ts +51 -3
  96. package/src/tools/generate-context-map.ts +5 -3
@@ -1,512 +1,163 @@
1
1
  ---
2
2
  name: "pull-work"
3
- description: "Select ready GitHub issues from the executable backlog and prepare them for implementation. Use when choosing what to work on next, reviewing a kanban-style issue board, enforcing WIP limits, grouping issues, deciding worktree isolation, or handing selected work to plan-work."
3
+ description: "Select ready provider-backed work and prepare a bounded implementation handoff."
4
4
  ---
5
5
 
6
6
  # Pull Work
7
7
 
8
- Select ready backlog work and prepare a bounded execution handoff without implementing it.
8
+ Select ready backlog work and prepare a bounded handoff without implementing it.
9
9
 
10
- ## Contract
11
-
12
- - Use `context/contracts/work-item-contract.md` as the source vocabulary for provider-backed work item shape, provider roles, and capability flags.
13
- - Use `context/contracts/assignment-provider-contract.md` as the second source vocabulary for durable ownership: the `AssignmentProvider` operations (`claim`/`release`/`supersede`/`status`/`list`), the assignment ⋈ liveness join's effective-state enum (`held`/`reclaimable`/`human-held`/`free`), and the versioned claim-record format come from that contract, not from this skill.
14
- - `pull-work` may perform exactly two provider-adjacent writes at selection: the liveness claim (ADR 0012, ephemeral, local runtime presence stream — see "1a. Liveness Selection Preflight" / "Liveness Claim On Selection") and the durable assignment claim (`context/contracts/assignment-provider-contract.md`, GitHub assignee/label/comment or a local-file record — see "Assignment Claim On Selection"); no other provider mutation is added to this skill.
15
- - Read the configured backlog provider dynamically.
16
- - Select one issue or a coherent issue group.
17
- - Do not implement code.
18
- - Do not weaken scope to make execution easier.
19
- - Do not implement provider settings, provider configuration, or configured-provider discovery; this skill consumes configured provider state and helper outputs when available.
20
- - Do not reimplement Flow Definition validation or gate expectation semantics. When Flow Definition readiness is relevant, call Flow's validation surface (`flow validate-definition <path> [--json]` or `validateDefinitionWithDiagnostics`) and cite that result.
21
- - Do not pull unrelated ideas together just because they are nearby in the backlog.
22
- - Do not invoke `execute-plan`, `review-work`, `verify-work`, `evidence-gate`, or release skills.
23
- - Hand selected work to `plan-work` only after the pickup gate is satisfied and the user wants planning.
24
- - When the user wants to pick up work, enforce the full pull-work selection, WIP/shepherding, dependency, grouping, and worktree logic before any planning handoff.
25
- - Do not hand selected work to `plan-work` until a fresh pickup Probe record exists for the selected item or explicitly bundled group, unless the user is making a direct primitive-only `pull-work` request and explicitly wants the primitive to stop before planning.
26
- - Every pull-work artifact must correlate to selected backlog refs, shepherding refs for active PRs/sidecars/issues being finished before new work, or `backlog_gap=true` with a route to `idea-to-backlog`; direct audits with no new selection must record `shepherding_item_ids` or `backlog_gap`, not free-floating implementation scope.
27
- - A stale broad continuation instruction, such as "keep going", "pick up the next two", or "continue after merge", may allow queue inspection but must not bypass per-item pickup Probe evidence.
28
-
29
- ## Model Routing
30
-
31
- Board selection, WIP/shepherding scans, dependency joins, liveness preflight, and
32
- issue-sync-style bookkeeping are fully-specified mechanical work: when this skill
33
- delegates them, resolve the `delegate-mechanical` role from `.datum/config.json`
34
- (`npx @kontourai/datum resolve delegate-mechanical --json`) and pass the resolved
35
- model explicitly. See `context/contracts/execution-contract.md` § Delegation:
36
- Model Routing. Fallback: inherit the session model when datum/config is absent,
37
- noted in the artifact.
38
-
39
- ## Inputs
40
-
41
- - Repository or working directory.
42
- - Optional labels, milestone, project board, assignee, or priority filter.
43
- - Optional WIP limit or current in-progress context.
44
- - Existing `.kontourai/flow-agents/<slug>/` artifacts, PRs, and CI/review queues.
45
-
46
- ## Artifact Contract
47
-
48
- Create or update `.kontourai/flow-agents/<slug>/<slug>--pull-work.md` with:
49
-
50
- - `board_snapshot`: filters, issue list, labels, milestone/provider milestone state, project fields, state, blockers
51
- - `wip_assessment`: active work, reviews, verification, CI remediation, with personal WIP separated from global conflict context
52
- - `liveness_preflight`: per-candidate `{subjectId, state: held|reclaimable|human-held|free|mine, holder_actor?, status_raw, effective_reason?}` plus `self_actor`/`self_actor_source`, computed via `liveness status --json` + `liveness whoami --json` joined with `assignment-provider status`'s `effective_state`/`reason` (see "1a. Liveness Selection Preflight"); `self_actor` is captured exactly once per pull-work pass and pinned for reuse (see "1a. Liveness Selection Preflight" and "Liveness Claim On Selection" — never re-derived per claim call); this is now the **full** ADR 0021 §1 `assignment ⋈ liveness` join (previously liveness-only pending #290 — #290 has landed)
53
- - `reclaimable_override`: recorded only when a `reclaimable` (stale) candidate is selected, or when `--force`/an explicit user instruction overrides a `held` exclusion — the explicit opt-in decision and its stated reason (see "1a. Liveness Selection Preflight")
54
- - `liveness_claim`: per selected item, `{subjectId, actor, emitted_at, ttl_seconds}`; on any claim-emit failure, `{skipped: <stderr reason>}` instead — fail-open (never block selection on a liveness-emit failure) but never silent: the skip reason is also surfaced in pull-work's user-facing output, and an unresolved-actor failure additionally names the remediation (`--actor <id>` / `FLOW_AGENTS_ACTOR=<id>` / a supported runtime), matching ADR 0012; also carries an optional `post_claim_conflict: {other_actor, detected_at}` when the post-claim re-check (see "Post-Claim Conflict Re-check") detects a double-hold
55
- - `assignment_claim`: per selected item, `{provider: "github"|"local-file", subject_id, actor, command_evidence, confirmed_status}` — the durable-claim analog of `selected_item_ids`: provider kind, subject id, actor, the rendered/executed command evidence (`gh_commands`/`claim_comment_body` for `github`, the local-file `claim` invocation for `local-file`), and the confirmed `assignment-provider status` result for each selected item, recorded once the post-claim confirmation in "Assignment Claim On Selection" succeeds; see `context/contracts/assignment-provider-contract.md` for the underlying claim-record shape
56
- - `my_active_work`: local worktrees, dirty branches, open PRs by the current user, active sidecars, and in-flight review/verification/release work owned by the current user
57
- - `shepherding_candidates`: personal PRs, worktrees, or sidecars that should be reviewed, fixed, published, merged, abandoned, or cleaned before starting more work
58
- - `stale_worktrees`: worktrees with no open PR, no recent activity, merged/abandoned branches, or unclear ownership that need an explicit keep/remove decision
59
- - `open_prs_by_me`: open pull requests authored by the current user, including check/review state and whether they need shepherding
60
- - `global_conflicts`: open PRs, active work, or sidecars by others that overlap selected files, dependencies, release lanes, or provider state
61
- - `dependency_impacts`: blockers, blocked-by relationships, sequencing constraints, and work that should be prioritized because it unlocks or protects other work
62
- - `start_new_work_decision`: `proceed`, `shepherd_existing`, `cleanup_required`, `blocked`, or `needs_user`, with the reason and next action
63
- - `selection`: selected issue(s), rationale, priority, dependencies
64
- - `selected_item_ids`: provider or local backlog artifact refs selected for pickup, using neutral work item refs when available
65
- - `shepherding_item_ids`: active PR, sidecar, issue, worktree, or local backlog artifact refs being finished, reviewed, cleaned up, or unblocked before starting new work
66
- - `backlog_gap`: `true` only when no provider/local backlog item or shepherding item can anchor the artifact, with the gap reason
67
- - `backlog_gap_route`: route to `idea-to-backlog` or Builder Kit shape, including the prompt/context needed to create a local backlog artifact or provider-backed item
68
- - `selected_scope`: selected repository, work item refs, whether the selection is single-item, independent-items, or a justified Work Item Group, and the thinnest meaningful slice being handed to planning
69
- - `priority_rationale`: provider-neutral ranking reason, including delivery outcome, dependency unlocking, urgency, risk, size, readiness, and why higher-visible items were not selected
70
- - `dependencies`: known blockers, blocked-by items, dependency freshness, cross-repo sequencing constraints, and any dependency checks that are `NOT_VERIFIED`
71
- - `wip_conflict_notes`: personal WIP gate result, global WIP/conflict notes, file/provider-state/release-lane risks, and whether conflicts block, inform, or require isolation
72
- - `alignment_questions`: pickup Probe questions asked one at a time, recommended answer, user answer, unresolved question, or reason no question is needed
73
- - `grouping_check`: thinnest meaningful slice, bundle justification, dependency map, split/keep decision
74
- - `anchor`: objective, source artifacts, non-goals, done criteria
75
- - `work_scope`: allowed files/areas, risky areas, coordination notes
76
- - `worktree_decision`: yes/no, path/branch if known, rationale
77
- - `worktree_lifecycle`: path, branch, retain-until condition, cleanup owner, cleanup command, and whether cleanup is blocked by an open PR, review, CI, or user decision
78
- - `handoff`: recommended `plan-work` prompt and acceptance criteria
79
- - `pickup_gate`: pass/fail/block and reason
80
- - `pickup_probe`: for Builder Kit build flow only, the recorded Probe decisions, unresolved questions, accepted gaps, planning readiness, expected modified files, sandbox/worktree mode, and conflict risks that `plan-work` must consume
81
- - `builder_kit_handoff`: when Builder Kit build flow is active, machine-checkable fields `probe_status`, `probe_artifact_ref`, selected item ids, grouping decision, accepted gaps, route reason, and next action
82
-
83
- ## Workflow
84
-
85
- ### 1. Read Board State
86
-
87
- First inspect effective backlog provider settings when the repo provides them:
88
-
89
- ```bash
90
- npm run effective-backlog-settings -- --repo-path . --json
91
- ```
92
-
93
- If the command returns `status: configured`, use the returned `WorkItemProvider`, `BoardProvider`, filters, and WIP policy as the default board source. Preserve the provider source and settings path in the pull-work artifact. If it returns `status: ask_user` or the helper is unavailable, ask the user which backlog `WorkItemProvider` and `BoardProvider` to use before selecting work. Do not silently assume a repository, project, filters, labels, milestone, or WIP policy.
94
-
95
- Use `github-cli` / `gh` when available to inspect issues, labels, milestones, project fields, PR links, and blockers.
96
-
97
- Treat GitHub Issues as a `WorkItemProvider` and GitHub Projects as a `BoardProvider`, mapped through `context/contracts/work-item-contract.md`. Preserve provider-specific values in the artifact when useful, but use the contract's neutral fields for selection, grouping, and handoff.
98
-
99
- When a `BoardProvider` is configured, read the board Ready queue as the primary cross-repo selection input, ordered by configured priority and board position. Per-repo `WorkItemProvider` issue listing is the intake-gap detector: use it to surface open issues missing from the board, not as a silent fallback when the board has no ready items. If the configured board returns zero ready items, record and surface that warning as a dead readiness source before selecting or asking for alignment.
100
-
101
- Classify issues:
102
-
103
- - ready
104
- - blocked
105
- - stale
106
- - in progress
107
- - related-only
108
-
109
- When local JSON from `gh issue list/view --json ...` is available, normalize it through the helper before selection:
110
-
111
- ```bash
112
- npm run pull-work-provider -- \
113
- --settings-json context/settings/backlog-provider-settings.json \
114
- --issues-json /path/to/github-issues.json \
115
- --resolved-ref kontourai/flow#2=closed
116
- ```
117
-
118
- The helper preserves provider refs, project fields, blockers, PR links, and source artifact refs, then emits the work item contract fields plus readiness evidence. Use live provider state for final decisions; fixture output is only test evidence.
119
-
120
- When board state is available, read the Ready queue and intake gaps through the same helper:
121
-
122
- ```bash
123
- npm run pull-work-provider -- \
124
- --settings-json context/settings/backlog-provider-settings.json
125
- ```
126
-
127
- For fixture-backed evaluation or cached provider JSON, pass `--items-json /path/to/project-items-and-open-issues.json`. The board output includes `ready_queue`, `intake_gaps`, and `warnings`; select from `ready_queue` first when it is populated.
128
-
129
- Before classifying provider-backed work as ready for pickup, fetch the latest target ref when network access and provider credentials are available, then compare the current target SHA to the work item's `planned_base_sha`. Record the current target ref/SHA, planned base ref/SHA, `commits-since`, planned age, changed files since the planned base, and changed-file intersections with `planning_scope_refs` in the pull-work artifact or helper output.
130
-
131
- Classify revision freshness as:
132
-
133
- - `fresh`: the planned base matches the current target SHA, or the only newer commits/files are known not to affect the planning scope.
134
- - `drifted`: the target has moved, but changed files do not materially intersect `planning_scope_refs`; prompt alignment and record accepted decisions before planning may proceed.
135
- - `stale`: changed files intersect `planning_scope_refs`, contracts, dependencies, or expected execution areas enough that the issue may no longer describe the right slice; route back to `idea-to-backlog` instead of handing directly to `plan-work`.
136
-
137
- Missing `planned_base_sha` is not fresh. Record it as an explicit `NOT_VERIFIED` or accepted-gap baseline with the concrete fallback baseline used, such as current target ref/SHA plus provider history. Do not invent revision certainty for legacy work items.
138
-
139
- Return vague work to `idea-to-backlog` instead of inventing scope.
140
-
141
- ### 1a. Liveness Selection Preflight
142
-
143
- Resolve the current actor once per `pull-work` pass and pin it for reuse:
144
-
145
- ```bash
146
- npm run workflow:sidecar -- liveness whoami --json
147
- ```
148
-
149
- Capture the returned `actor` value as `self_actor` (and its `source` as `self_actor_source`) exactly once per pass. Reuse this pinned `self_actor` value explicitly via `--actor <self_actor>` on every subsequent `liveness claim` call in the same pass (see "Liveness Claim On Selection" below) — never re-derive the actor mid-pass, since ancestry/session-based resolution could otherwise resolve to a different value across separate calls within the same pass and silently defeat the "who am I" pinning this preflight depends on.
150
-
151
- Read the full liveness stream once per pass (omit `--subject` to get every row):
152
-
153
- ```bash
154
- npm run workflow:sidecar -- liveness status --json
155
- ```
156
-
157
- For each ready candidate, derive `subjectId` via:
158
-
159
- ```bash
160
- npm run workflow:sidecar -- resolve-slug <owner>/<repo>#<issue-number>
161
- ```
162
-
163
- then group all rows for that `subjectId` by subject (classify per subject, not per row), reading each row's raw `status` field (never `label`). Detect the liveness-only double-hold case first, before computing the full assignment ⋈ liveness join below: when a `verified` row for an actor other than self and a `verified` row for the resolved self actor both exist on the same subject, that is a double-hold — surface it as `held` plus an explicit conflict warning (per ADR 0012 §4 detection: "a false-stale double-hold ... is detected ... not prevented"), never silently resolve it to `mine`.
164
-
165
- Otherwise, compute the full ADR 0021 §1 `assignment ⋈ liveness` join per candidate via `assignment-provider status` (using the effective provider kind, repo, artifact root, `label_name`, and `claim_comment_marker` from `effective-assignment-provider-settings` — see "Assignment Claim On Selection" below — joined against the same liveness stream already read above):
166
-
167
- ```bash
168
- npm run assignment-provider -- status \
169
- --provider <github|local-file> \
170
- --subject-id <subjectId> \
171
- --liveness-stream <path-to-events.jsonl> \
172
- --self-actor <self_actor>
173
- # github: --issue-json <path-to-gh-issue-view-json|-> --label-name <label> --claim-comment-marker <marker>
174
- # local-file: --artifact-root <dir>
175
- ```
176
-
177
- Read the returned `.effective.effective_state` and `.effective.reason` and classify in this precedence order:
178
-
179
- 1. `effective_state: "held"` with `reason: "self_is_holder"` ⇒ `mine`: hand to `### 2. Enforce WIP And Shepherding`'s existing personal-WIP logic; do not re-offer as new, do not exclude as held-by-other.
180
- 2. else `effective_state: "held"` (`reason: "fresh_liveness_heartbeat"` or `"liveness_claim_present_assignment_lagging"`) ⇒ excluded from the ready set by default.
181
- 3. else `effective_state: "reclaimable"` ⇒ offered, flagged, with a warning; selecting it requires an explicit recorded opt-in (record in `reclaimable_override`, and/or `alignment_questions`), never a silent normal pick. On selecting a `reclaimable` candidate, run the **Takeover Protocol** (#294, ADR 0021 §5) below — takeover is resumption, not restart: grace-beat, supersede, then continue the incumbent's branch. Never auto-reclaim without the recorded opt-in.
182
- 4. else `effective_state: "human-held"` ⇒ surfaced, never auto-reclaimed (Design Decision 3 / ADR 0021 §6): record the assignee identity and idle duration (`effective.holder.assignee`, `effective.holder.idle_days`) in `alignment_questions` with a recommended answer (e.g. "assigned to `<assignee>`, idle `<idle_days>` days — reclaim?" recommending confirmation before proceeding), and select only on the user's explicit confirmation.
183
- 5. else `effective_state: "free"` ⇒ offered normally — including a `superseded` liveness row (no active assignment, no fresh liveness): now select-able via the **Takeover Protocol** below once the reclaimable/opt-in gate is satisfied (#294 implements the takeover semantics previously deferred here).
184
-
185
- An explicit user instruction to proceed despite a `held` or `reclaimable` classification (`--force`, "take it anyway", equivalent) overrides the exclusion/opt-in requirement; the override and its stated reason must be recorded in the artifact (`liveness_preflight`, `reclaimable_override`, and/or `priority_rationale`). A `human-held` classification is never overridden by `--force` alone — only the user's explicit answer to the recorded `alignment_questions` entry authorizes selecting it.
186
-
187
- This preflight now computes the **full** ADR 0021 §1 `assignment ⋈ liveness` join (previously liveness-only, pending #290): the assignment dimension is `#290`'s `AssignmentProvider` `status()` (`context/contracts/assignment-provider-contract.md`), joined against the same liveness stream this preflight already reads.
188
-
189
- #### Takeover Protocol (#294, ADR 0021 §5) — resumption, not restart
190
-
191
- When a `reclaimable` (or `superseded`-liveness) candidate is selected WITH the recorded opt-in, take it over by resuming the incumbent's work — never by starting a parallel branch or replanning. This is render-don't-execute: the CLI computes the decision and emits the exact steps; you run them.
192
-
193
- 1. **Preflight:** `npm run workflow:sidecar -- takeover-preflight .kontourai/flow-agents/<slug>`. It returns `{action, effective_state, holder, resume_branch, grace_seconds, next_steps}`. Only `action: "grace-then-supersede"` proceeds; `back-off` (incumbent live/revived) ⇒ STOP and reselect; `ask-first` (human-held) ⇒ do not proceed without the user's explicit answer.
194
- 2. **Grace beat:** wait `grace_seconds` (one heartbeat interval), then **re-run `takeover-preflight`**. If it now returns `back-off`, the incumbent revived — concede and reselect (this is the AC2 race guard). Proceed only if it is still `grace-then-supersede`.
195
- 3. **Supersede:** `npm run workflow:sidecar -- ensure-session … --supersede-stale`. It re-checks the state and REFUSES if the incumbent revived in the meantime (a live `held` is never superseded), records the audit trail ("superseded actor X, last seen T, resuming from trust bundle"), and prints `resumed_branch`.
196
- 4. **Resume the incumbent's branch — never a new one:** `git fetch origin <resume_branch> && git checkout <resume_branch>` (the `resume_branch` from step 1/3). Re-enter the existing artifact dir (the deterministic slug points at the same `.kontourai/flow-agents/<slug>/`); restore the durable record via the resume surface (#153) and continue from `handoff.json`/plan — do NOT re-plan or restart.
197
- 5. **Record** the takeover (superseded actor, `resume_branch`, grace outcome) in `reclaimable_override`. If the superseded incumbent later wakes, it is blocked at publish by the verify-hold gate (#293) — the takeover is authoritative.
198
-
199
- `liveness claim`/`status`/`whoami` read/write the local runtime liveness stream, never GitHub issue/label/assignee state — this is not a provider mutation, and the two-provider-writes-only invariant in `## Contract` is unchanged by this slice. `#290` adds the one narrow, audited durable assignment claim that pairs with this liveness emit — see "Assignment Claim On Selection" below.
200
-
201
- ### 2. Enforce WIP And Shepherding
202
-
203
- Before selecting new work, check whether review, verification, release, or CI remediation is congested. Separate the current user's active work from global conflict context.
204
-
205
- Personal WIP scan:
206
-
207
- - Inspect local worktrees and branches for dirty state, unpublished commits, merged branches, abandoned branches, and unclear ownership.
208
- - Inspect open PRs authored by the current user and record review/check state, requested changes, mergeability, and whether the PR needs shepherding.
209
- - Inspect active `.kontourai/flow-agents/<slug>/` sidecars owned by the current user or current session, especially `planning`, `planned`, `in_progress`, `verifying`, `needs_decision`, `not_verified`, `failed`, and `blocked`.
210
- - Classify personal items into `my_active_work`, `shepherding_candidates`, `stale_worktrees`, and `open_prs_by_me`.
211
-
212
- Global conflict scan:
213
-
214
- - Inspect open PRs, active work, and known sidecars from other owners only for file overlap, dependency, sequencing, release-lane, provider-state, or artifact-contract risk.
215
- - Record those risks in `global_conflicts` and `dependency_impacts`; do not block just because other people have work in progress.
216
-
217
- Default policy:
218
-
219
- - Prefer finishing active work over starting new work.
220
- - Personal WIP may block new work when it exceeds the WIP policy, needs review/CI shepherding, has dirty worktrees, or has unresolved verification/release decisions.
221
- - Other people's WIP blocks only when it creates concrete file-scope conflict, dependency, sequencing, release, provider-state, or artifact-contract risk for the selected item.
222
- - Do not pull new implementation work when verification/evidence gates are overloaded.
223
- - Prefer shepherding an already-open personal PR over starting new implementation when the PR is near merge or needs only checks/review/fixes.
224
- - Return vague or stale issues to `idea-to-backlog`.
225
- - Do not select work that conflicts with another active TODO's `modified_files` unless isolation or sequencing is recorded.
226
- - Always record `start_new_work_decision` before selection handoff. If the decision is not `proceed`, stop with the shepherding, cleanup, blocker, or user-decision next action.
227
-
228
- ### 3. Select Work
229
-
230
- Choose one issue or coherent group based on:
231
-
232
- - priority
233
- - milestone / delivery outcome alignment
234
- - dependency unlocking
235
- - risk
236
- - size
237
- - readiness
238
- - owner / agent availability
239
- - parallelism opportunity
240
-
241
- Prefer the smallest coherent unit that can reach evidence and release readiness without leaving dependent half-work.
242
-
243
- ### Cross-Repo Ranking And Selection
244
-
245
- When the backlog spans related repositories or product areas, use provider-neutral cross-repo ranking before selection. Compare work items by normalized work item refs from `context/contracts/work-item-contract.md`, not by provider-specific board mechanics. Preserve provider-specific details as evidence, but do not mutate GitHub Projects, provider fields, or cross-repo provider state from this skill.
246
-
247
- Rank candidates by:
248
-
249
- - delivery outcome alignment, including milestone, release lane, dogfood target, or explicit user priority
250
- - dependency unlocking or protection across repositories
251
- - readiness, acceptance criteria quality, dependency freshness, and provider state
252
- - risk, size, reversibility, and ability to produce evidence without dependent half-work
253
- - personal WIP, global conflicts, release-lane conflicts, and file/provider-state overlap
254
- - owner or agent availability and whether the work is appropriate for the current sandbox/worktree mode
255
-
256
- The output must make the ranking decision reviewable. Record `selected_scope`, `priority_rationale`, `dependencies`, `wip_conflict_notes`, and `alignment_questions` even when the selection is a single issue. Include why visible alternatives were deferred when they outrank the selected item on one dimension but lose on readiness, dependency, WIP, or scope fit. If ranking cannot be completed from available provider context, ask one alignment question or record the unknown as a blocker or accepted gap before planning.
257
-
258
- Default to one thinnest meaningful slice. A Work Item Group selection requires explicit justification in `grouping_check` and `selected_scope`; do not group items merely because they share a milestone, label, repository family, or theme.
259
-
260
- For issue groups, require an explicit grouping check:
261
-
262
- - the group shares one user outcome and acceptance signal, or
263
- - one issue hard-blocks another and the dependency sequence is recorded, or
264
- - splitting would create unsafe or unusable partial delivery.
265
-
266
- If the relationship is only thematic, split the work and select the thinnest meaningful slice instead.
10
+ ## Role And Binding
267
11
 
268
- ### Selection Examples
12
+ - **Role:** canonical Builder build-step producer.
13
+ - **Binding:** `builder.build` step `pull-work`.
14
+ - **Produces:** `<slug>--pull-work.md` and, for an active matching run, the `selected-work` expectation.
15
+ - **Standalone no-run behavior:** inspect and select work as a direct primitive, then return the artifact. Do not start a Builder run, record Builder evidence, or represent selection as an active-flow gate pass.
269
16
 
270
- Use these compact examples as the expected artifact shape when selecting or rejecting cross-repo work:
271
-
272
- - **independent docs work**: `selected_scope`: single-item docs update in `kontourai/flow-agents`; `priority_rationale`: small, ready, improves workflow discoverability, and does not block runtime delivery; `dependencies`: none known; `wip_conflict_notes`: no personal WIP block and no global file overlap; `grouping_check`: single-item, no Work Item Group; `alignment_questions`: none needed because scope and docs target are explicit.
273
- - **Resource Contract audit work**: `selected_scope`: single-item audit of the Resource Contract guidance across the owning repo and referenced docs; `priority_rationale`: selected because it protects later implementation work and resolves contract drift before code changes; `dependencies`: requires current contract docs and provider refs to be fresh, with unknown external repo state recorded as `NOT_VERIFIED` if not checked; `wip_conflict_notes`: block if another active task edits the same contract, otherwise record as global context; `grouping_check`: do not bundle fixes unless the issue explicitly requires audit plus remediation; `alignment_questions`: ask whether to stop at audit evidence or include narrowly scoped doc fixes, with a recommended answer.
274
- - **dogfood-alpha implementation work**: `selected_scope`: single-item implementation slice in the dogfood-alpha milestone; `priority_rationale`: high delivery alignment and unlocks product dogfood evidence, but only selected if dependencies are closed or explicitly accepted; `dependencies`: list blocked-by issues, required artifacts, and pickup Probe freshness; `wip_conflict_notes`: require worktree isolation when implementation overlaps active files or release lanes; `grouping_check`: Work Item Group only when one item hard-blocks the implementation and the dependency sequence is part of the same acceptance signal; `alignment_questions`: ask the narrow scope question before `plan-work` if the issue could expand into provider adapters or runtime orchestration.
275
- - **blocked cross-product dependency**: `selected_scope`: no implementation selection; `priority_rationale`: defer because a higher-priority item in another product/repo is blocked by an unresolved dependency or missing provider state; `dependencies`: name the blocker, owner/repo when known, and freshness check; `wip_conflict_notes`: record any release-lane or provider-state conflict as the reason to stop; `grouping_check`: unsafe-group unless explicit dependency sequencing and shared acceptance justify a bundle; `alignment_questions`: ask whether to shepherd/unblock the dependency, return to shaping, or choose the next ready independent item.
276
-
277
- ### Liveness Claim On Selection
278
-
279
- Once `selected_item_ids` is finalized at the end of `### 3. Select Work`, before handoff to `plan-work`, for each selected item run:
280
-
281
- ```bash
282
- npm run workflow:sidecar -- liveness claim <subjectId> --actor <self_actor>
283
- ```
284
-
285
- using the same `subjectId` computed via `resolve-slug` during the preflight, and the same pinned `self_actor` captured once from `liveness whoami --json` at the start of this pass (`### 1a. Liveness Selection Preflight`) — always pass `--actor <self_actor>` explicitly on every claim in this pass; never a fresh derivation per claim call.
286
-
287
- Record the result in `liveness_claim` as `{subjectId, actor, emitted_at, ttl_seconds}`. On any claim-emit failure (non-zero exit, unresolved actor, or liveness disabled/unavailable), record `{skipped: <stderr reason>}` in `liveness_claim` instead — fail-open, never block selection on a liveness-emit failure — and also surface that skip reason in pull-work's user-facing output; never silent. When the failure is specifically an unresolved-actor failure, additionally name the remediation (`--actor <id>` / `FLOW_AGENTS_ACTOR=<id>` / a supported runtime), matching `liveness claim`'s own error message.
288
-
289
- ### Post-Claim Conflict Re-check
290
-
291
- After emitting claims for the selected item(s) above, re-read liveness status for those same subjects:
292
-
293
- ```bash
294
- npm run workflow:sidecar -- liveness status --json --subject <subjectId>
295
- ```
296
-
297
- If another actor's fresh (`verified`) claim now coexists with this session's own just-emitted claim on the same subject — a double-hold, per ADR 0012 §4 ("a false-stale double-hold (two fresh claims on one subject) is detected ... via Hachure `conflictRules`/`conflictedClaims`, not prevented") — surface the conflict prominently in the user-facing output and instruct the user to coordinate before proceeding; do not silently continue as if the selection were exclusive. Record the detected conflict in `liveness_claim`'s `post_claim_conflict` field.
298
-
299
- When a double-hold is detected, immediately run the deterministic tiebreaker using the same pinned `self_actor` and the same `subjectId` already in scope:
300
-
301
- ```bash
302
- npm run workflow:sidecar -- liveness verdict <subjectId> --json
303
- ```
304
-
305
- `liveness verdict` is a read-only, lock-free CLI action that computes `{subjectId, winner, losers, reason, holders}` as a pure function of the shared liveness stream: among the subject's currently-fresh claim holders, the one whose current `claim` event has the earliest `at` wins; an exact-timestamp tie breaks by ascending actor-id string comparison (`reason: "tie-actor-lexicographic"`) — the SAME verdict for the SAME stream state regardless of which actor invokes it.
306
-
307
- Branch on the returned `winner.actor`:
308
-
309
- - If `winner.actor !== self_actor`, this session is the loser: immediately run `npm run workflow:sidecar -- liveness release <subjectId> --actor <self_actor>`, extend `post_claim_conflict` with `{verdict_reason, winner_actor, conceded: true}`, and return to `### 3. Select Work` to reselect within the same `pull-work` pass — excluding the just-released subject — before any handoff to `plan-work`.
310
- - If `winner.actor === self_actor`, this session wins: record the verdict for transparency (`{verdict_reason, winner_actor: self_actor, conceded: false}`) in `post_claim_conflict` and proceed normally; do not release.
311
-
312
- Honesty note: this re-check narrows, but does not close, the read-then-write race between the preflight's read and the claim's write. The verdict-and-release loop above closes the "detected but advisory-only" gap ADR 0012 §4 names for THIS session's own double-hold — the loser deterministically concedes and re-selects within the same pass, a new convergence guarantee this slice adds — but it still does not provide true mutual exclusion across the read-then-write race window itself; that residual is unchanged from before. `#290`'s provider assignment lease closes this gap for the **local-file** provider only: `claim`/`release`/`supersede` there are wrapped in a per-subject `mkdir`-lock (atomic create, EEXIST-spin, staleness reclaim), so two concurrent local-file `claim` calls on the same subject genuinely cannot both win — true mutual exclusion, not just detection. The **GitHub** provider (assignee/label/claim-comment) remains advisory/last-writer: `render-claim`/`render-supersede` emit `gh` argv for the calling skill to run, and nothing about a GitHub issue's assignee/label/comment state gives atomic compare-and-swap across two concurrent skill invocations — the post-claim `status` re-check above still only *detects* a lost race after the fact, it does not *prevent* one. Do not read "provider assignment lease" as closing the GitHub race; only the `verify-hold` publish gate (#293), not yet implemented, would do that for GitHub.
313
-
314
- ### Assignment Claim On Selection
315
-
316
- After the post-claim liveness conflict re-check above resolves (no double-hold detected, or this session won the deterministic tiebreaker and any loser has reselected) and `selected_item_ids` is otherwise ready to finalize, perform the durable assignment claim — the second and last provider-adjacent write this skill performs (see `## Contract`) — before recording `selected_item_ids` as final and before any handoff to `plan-work`.
317
-
318
- Resolve the effective assignment provider settings once per pass:
319
-
320
- ```bash
321
- npm run effective-assignment-provider-settings -- --repo-path . --json
322
- ```
323
-
324
- If the result is `status: ask_user`, ask the user which `AssignmentProvider` (`github` or `local-file`) to use before claiming; do not silently assume. If `status: configured`, use the returned `settings.provider.kind`, `settings.provider.repo`, `settings.policy.label_name`, and `settings.policy.claim_comment_marker` for every call below.
325
-
326
- For each selected item's `subjectId` (the same `subjectId` resolved via `resolve-slug` and used throughout this pass):
327
-
328
- - **`kind: "github"`**: build an `--input-json` payload with `repo` (`{owner, name}`), `issue_number`, `assignee_login` (the current actor's GitHub login when known), `existing_assignee_login` and `existing_comment_id` (only when superseding an already-recorded `reclaimable`/confirmed `human-held` candidate — otherwise omit), `label_name`, `claim_comment_marker`, `ttl_seconds`, `branch`, and `artifact_dir`, then render:
329
-
330
- ```bash
331
- npm run assignment-provider -- render-claim \
332
- --provider github \
333
- --subject-id <subjectId> \
334
- --input-json <path> \
335
- --actor-json <path>
336
- ```
337
-
338
- Execute every command in the returned `gh_commands` array **verbatim** via the Bash tool, in order — never freehand `gh` text. Each `gh_commands` entry is an **argv array** (one element per argument, e.g. `["gh", "issue", "comment", "9101", "--repo", "kontourai/flow-agents", "--body", "..."]`) and MUST be executed as argv — every element passed as its own separate Bash-tool argument — **never** concatenated into a single shell-command string, and **never** run via `bash -c "..."` or any other shell re-interpretation of the joined elements. `claim_comment_body` (and, when superseding, `previous_record`) can carry attacker-influenced text (see the GitHub claim-record sanitization note in `context/contracts/assignment-provider-contract.md`); concatenating argv elements into a shell string before execution would reintroduce a shell-injection surface this render/execute split is designed to avoid. Record the rendered `record`, `claim_comment_body`, and each executed `gh_commands` entry as evidence.
339
-
340
- - **`kind: "local-file"`**: call the local-file `claim` subcommand directly — no render step, since this is the one path that performs real I/O inside the CLI itself:
341
-
342
- ```bash
343
- npm run assignment-provider -- claim \
344
- --provider local-file \
345
- --artifact-root <artifact-root> \
346
- --subject-id <subjectId> \
347
- --branch <branch> \
348
- --artifact-dir <artifact_dir> \
349
- --actor-json <path>
350
- ```
351
-
352
- A non-zero exit (already claimed by a different actor) must not be silently retried or overwritten — treat it exactly like a `held`/`reclaimable` conflict and return to `### 3. Select Work` to reselect.
353
-
354
- Then, regardless of provider kind, re-fetch current state — re-fetch the GitHub issue via `gh issue view --json assignees,labels,comments` for `github` (the local-file record is already current on disk) — and call `assignment-provider status` again, passing the same pinned `self_actor`, to **confirm** the claim landed before treating `selected_item_ids` as final:
355
-
356
- ```bash
357
- npm run assignment-provider -- status --provider <github|local-file> --subject-id <subjectId> --self-actor <self_actor> ...
358
- ```
359
-
360
- Confirm `effective.effective_state === "held"` with `effective.reason === "self_is_holder"` (the join function's signal that this session's own actor is the confirmed holder). Only after this confirmation does `selected_item_ids` become final for handoff. If confirmation fails — the claim did not land, or a different actor's record now appears — treat this exactly like a liveness double-hold: do not proceed to `plan-work` with this subject; return to `### 3. Select Work` to reselect, excluding the contested subject.
361
-
362
- Record the render/status evidence — provider kind, subject id, actor, the rendered/executed command(s), and the confirmed `status()` result — for every selected item under `selection` and in the dedicated `assignment_claim` artifact field (see Artifact Contract above).
363
-
364
- ### 4. Anchor Check
365
-
366
- Before planning, restate:
367
-
368
- - selected issue links
369
- - objective
370
- - authoritative artifacts
371
- - milestone or delivery outcome, including whether it is a real provider milestone, a project field, a label, or intentionally unset
372
- - non-goals
373
- - current gate
374
- - allowed file/work scope
375
- - done criteria
376
- - expected verification/evidence/release gates
377
-
378
- ### 5. Worktree Decision
379
-
380
- Use `context/contracts/sandbox-policy.md` for the broader execution boundary decision. `pull-work` owns the first `sandbox_mode` recommendation; `execute-plan` may upgrade it if risk increases.
381
-
382
- Strongly consider isolated worktrees, especially for:
383
-
384
- - parallel agent execution
385
- - risky refactors
386
- - prototype/MVP work
387
- - multiple agents in one repo
388
- - large dependency or migration changes
389
-
390
- Record:
391
-
392
- - sandbox_mode: `local-read-only`, `local-edit`, `worktree`, `container`, `cloud-sandbox`, or `privileged-integration`
393
- - worktree used: yes/no
394
- - path or branch when known
395
- - rationale
396
- - worktree lifecycle:
397
- - `retain_until`: `pr_merged`, `branch_abandoned`, `user_override`, or a documented equivalent
398
- - `cleanup_owner`: user, orchestrator, or named agent role
399
- - `cleanup_command`: usually `git worktree remove <path>` after merge/abandonment and optional branch deletion when safe
400
- - `cleanup_blocked_by`: open PR, pending review, pending CI, dirty files, unpublished commits, or user decision
401
-
402
- If not using a worktree, state why shared-workspace execution is acceptable.
403
-
404
- Publishing a branch must retain the worktree for review, CI, and follow-up fixes. Final acceptance, release cleanup, or explicit abandonment owns worktree removal. Do not copy files back into the main checkout by hand; Git is the merge surface.
405
-
406
- ### 6. Handoff
407
-
408
- Then invoke or recommend `plan-work` only when the user wants execution planning to begin.
409
-
410
- ### Builder Kit Pickup Probe Handoff
411
-
412
- Direct `pull-work` remains a standalone primitive: it may select work, write the pull-work artifact, and stop at a `plan-work` handoff without invoking the productized Builder Kit build flow.
413
-
414
- For productized pickup, selected work routes through the `design-probe` step as `pickup-probe` before planning. This applies to Builder Kit `build` flow and to "pick up work and build it" requests that intend to continue into delivery. Do not let `plan-work` proceed until the pull-work or plan handoff artifact records the pickup Probe outcome:
415
-
416
- - goal fit and scope
417
- - blockers and dependencies
418
- - dependency freshness
419
- - acceptance criteria quality
420
- - provider state
421
- - risk and stop-short risks
422
- - sandbox/worktree mode
423
- - expected modified files and conflict risks
424
- - planning readiness
425
- - decisions, unresolved questions, and any accepted gaps
426
-
427
- Record these machine-checkable handoff fields for every selected productized pickup item or bundle:
428
-
429
- - `probe_status`: `missing`, `required`, `in_progress`, `passed`, `accepted_gap`, or `blocked`
430
- - `probe_artifact_ref`: path to the pull-work section or Builder Kit Probe sidecar that contains the pickup Probe evidence
431
- - `selected_item_ids`: neutral work item refs from `context/contracts/work-item-contract.md`
432
- - `grouping_decision`: `single-item`, `independent-items`, `justified-bundle`, `unsafe-group`, or `empty-board`
433
- - `accepted_gaps`: known gaps explicitly accepted for this planning pass
434
- - `route_reason` and `next_action`
435
-
436
- Ask one alignment question at a time only when repo/provider context leaves a genuine decision gap. Include a recommended answer with that question. If the user accepts proceeding despite an unresolved question, record the unresolved question as an accepted gap in the handoff artifact before planning.
437
-
438
- For productized pickup handoff, route `decision_gap` back to `design-probe`; for pickup/planning gaps, that means returning to this pickup Probe record before retrying `plan-work`.
439
-
440
- If a direct `pull-work` invocation has enough primitive inputs but no productized build intent, stop after the handoff and report the expected next step. If the user then asks to continue into build or delivery, route to `design-probe` / `pickup-probe` before planning.
441
-
442
- If no ready backlog item exists, route to Builder Kit shape / `idea-to-backlog` instead of inventing implementation work.
443
-
444
- Direct pull-work audits that inspect WIP, PRs, sidecars, or board state without selecting new implementation work are valid only when the artifact records `shepherding_item_ids` for the active items being finished or `backlog_gap=true` plus `backlog_gap_route` to `idea-to-backlog`. They must stop at shepherding, cleanup, blocker, or shaping guidance and must not create free-floating implementation scope.
445
-
446
- ## Pickup Gate
447
-
448
- Selected work is ready when:
17
+ ## Contract
449
18
 
450
- - `selected_item_ids` records the selected provider/local backlog item refs, or `shepherding_item_ids` records the active PR/sidecar/issue refs being finished before new work, or `backlog_gap=true` records the route to `idea-to-backlog`
451
- - issue scope is clear
452
- - acceptance criteria exist
453
- - dependencies are known
454
- - selected issue group has explicit bundle justification or is split to one thinnest meaningful slice
455
- - multi-item selection records independence or bundle justification and expected conflict risks
456
- - owner/agent path is clear
457
- - worktree decision is recorded
458
- - worktree lifecycle is recorded when a worktree is used
459
- - personal WIP/shepherding scan is recorded
460
- - global conflicts and dependency impacts are recorded
461
- - `start_new_work_decision` is `proceed` or an explicit accepted gap allows pickup to continue
462
- - no higher-priority blocked verification work should be finished first
463
- - conflict risk with active TODOs is recorded
19
+ - Use `context/contracts/work-item-contract.md` and `context/contracts/assignment-provider-contract.md` as the source vocabulary.
20
+ - Select one ready work item or a justified coherent group; do not merge nearby but unrelated work.
21
+ - Finish or explicitly account for existing work before starting more work. Do not weaken scope to make selection easier.
22
+ - Do not implement code or invoke execution, review, verification, evidence-gate, or release skills.
23
+ - Do not hand off to planning until a fresh `pickup-probe` record exists, unless this direct primitive is intentionally stopping after selection.
24
+ - A broad continuation request may trigger queue inspection but never replaces per-item pickup evidence.
464
25
 
465
- If the gate fails, update the artifact and stop with the blocker.
26
+ ## Provider Boundaries
466
27
 
467
- After a merge, automatic continuation may inspect the queue and write a new pull-work artifact, but it cannot enter planning or execution for the next work item until a fresh pickup Probe record exists for that newly selected item or justified group.
468
- ## Gate Claim: Record Selected Work
28
+ - `BoardProvider` lists and ranks ready work, board state, priority, milestone, and blockers.
29
+ - `WorkItemProvider` reads the selected item, acceptance criteria, relationships, and provider state.
30
+ - `RepositoryAdapter` supplies target revision, worktree capability, and changed-file overlap context.
31
+ - `AssignmentProvider` is the sole durable ownership interface: claim, release, supersede, status, and list.
469
32
 
470
- When the Pickup Gate passes and work is selected (not just a shepherding scan or WIP-only audit), record the gate claim for the Builder Kit `pull-work` step before handing off to `design-probe` or `plan-work`. This satisfies the `builder.pull-work.selected` gate expectation.
33
+ An optional GitHub adapter may implement these interfaces. Do not require GitHub issue numbers, labels, Projects, pull requests, `gh`, or provider-native dependency APIs.
471
34
 
472
- Start the canonical Flow run before recording the first gate claim. This is idempotent for an existing run and projects Flow's current step and gate requirements into the sidecar:
35
+ ## Model Routing
473
36
 
474
- ```bash
475
- flow-agents builder-run start --session-dir .kontourai/flow-agents/<slug>
476
- ```
37
+ For board scans, WIP assessment, dependency joins, and selection bookkeeping, resolve `delegate-mechanical` from `.datum/config.json`. If unavailable, inherit the session model and record the fallback.
38
+ Apply the routing and escalation contract in `context/contracts/execution-contract.md`.
477
39
 
478
- Do not start at a later step. Flow owns advancement from `pull-work` after it evaluates the recorded evidence.
40
+ ## Inputs
479
41
 
480
- Use the `selected_item_ids` as the evidence artifact ref and confirm that scope and acceptance criteria are present in the pull-work artifact:
42
+ - working directory and configured provider capabilities
43
+ - optional priority, board, milestone, assignee, or WIP filters
44
+ - current delivery artifacts and active assignment/liveness context
45
+
46
+ ## Artifact
47
+
48
+ Create or update `<slug>--pull-work.md` with:
49
+
50
+ - board snapshot and applied filters
51
+ - active work, review, verification, and conflict assessment
52
+ - candidate readiness, blockers, dependencies, priority rationale, and grouping decision
53
+ - assignment/liveness preflight, claim confirmation, takeover, post-claim
54
+ conflict evidence, and any explicit `reclaimable_override`
55
+ - selected work-item identifiers, scope, acceptance criteria, target revision, and repository context
56
+ - revision freshness, source revision assumptions, changed-scope intersections, and unknowns
57
+ - worktree/isolation decision, expected modified files, conflict risks, route reason, and next action
58
+
59
+ ## Selection Method
60
+
61
+ 1. Read configured board and work-item state. Normalize readiness, dependencies, priority, target milestone or delivery outcome, and blockers through the provider interfaces.
62
+ 2. Assess WIP and shepherding. Prefer completing active implementation, review, verification, or provider follow-up before selecting new work. Separate the caller's WIP limit from global overlap risk.
63
+ 3. Join `AssignmentProvider` state with liveness state where available. Exclude held work unless the caller explicitly overrides it; record the reason, holder context, and recovery rule. A liveness emission failure is non-blocking only when the skipped check and its consequence are recorded.
64
+ 4. Rank candidates by readiness, user outcome, dependency freshness, risk, priority, and overlap. Select a single item by default. A group needs a shared outcome, hard dependency, or explicit risk-reduction rationale.
65
+ 5. Create the durable assignment through `AssignmentProvider` when the selected work requires ownership. Record the claim result, but do not substitute a provider-specific mutation for the interface contract.
66
+ 6. Confirm the repository anchor with `RepositoryAdapter`: target ref/SHA, planned base when present, acceptance-criteria drift, related changes, and source-scope intersections. Mark unavailable evidence `NOT_VERIFIED`; do not call it fresh by assumption.
67
+ 7. Decide isolation from expected modified-file overlap, active assignments, worktree support, and rollback needs. Record a shared-worktree decision only when overlap is acceptably low and coordination is explicit.
68
+ 8. Hand the selected item and all unresolved context to `pickup-probe` before planning.
69
+
70
+ ### Assignment And Liveness Selection Preflight
71
+
72
+ Capture the caller identity once for the selection pass. For each candidate,
73
+ join durable `AssignmentProvider.status()` with available liveness observations
74
+ and classify the subject, not individual observation rows, in this precedence:
75
+
76
+ 1. `mine`: the durable assignment confirms the caller as holder. Fold it into
77
+ WIP/shepherding; do not re-offer it as new work.
78
+ 2. `held`: another live holder or a conflicting own/other live observation is
79
+ present. Exclude it by default and surface a double-hold conflict.
80
+ 3. `reclaimable`: the incumbent assignment is stale. Selection requires an
81
+ explicit recorded opt-in and the provider's takeover protocol.
82
+ 4. `human-held`: a human-owned assignment requires that human's explicit
83
+ release or authorization; a force flag alone is insufficient.
84
+ 5. `free`: no effective assignment or live holder blocks selection.
85
+
86
+ Read raw provider status, freshness, holder identity, and reason fields; do not
87
+ collapse them into a coarse display label. Record `assignment_preflight`, the
88
+ classification, holder context, provider capability, and any unavailable
89
+ liveness dimension. A missing optional liveness observation may be recorded as
90
+ skipped, but a missing durable assignment check is `NOT_VERIFIED` when ownership
91
+ matters.
92
+
93
+ An explicit override of `held` or `reclaimable` records the requester,
94
+ authorization, reason, consequence, and `reclaimable_override`. Reclaimable
95
+ takeover is resumption, not restart: observe the provider grace rule, supersede
96
+ the stale holder atomically when supported, and continue the incumbent branch
97
+ or durable handoff.
98
+
99
+ After `AssignmentProvider.claim()`, call `status()` again. If another holder now
100
+ coexists or the caller is not the confirmed holder, record a post-claim
101
+ conflict, surface it prominently, and reselect rather than planning. The check
102
+ does not imply universal mutual exclusion: a local-file provider may serialize
103
+ claims with a lock, while a remote provider without compare-and-swap remains
104
+ advisory and must rely on conflict detection plus its publish-time hold gate.
105
+
106
+ When the provider exposes deterministic conflict arbitration, resolve a
107
+ double-hold from the same pinned caller identity, subject, and observation
108
+ snapshot. Prefer the earlier claim; break an exact timestamp tie by ascending
109
+ actor identifier. Every caller must derive the same winner from the same state.
110
+ If the caller loses, release or concede its claim immediately, record
111
+ `{verdict_reason, winner_actor, conceded: true}`, exclude the contested subject,
112
+ and reselect in the same pass. If the caller wins, record
113
+ `{verdict_reason, winner_actor, conceded: false}` and continue without release.
114
+ This convergence rule closes a detected conflict for the current pass; it does
115
+ not close the underlying read-then-write race on a non-atomic provider.
116
+
117
+ Assignment and liveness records are runtime/provider state. Apart from the
118
+ narrow `AssignmentProvider` claim or supersede required for ownership, do not
119
+ mutate board fields, work-item content, or unrelated provider state from this
120
+ skill.
121
+
122
+ ## Active Builder Run
123
+
124
+ Complete selection and ownership preflight before creating a run. The public
125
+ runtime supports exactly two Work Item reference forms: `provider:id` and
126
+ `owner/repo#numeric-id`. `provider:id` is the provider-neutral adapter form;
127
+ `owner/repo#numeric-id` is the GitHub-compatible adapter form. Do not invent
128
+ other reference formats or treat an unconfigured provider as resolved. Bind a
129
+ supported selected Work Item through either form:
481
130
 
482
131
  ```bash
483
- npm run workflow:sidecar -- record-gate-claim .kontourai/flow-agents/<slug> \
484
- --expectation selected-work \
485
- --status pass \
486
- --summary "Selected <work-item-ref>: scope clear, acceptance criteria present." \
487
- --evidence-ref-json '{"kind":"artifact","file":".kontourai/flow-agents/<slug>/<slug>--pull-work.md","summary":"Pull-work artifact with selected_item_ids, scope, and acceptance criteria."}'
132
+ flow-agents workflow start --flow builder.build \
133
+ --work-item provider:work-item-123 \
134
+ --assignment-provider <configured-kind> \
135
+ --effective-state-json <provider-status.json>
136
+ # GitHub adapter example:
137
+ flow-agents workflow start --flow builder.build \
138
+ --work-item kontourai/flow-agents#123 \
139
+ --assignment-provider github \
140
+ --effective-state-json <github-assignment-status.json>
141
+ flow-agents workflow status --session-dir <session-dir>
488
142
  ```
489
143
 
490
- The sidecar writer synchronizes an existing canonical Flow run after writing the trust bundle. If synchronization was interrupted, recover with the exact `next_action.command` from `state.json`; do not edit Flow state or restamp the active step.
491
-
492
- Use `--status fail` when the gate fails (blocker recorded but no selection made). Use `--status not_verified` only when the session has no active flow step (non-Builder-Kit usage).
493
-
494
- Record `--status fail` with a summary naming the blocker when stopping before selection. Do not record `pass` until `selected_item_ids` are confirmed and the pickup gate criteria above are met.
144
+ For `local-file`, pass `--assignment-provider local-file` and omit
145
+ `--effective-state-json`. `workflow start` atomically binds the selected Work Item, records the canonical
146
+ `selected-work` claim, and projects the next step. Do not call it before
147
+ provider ownership is confirmed, and do not attempt to attach `selected-work`
148
+ again after start. If readiness, ownership, or source context is unresolved,
149
+ stop before run creation with `FAIL` or `NOT_VERIFIED` in the pull-work artifact.
150
+ Do not use a private writer command, enter at a later step, or infer an active
151
+ run from an artifact path.
495
152
 
153
+ ## Handoff
496
154
 
155
+ Pass `pickup-probe` the selected identifiers, artifact path, provider state, dependencies, revision-freshness result, expected modified files, conflict risks, assignment/liveness result, worktree mode, route reason, and next action. Stop here unless the next primitive is explicitly requested.
497
156
 
498
- ## Flow Validation Boundary
157
+ ## Revision Freshness
499
158
 
500
- Flow Agents may need to know whether a Flow Definition referenced by a work item is valid, but Flow owns those semantics. Use one of Flow's published validation surfaces instead of copying checks into this repo:
159
+ Fetch or otherwise resolve the latest target ref before classifying readiness. Compare the current target ref/SHA to the Work Item's `planned_base_ref` and `planned_base_sha`; record commits-since, planned age, changed files, and changed-file intersections with `planning_scope_refs`.
501
160
 
502
- ```bash
503
- flow validate-definition <path> --json
504
- ```
505
-
506
- or, from code that already depends on Flow:
507
-
508
- ```js
509
- validateDefinitionWithDiagnostics(definition)
510
- ```
161
+ Classify revision freshness as `fresh`, `drifted`, or `stale`, and classify material drift as `no_material_drift`, `scope_drift`, `dependency_drift`, `contract_drift`, or `conflict_risk`. `drifted` requires an alignment decision or accepted gap. `stale` routes back to `idea-to-backlog`. Missing `planned_base_sha` is not fresh: record `NOT_VERIFIED` and stop unless an accepted-gap baseline explicitly names the current target ref/SHA plus provider history.
511
162
 
512
- Record the command/API result in the pull-work artifact or evidence sidecar. If Flow is unavailable, mark that readiness subcheck `NOT_VERIFIED` or blocked; do not create a partial validator in Flow Agents.
163
+ Provider discovery and normalization belong to configured adapters, not this skill. Consume configured `WorkItemProvider`, `BoardProvider`, and `AssignmentProvider` results; when configuration is absent, ask for the intended adapters instead of assuming one.