@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.
- package/CHANGELOG.md +19 -0
- package/build/src/builder-flow-run-adapter.d.ts +22 -2
- package/build/src/builder-flow-run-adapter.js +93 -28
- package/build/src/builder-flow-runtime.d.ts +8 -3
- package/build/src/builder-flow-runtime.js +407 -51
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +80 -14
- package/build/src/cli/builder-run.js +14 -18
- package/build/src/cli/workflow-sidecar.d.ts +28 -4
- package/build/src/cli/workflow-sidecar.js +825 -103
- package/build/src/cli/workflow.js +301 -43
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.js +5 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/tools/build-universal-bundles.js +53 -3
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +78 -9
- package/docs/context-map.md +22 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/getting-started.md +9 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +75 -40
- package/docs/workflow-usage-guide.md +109 -42
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +52 -41
- package/evals/integration/test_builder_step_producers.sh +330 -6
- package/evals/integration/test_bundle_install.sh +318 -65
- package/evals/integration/test_bundle_lifecycle.sh +4 -6
- package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
- package/evals/integration/test_current_json_per_actor.sh +12 -0
- package/evals/integration/test_dual_emit_flow_step.sh +62 -43
- package/evals/integration/test_flowdef_session_activation.sh +145 -25
- package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
- package/evals/integration/test_gate_lockdown.sh +3 -5
- package/evals/integration/test_goal_fit_hook.sh +60 -2
- package/evals/integration/test_install_merge.sh +18 -8
- package/evals/integration/test_liveness_verdict.sh +14 -17
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
- package/evals/integration/test_public_workflow_cli.sh +334 -14
- package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
- package/evals/integration/test_sidecar_field_preservation.sh +36 -11
- package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
- package/evals/integration/test_workflow_steering_hook.sh +15 -38
- package/evals/run.sh +2 -0
- package/evals/static/test_builder_skill_coherence.sh +247 -0
- package/evals/static/test_library_exports.sh +5 -2
- package/evals/static/test_universal_bundles.sh +44 -1
- package/evals/static/test_workflow_skills.sh +13 -325
- package/kits/builder/flows/build.flow.json +22 -0
- package/kits/builder/flows/shape.flow.json +9 -9
- package/kits/builder/kit.json +70 -16
- package/kits/builder/skills/builder-shape/SKILL.md +75 -75
- package/kits/builder/skills/continue-work/SKILL.md +45 -106
- package/kits/builder/skills/deliver/SKILL.md +96 -442
- package/kits/builder/skills/design-probe/SKILL.md +40 -139
- package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
- package/kits/builder/skills/execute-plan/SKILL.md +54 -125
- package/kits/builder/skills/fix-bug/SKILL.md +42 -132
- package/kits/builder/skills/gate-review/SKILL.md +60 -211
- package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
- package/kits/builder/skills/learning-review/SKILL.md +63 -170
- package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
- package/kits/builder/skills/plan-work/SKILL.md +51 -185
- package/kits/builder/skills/pull-work/SKILL.md +136 -485
- package/kits/builder/skills/release-readiness/SKILL.md +66 -107
- package/kits/builder/skills/review-work/SKILL.md +89 -176
- package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
- package/kits/builder/skills/verify-work/SKILL.md +101 -113
- package/package.json +2 -2
- package/packaging/README.md +1 -1
- package/scripts/README.md +1 -1
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/scripts/install-codex-home.sh +63 -23
- package/scripts/install-owned-files.js +18 -2
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +426 -64
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +75 -14
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +436 -18
- package/src/cli/builder-run.ts +3 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +746 -103
- package/src/cli/workflow.ts +288 -41
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +6 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/tools/build-universal-bundles.ts +51 -3
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -1,512 +1,163 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "pull-work"
|
|
3
|
-
description: "Select ready
|
|
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
|
|
8
|
+
Select ready backlog work and prepare a bounded handoff without implementing it.
|
|
9
9
|
|
|
10
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
- `
|
|
451
|
-
-
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
-
|
|
455
|
-
-
|
|
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
|
-
|
|
26
|
+
## Provider Boundaries
|
|
466
27
|
|
|
467
|
-
|
|
468
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
+
## Model Routing
|
|
473
36
|
|
|
474
|
-
|
|
475
|
-
|
|
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
|
-
|
|
40
|
+
## Inputs
|
|
479
41
|
|
|
480
|
-
|
|
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
|
-
|
|
484
|
-
--
|
|
485
|
-
--
|
|
486
|
-
--
|
|
487
|
-
|
|
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
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
##
|
|
157
|
+
## Revision Freshness
|
|
499
158
|
|
|
500
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|