@deftai/directive-content 0.85.0 → 0.87.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/QUICK-START.md +2 -0
- package/Taskfile.yml +2 -1
- package/conventions/references.md +1 -1
- package/docs/getting-started.md +2 -0
- package/docs/openclaw-agent-host.md +137 -0
- package/package.json +1 -1
- package/packs/lessons/lessons-pack-0.1.json +51 -0
- package/packs/skills/skills-pack-0.1.json +24 -24
- package/skills/deft-directive-release/SKILL.md +50 -2
- package/skills/deft-directive-review-cycle/SKILL.md +118 -14
- package/skills/deft-directive-swarm/SKILL.md +56 -25
- package/skills/deft-directive-triage/SKILL.md +40 -55
- package/tasks/triage-queue.yml +1 -1
- package/tasks/verify.yml +12 -0
- package/templates/agent-prompt-preamble.md +16 -5
- package/templates/swarm-greptile-poller-prompt.md +21 -12
|
@@ -50,98 +50,83 @@ Directive does not guess your mix: **ordered plan** (`task plan-sequence:*`) whe
|
|
|
50
50
|
! Probe cache freshness before doing any classification or selection. Stale cache reads produce stale decisions; the gate is the contract.
|
|
51
51
|
|
|
52
52
|
1. ! Run `task verify:cache-fresh` (D5 / #1127). Exit 0 -> proceed to Phase 1. Exit 1 (stale or blocked) -> refresh per the printed remediation. Exit 2 (no bootstrap) -> run `task triage:bootstrap` first. When the cache has zero entries, read paths auto-fetch from GitHub first (#2575).
|
|
53
|
-
2. ~ Refresh path: `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` for an already-bootstrapped project
|
|
54
|
-
3. ~ If `xbrief/active/*.xbrief.json` references are in play, run `task triage:refresh-active` to
|
|
55
|
-
4. ~ When the one-liner
|
|
53
|
+
2. ~ Refresh path: `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` for an already-bootstrapped project; `task triage:bootstrap` for a first-time seed.
|
|
54
|
+
3. ~ If `xbrief/active/*.xbrief.json` references are in play, run `task triage:refresh-active` to surface drift before the queue is rendered.
|
|
55
|
+
4. ~ When the session one-liner carries `[scope-drift] N` (D14 / #1133), run `task triage:scope-drift` and choose subscribe / ignore before walking the queue.
|
|
56
56
|
5. ⊗ Walk the queue against a stale cache -- the audit log will record decisions against bodies the operator never actually saw.
|
|
57
57
|
|
|
58
58
|
## Phase 1 -- Classify
|
|
59
59
|
|
|
60
60
|
! Inspect the auto-classification audit log so manually-decided items are not re-walked, and surface anomalies before the queue render.
|
|
61
61
|
|
|
62
|
-
1. ! Run `task triage:classify --list` (D10 / #1129) to render
|
|
63
|
-
2. ! Walk recent
|
|
64
|
-
3. ~
|
|
65
|
-
4. ~
|
|
66
|
-
5. ⊗ Re-classify
|
|
67
|
-
6. ⊗ Block issue creation solely because no label was selected, or invent ad hoc labels outside the repository's existing label set.
|
|
62
|
+
1. ! Run `task triage:classify --list` (D10 / #1129) to render effective rules and hold-markers.
|
|
63
|
+
2. ! Walk recent `xbrief/.eval/candidates.jsonl` entries for anomalies (classifier disagreement, repeated defer, stale needs-ac); surface before Phase 2; do NOT auto-fix.
|
|
64
|
+
3. ~ Scope widen/narrow via `task triage:scope --list` (D12 / #1131); edits belong in PROJECT-DEFINITION.
|
|
65
|
+
4. ~ Label hygiene: recommend repo labels via `gh label list` when unlabeled; do not invent labels or block creation solely for missing labels.
|
|
66
|
+
5. ⊗ Re-classify terminally decided items without operator approval -- supersession is `task triage:reset <N>` only.
|
|
68
67
|
|
|
69
68
|
## Phase 2 -- Present
|
|
70
69
|
|
|
71
70
|
! Apply the Work selection fork gate (#2542): when no ordered-plan is active, render `task triage:queue` before suggesting work (#1149). Active sequence yields to the ordered-plan entry (#2402).
|
|
72
71
|
|
|
73
|
-
1. ! Run `task triage:queue --limit=N` (D11 / #1128) -- default `N=10
|
|
74
|
-
2. ! For per-item detail, run `task triage:show <N>` --
|
|
75
|
-
3. ~ Present the ranked queue verbatim; do NOT silently re-rank, drop, or annotate beyond
|
|
76
|
-
4. ⊗ Recommend a specific issue without
|
|
72
|
+
1. ! Run `task triage:queue --limit=N` (D11 / #1128) -- default `N=10`. Groups `[RESUME]` -> `[URGENT]` -> untriaged -> other; ranking via `plan.policy.triageRankingLabels[]`, tiebreak `updated_at` desc.
|
|
73
|
+
2. ! For per-item detail, run `task triage:show <N>` (default) or `task triage:show --format=operator <N>` (#2890) -- cached payload, latest decision, audit timeline, active-xBRIEF flag; operator format is the pasteable Phase 3 brief backbone. Exit 0 on hit, 1 on cache miss (re-sync per Phase 0).
|
|
74
|
+
3. ~ Present the ranked **queue listing** verbatim; do NOT silently re-rank, drop, or annotate the listing beyond the canonical renderer. This queue non-annotation rule does **not** forbid Phase 3 per-candidate operator briefs or leans (see Phase 3 / #2890).
|
|
75
|
+
4. ⊗ Recommend a specific issue without `task triage:queue` first, or an issue absent from the queue without `task triage:show` to surface why.
|
|
77
76
|
|
|
78
77
|
## Phase 3 -- Decide
|
|
79
78
|
|
|
80
|
-
! Walk per-item decisions through the canonical `task triage:*` verbs
|
|
79
|
+
! Walk per-item decisions through the canonical `task triage:*` verbs (tasks own audit-log append / schema / `xbrief/proposed/` write).
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
! **Operator brief (same turn as menu) (#2890):** Before every per-item decision menu, present an operator brief in the **same operator-visible message/surface** as the menu, containing at least: issue `#N` + title + link; labels (or explicit none); 2–5 line problem/context summary; AC bullets or explicit "thin body / no AC"; agent **lean** + one-line why (Accept / Defer / Reject / Needs-AC / …). ~ Prefer `task triage:show --format=operator <N>` as the brief backbone; agent still owns lean. ⊗ Menu-only or chip-only Phase 3 turns without that brief. ⊗ Brief-only turn followed by a later chip/menu-only turn that does not restate the brief.
|
|
82
|
+
|
|
83
|
+
! **Host structured-question adapter:** On chips / `ask_user` / similar UIs (e.g. OpenClaw `ask_user`), keep the prose brief in chat; structured options are **actions only** (Accept / Defer / Reject / Needs-AC / Mark duplicate / Discuss / Back). Option labels ≉ substitute for the brief.
|
|
84
|
+
|
|
85
|
+
For each candidate, render the canonical numbered action menu and dispatch:
|
|
83
86
|
|
|
84
87
|
```
|
|
85
88
|
What would you like to do with this candidate?
|
|
86
|
-
1. Accept -- `task triage:accept <N>`
|
|
87
|
-
2. Reject -- `task triage:reject <N>`
|
|
88
|
-
3. Defer -- `task triage:defer <N> [--resume-on <event>]`
|
|
89
|
-
4. Needs-AC -- `task triage:needs-ac <N>`
|
|
90
|
-
5. Mark duplicate -- `task triage:mark-duplicate <N> <of-issue>`
|
|
89
|
+
1. Accept -- `task triage:accept <N>`
|
|
90
|
+
2. Reject -- `task triage:reject <N>`
|
|
91
|
+
3. Defer -- `task triage:defer <N> [--resume-on <event>]`
|
|
92
|
+
4. Needs-AC -- `task triage:needs-ac <N>`
|
|
93
|
+
5. Mark duplicate -- `task triage:mark-duplicate <N> <of-issue>`
|
|
91
94
|
6. Discuss
|
|
92
95
|
7. Back
|
|
93
96
|
```
|
|
94
97
|
|
|
95
|
-
- ! `--resume-on <event>` on `task triage:defer` (D3 / #1123 -- ships in parallel; reference but do not hard-depend) records a resume condition with the defer entry; the resume condition surfaces in `task triage:queue` once met. When D3 has not landed yet, omit the flag -- the verb stays terminal-shape-compatible.
|
|
96
98
|
- ! Map user replies only to the displayed number (`1`-`7`) or exact displayed option text. ⊗ Do NOT infer from alphabetic host affordances or bare letters such as `d` / `b` unless those letters were visibly rendered as choices.
|
|
97
|
-
- ! On `Discuss`, halt
|
|
98
|
-
- ! On `Back`, un-buffer
|
|
99
|
-
- ~ Bulk
|
|
100
|
-
- ⊗ Write to `xbrief/proposed/` directly -- only `task triage:accept`
|
|
99
|
+
- ! On `Discuss`, halt immediately, prompt `What would you like to discuss?`, resume only on explicit user signal. ⊗ Implicit resumption.
|
|
100
|
+
- ! On `Back`, un-buffer prior selection and re-render its action menu only before a `task triage:*` dispatch; after dispatch use `task triage:reset`.
|
|
101
|
+
- ~ Bulk: `task triage:bulk-{accept,reject,defer,needs-ac}`; results still flow through the audit log.
|
|
102
|
+
- ⊗ Write to `xbrief/proposed/` directly -- only `task triage:accept` is authorised.
|
|
101
103
|
|
|
102
104
|
## Phase 4 -- Audit
|
|
103
105
|
|
|
104
106
|
! Confirm the session's decisions landed coherently before exiting the skill.
|
|
105
107
|
|
|
106
|
-
1. ! Run `task triage:audit --format=json` (D11 / #1128)
|
|
107
|
-
2. ! Run `task triage:summary` (D2 / #1122) --
|
|
108
|
-
3. ~
|
|
109
|
-
4. ~
|
|
110
|
-
5. ⊗ Skip
|
|
111
|
-
|
|
112
|
-
! Before reporting an umbrella or epic's current status during triage (what is done, what blocks, wave order), fetch `repos/<owner>/<repo>/issues/<N>/comments` via REST, read the `## Current shape (as of pass-N)` comment and any linked context/`LockedDecisions` xBRIEF — never conclude status from the issue body alone (claim-cites-state-surface, #2066 / AGENTS.md #1152).
|
|
108
|
+
1. ! Run `task triage:audit --format=json` (D11 / #1128); optional `#1180` filters `--since` / `--action`. Transform with `jq` -- framework does not compute trends.
|
|
109
|
+
2. ! Run `task triage:summary` (D2 / #1122) -- `[triage] N untriaged · S stale-defer · M in-flight · WIP X/Y [⚠] [· [scope-drift] N]`.
|
|
110
|
+
3. ~ Non-zero `[scope-drift]` → surface `task triage:scope-drift` + subscribe/unsubscribe/ignore remediation; then `task triage:bootstrap -- --resume`.
|
|
111
|
+
4. ~ Stale accept (no active xBRIEF ref) → re-ingest or `task triage:reset`.
|
|
112
|
+
5. ⊗ Skip Phase 4 audit.
|
|
113
|
+
6. ! Umbrella/epic status: REST comments → `## Current shape (as of pass-N)` (#2066 / #1152); never body alone.
|
|
113
114
|
|
|
114
115
|
## Reversibility
|
|
115
116
|
|
|
116
|
-
!
|
|
117
|
-
|
|
118
|
-
⊗ Edit or delete prior entries in `xbrief/.eval/candidates.jsonl` to "undo" a decision -- the log is append-only by design and any external mutation breaks the `merge=union` rebase ergonomic (#1144 / N4).
|
|
117
|
+
! Undo via `task triage:reset <N>` (Layer 5; history never deleted). ⊗ Edit/delete `xbrief/.eval/candidates.jsonl` to "undo".
|
|
119
118
|
|
|
120
119
|
## Anti-Patterns
|
|
121
120
|
|
|
122
|
-
- ⊗ Recommend
|
|
123
|
-
- ⊗ Conclude "nothing to do" from
|
|
124
|
-
- ⊗
|
|
125
|
-
- ⊗ Reimplement audit-log append / `proposed/` write inline -- the `task triage:*` verbs own those surfaces (#845, #883).
|
|
126
|
-
- ⊗ Treat `defer` / `needs-ac` as terminal -- they intentionally resurface on the next pass.
|
|
127
|
-
- ⊗ Edit `xbrief/.eval/candidates.jsonl` directly to revoke a decision -- use `task triage:reset <N>`.
|
|
121
|
+
- ⊗ Recommend work without `task triage:queue` (#1149).
|
|
122
|
+
- ⊗ Conclude "nothing to do" from folder scans or live GitHub alone (#2576).
|
|
123
|
+
- ⊗ Stale-cache walk; reimplement audit/`proposed/` writes; treat defer/needs-ac as terminal; edit candidates.jsonl; menu-only Phase 3 without operator brief (#2890).
|
|
128
124
|
|
|
129
125
|
## EXIT
|
|
130
126
|
|
|
131
|
-
!
|
|
132
|
-
|
|
133
|
-
! Provide chaining instructions:
|
|
134
|
-
|
|
135
|
-
- **Ingestion / evaluation of accepted items**: chain into `skills/deft-directive-refinement/SKILL.md` -- refinement's Phase 1 ingests the `xbrief/proposed/` items this skill just wrote into the rest of the lifecycle.
|
|
136
|
-
- **Cohort dispatch**: chain into `skills/deft-directive-swarm/SKILL.md` -- swarm Phase 0 is queue-driven (N2 / #1142) and consumes the same `task triage:queue` ordering you just walked.
|
|
137
|
-
- **Fresh-state refresh before re-entry**: run `task cache:fetch-all -- --source=github-issue --repo OWNER/NAME` then re-enter this skill when ready to continue.
|
|
138
|
-
|
|
139
|
-
⊗ Exit silently without the canonical confirmation + chaining instruction -- the Skill Completion Gate in AGENTS.md is binding.
|
|
127
|
+
! On opt-out: `deft-directive-triage complete -- exiting skill.` Chain: `deft-directive-refinement` (accepted items) · `deft-directive-swarm` (cohort) · `task cache:fetch-all` then re-enter. ⊗ Silent exit.
|
|
140
128
|
|
|
141
129
|
## References
|
|
142
130
|
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
- Layer 5 reversibility verb: `scripts/triage_actions.py::reset` (already shipped under #845)
|
|
146
|
-
- Sibling skills: `skills/deft-directive-refinement/SKILL.md`, `skills/deft-directive-swarm/SKILL.md`, `skills/deft-directive-sync/SKILL.md`
|
|
147
|
-
- Stub author (replaced): #1149 (N9)
|
|
131
|
+
- #1119 D6; #1128 D11 (`triage:queue` / `show` / `audit`); #2890 Phase 3 operator brief; #1122 / #1123 / #1127 / #1129 / #1131
|
|
132
|
+
- Siblings: `deft-directive-refinement`, `deft-directive-swarm`, `deft-directive-sync`
|
package/tasks/triage-queue.yml
CHANGED
|
@@ -36,7 +36,7 @@ tasks:
|
|
|
36
36
|
ENGINE_CMD: 'triage-queue queue --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
|
|
37
37
|
|
|
38
38
|
show:
|
|
39
|
-
desc: "Per-issue triage detail (#1128 / D11). -- task triage:show -- <N> [--repo OWNER/NAME]"
|
|
39
|
+
desc: "Per-issue triage detail (#1128 / D11, #2890). -- task triage:show -- <N> [--format=default|operator] [--repo OWNER/NAME]"
|
|
40
40
|
internal: true
|
|
41
41
|
deps: [":engine:_ts-build"]
|
|
42
42
|
dir: '{{.USER_WORKING_DIR}}'
|
package/tasks/verify.yml
CHANGED
|
@@ -91,6 +91,18 @@ tasks:
|
|
|
91
91
|
vars:
|
|
92
92
|
ENGINE_CMD: 'verify-cursor-tier1 --project-root "{{.DEFT_ROOT}}"'
|
|
93
93
|
|
|
94
|
+
openclaw-tier1:
|
|
95
|
+
desc: "Framework-source content gate (#2875): assert OpenClaw (openclaw descriptor, sessions_spawn primitive) is enumerated as Tier 1 in the swarm Phase 3 capability matrix AND routing accepts openclaw as a dispatch_provider. Fails when a doc/code edit drops the OpenClaw descriptor and silently re-opens grok-build / generic-terminal misclassification. Three-state exit (0 clean / 1 missing marker / 2 config error)."
|
|
96
|
+
deps:
|
|
97
|
+
- task: :engine:_ts-build
|
|
98
|
+
# Framework-source-only gate: it scans THIS repo's swarm skill + routing
|
|
99
|
+
# module, so it targets DEFT_ROOT (not USER_WORKING_DIR). Mirrors
|
|
100
|
+
# verify:cursor-tier1 / verify:content-manifest.
|
|
101
|
+
cmds:
|
|
102
|
+
- task: :engine:invoke
|
|
103
|
+
vars:
|
|
104
|
+
ENGINE_CMD: 'verify-openclaw-tier1 --project-root "{{.DEFT_ROOT}}"'
|
|
105
|
+
|
|
94
106
|
go-freeze:
|
|
95
107
|
desc: "Tier-1 freeze gate for the legacy Go-installer bridge (#1912). Advisory while the Tier-0 SoT (lastGoInstaller) is null; once the operator pins it, fails when cmd/deft-install is bumped above the frozen tag. Three-state exit (0 ok / 1 violation / 2 config error). Emergency bypass: DEFT_ALLOW_GO_INSTALLER_BUMP=1."
|
|
96
108
|
deps:
|
|
@@ -73,15 +73,15 @@ When the operator supplies an ordered plan (delivery sequence, cohort, checklist
|
|
|
73
73
|
|
|
74
74
|
## 2.6 Provider-neutral worker metadata (#1531)
|
|
75
75
|
|
|
76
|
-
Heterogeneous swarm dispatch (#1531) assigns each worker a **dispatch provider** (the runtime primitive that launched the agent), a **worker role** (what the agent is allowed to do), and a **selected backend** or **routing policy** (how the harness maps that role to a concrete agent). These fields are provider-neutral: Composer-class coding agents, Grok Build (`spawn_subagent`), Cursor/cloud agents, and future adapters share the same contract.
|
|
76
|
+
Heterogeneous swarm dispatch (#1531) assigns each worker a **dispatch provider** (the runtime primitive that launched the agent), a **worker role** (what the agent is allowed to do), and a **selected backend** or **routing policy** (how the harness maps that role to a concrete agent). These fields are provider-neutral: Composer-class coding agents, Grok Build (`spawn_subagent`), Cursor/cloud agents, OpenClaw (`sessions_spawn`, #2874 / #2879), and future adapters share the same contract.
|
|
77
77
|
|
|
78
78
|
! Every intentional backend-routed dispatch MUST carry a separate `## Worker metadata` section in the dispatch envelope, placed AFTER `## Allocation context` and BEFORE the task body. This section is advisory metadata for the worker and for audit; it does NOT replace, extend, or reorder the five-field #1378 `## Allocation context` recognition contract above.
|
|
79
79
|
|
|
80
80
|
When present, the section documents these fields in order:
|
|
81
81
|
|
|
82
|
-
- `dispatch_provider`: the runtime primitive that launched this worker -- e.g. `spawn_subagent`, `start_agent`, `cursor-composer`, `cursor-cloud-agent`, or a future adapter id. Names the harness surface, not the model.
|
|
82
|
+
- `dispatch_provider`: the runtime primitive that launched this worker -- e.g. `spawn_subagent`, `start_agent`, `sessions_spawn` (OpenClaw host; platform descriptor `openclaw` per #2874 / #2875), `cursor-composer`, `cursor-cloud-agent`, or a future adapter id. Names the harness surface, not the model.
|
|
83
83
|
- `worker_role`: the role boundary for this dispatch -- one of `leaf-implementation`, `orchestrator`, `review-monitor`, or `merge-release` (stable ids from `packages/core/src/swarm/routing.ts` `SWARM_WORKER_ROLES`). Tells the worker which preamble rules and skill surfaces apply.
|
|
84
|
-
- `selected_backend`: the stable backend id from `plan.policy.swarmSubagentBackend` / `task policy:subagent-backends` (
|
|
84
|
+
- `selected_backend`: the stable backend id from `plan.policy.swarmSubagentBackend` / `task policy:subagent-backends` (accepted set today: `composer`, `grok-build`, `cursor-cloud` only — see `KNOWN_SUBAGENT_BACKEND_IDS`) | null -- which catalogued **coding** backend the operator selected for this role. OpenClaw is a **host / dispatch_provider** (`sessions_spawn` / descriptor `openclaw`), not a `swarmSubagentBackend` enum value; do not write `selected_backend: openclaw` into policy (#2879 Greptile P1).
|
|
85
85
|
- `routing_policy`: <path or reference to the operator's routing file / tiering policy> | null -- when backend selection is delegated to harness routing instead of a typed policy field, cite the policy handle here so postmortems can reconstruct the route. The canonical handle is the gitignored, per-machine `.deft/routing.local.json` (#1739), keyed by `(dispatch_provider, worker_role)`; set decisions with `task swarm:routing-set -- --role <role> (--model <slug> | --harness-default)`.
|
|
86
86
|
- `resolved_model` (#1739): the concrete model slug the operator pinned for this `(provider, role)` | null for an explicit harness default. Resolved from `.deft/routing.local.json` and stamped into the `task swarm:launch` manifest. **This is the field the dispatch primitive must actually honor** -- see the threading rule below.
|
|
87
87
|
- `model_source` (#1739): provenance of `resolved_model` -- e.g. `cursor-route`, `harness-default explicit`. Lets a postmortem tell a pinned model from a harness default.
|
|
@@ -94,7 +94,7 @@ Populate `selected_backend` OR `routing_policy` (or both when the operator sets
|
|
|
94
94
|
- `orchestrator`, `review-monitor`, or `merge-release` + explicit backend routing: at least one MUST be non-null so strong-tier audit traces stay reconstructable.
|
|
95
95
|
- Any role on the harness-default agent with no tiering decision: both MAY be null; `dispatch_provider` and `worker_role` remain required.
|
|
96
96
|
|
|
97
|
-
**Role-boundary expectations (all providers):** the same boundaries apply whether the worker runs on Composer, Grok Build, Cursor/cloud, or a future adapter:
|
|
97
|
+
**Role-boundary expectations (all providers):** the same boundaries apply whether the worker runs on Composer, Grok Build, Cursor/cloud, OpenClaw, or a future adapter:
|
|
98
98
|
|
|
99
99
|
- ! `leaf-implementation` workers implement scoped xBRIEF work in their assigned worktree only -- gates (`task check`, file-scope audit, Greptile review cycle) are model-agnostic and MUST still pass.
|
|
100
100
|
- ! `orchestrator`, `review-monitor`, and `merge-release` roles MUST run on strong or review-capable agents; dispatchers MUST NOT route these roles to cheap leaf backends.
|
|
@@ -460,6 +460,7 @@ These rules bind **orchestrators** dispatching implementation, fix, or review-cy
|
|
|
460
460
|
|
|
461
461
|
- ! Long-running workers (expected >~3 min: implementation, fix batches, review-cycle owners, pollers) MUST be dispatched independently / in the background so the parent conversation channel stays interactive and the orchestrator is notified on completion (`DONE` / `BLOCKED` / `FAILED` per §11).
|
|
462
462
|
- ! On Cursor, background dispatch means the Task tool's background path (`run_in_background: true` on the Task invocation) — NOT blocking the orchestrator's turn for the worker's full wall-clock.
|
|
463
|
+
- ! On OpenClaw, background dispatch means `sessions_spawn` (optionally with `visible` so the Control UI can watch the subagent) so the parent session stays interactive; the completion channel is **parent push / announce**, not `get_command_or_subagent_output` and not Cursor Task completion (#2874 / #2879). Nested leaf-spawn-leaf limits mirror Cursor #2797 when the platform does not support reliable nested `sessions_spawn`.
|
|
463
464
|
- ⊗ Foreground/blocking dispatch for long-running implementation, fix, or review-cycle workers when a background/independent dispatch primitive is available — blocking locks the conversation and prevents user steerability (#1878 / Gap D).
|
|
464
465
|
- ~ Foreground dispatch is reserved for short tasks (<~3 min): quick probes, single-command checks, terse status reads.
|
|
465
466
|
|
|
@@ -490,7 +491,7 @@ Reference: scope-expansion comment 4399553752 on issue #954.
|
|
|
490
491
|
|
|
491
492
|
## 10.5 Heartbeat contract (#1365)
|
|
492
493
|
|
|
493
|
-
Long-running `spawn_subagent` review-cycle agents on the Grok Build hybrid swarm path can go completely dark from the monitor's perspective -- no commits, no PR comments, no completion notifications. The #1166 swarm session demonstrated the failure mode: two of three dispatched pollers produced zero observable signals; the monitor could not distinguish stalled from healthy.
|
|
494
|
+
Long-running `spawn_subagent` review-cycle agents on the Grok Build hybrid swarm path can go completely dark from the monitor's perspective -- no commits, no PR comments, no completion notifications. The same visibility gap applies to OpenClaw `sessions_spawn` and Cursor `Task` pollers. The #1166 swarm session demonstrated the failure mode: two of three dispatched pollers produced zero observable signals; the monitor could not distinguish stalled from healthy.
|
|
494
495
|
|
|
495
496
|
The heartbeat contract closes that gap. Any sub-agent whose tool loop is expected to run for more than ~3 minutes (review-cycle pollers, watchdogs, long-running implementation agents) MUST emit a small JSON heartbeat at `<project-root>/.deft-scratch/subagent-status/<agent-id>.json` per `docs/subagent-heartbeat.md`.
|
|
496
497
|
|
|
@@ -506,6 +507,10 @@ The parent monitor watches the heartbeat file directly (three-state exit 0 ok /
|
|
|
506
507
|
|
|
507
508
|
! **Cursor false-alive / REDISPATCH_OK (#2824):** On the Cursor `Task` path, the host may report a leaf as "still running" after it has gone silent (empty transcript, no heartbeats, no DONE/FAILED). When `task verify:subagent-alive` exits `1` for a registered in-flight `drive-to: merge*` worker — missing heartbeat, STALE heartbeat, or no recent git/PR activity — the monitor MUST treat the worker as dead and print `REDISPATCH_OK` to authorize takeover re-dispatch. Do NOT block on host resume when the liveness gate has failed closed.
|
|
508
509
|
|
|
510
|
+
! **OpenClaw `sessions_spawn` / heartbeat mapping (#2879):** Same file-heartbeat contract applies to OpenClaw review-monitors and long-running leaves. OpenClaw host session liveness, Control UI presence, or gateway channel reachability does NOT replace periodic heartbeats — those signals only prove the session exists, not that the tool loop is progressing. OpenClaw pollers write `.deft-scratch/subagent-status/<agent-id>.json` so `task agent:monitor` / `task verify:subagent-alive` can detect stalled monitors; OpenClaw-native session status MAY be a *supplementary* signal only. Host "still running" + missing/STALE heartbeat authorizes the same `REDISPATCH_OK` posture as Cursor #2824.
|
|
511
|
+
|
|
512
|
+
! **Parent ensures scratch dir + startup grace before REDISPATCH_OK (#2879):** `task verify:subagent-alive` exits `2` (config error, no `REDISPATCH_OK`) when the scratch directory is **missing** and has no records. Parents MUST `mkdir` the worker worktree's `.deft-scratch/subagent-status/` at dispatch time so a later missing record is exit `1` + `REDISPATCH_OK`. Parents MUST ALSO wait a **startup grace** (default 3 minutes from dispatch, or until the first `phase: "starting"` heartbeat is observed) before treating a missing required-agent as takeover-eligible — probing an empty parent-created dir immediately races a healthy worker still writing its first heartbeat and can spawn a duplicate. Exit `2` remains reserved for true config errors (bad args / wrong path).
|
|
513
|
+
|
|
509
514
|
- Monitors run `task verify:subagent-alive -- --require-agent <agent-id> [--scratch-dir <worktree>/.deft-scratch/subagent-status]` each poll iteration.
|
|
510
515
|
- Workers run `task agent:monitor` (raw sweep) or the gate verb above; both wrap `subagent-monitor` (#1365).
|
|
511
516
|
|
|
@@ -518,6 +523,12 @@ Every worker MUST send a final status message before exiting its tool loop, rega
|
|
|
518
523
|
- Failure: `FAILED: <reason> + recovery hint`
|
|
519
524
|
- Stand-down: `STOOD-DOWN: <reason>` (e.g. user said "wait" with no follow-up dispatch)
|
|
520
525
|
|
|
526
|
+
! **`drive-to: merge-ready` DONE reservation (#2843):** When the dispatch envelope scoped `drive-to: merge-ready` (or `drive-to: merge`), `DONE` is reserved for merge-ready completion — `task pr:merge-ready -- <N>` exit 0 on current HEAD, or merge + `task scope:complete` when the envelope included merge authority. Greptile P0/P1 outstanding, CI failure, branch behind, review-cycle cap, or any other merge blocker MUST NOT exit as `DONE`.
|
|
527
|
+
|
|
528
|
+
! **Mid-cycle BLOCKED contract (#2843):** A `drive-to: merge-ready` worker that must exit before merge-ready (blocker, cap, context limit, host turn budget) MUST emit `BLOCKED:` (never `DONE`) with: PR number (or `no-pr`), HEAD SHA, blocker class (`greptile_p0_p1` / `ci_failures` / `behind_base` / `review_cycle_cap` / `context_limit` / other), worktree path, and `REDISPATCH_OK` when a continuation leaf should take over. Example: `BLOCKED: Greptile P1 on HEAD abc1234 (PR #2842, blocker greptile_p0_p1, worktree .deft-scratch/worktrees/2839-appsec, REDISPATCH_OK)`.
|
|
529
|
+
|
|
530
|
+
⊗ Emit `DONE` from a `drive-to: merge-ready` worker while merge-ready is false — a false-terminal `DONE` pulls the cohort monitor into inline Greptile fixes and violates Gap D (#2843 monitor-as-implementer recurrence).
|
|
531
|
+
|
|
521
532
|
Per-step acks during the run are noise. ONE start message, ONE final message; intermediate messages only on `BLOCKED` / `FAILED`. The final message lets the dispatcher distinguish a clean exit from a silent timeout when the lifecycle event arrives.
|
|
522
533
|
|
|
523
534
|
## 12. Session ritual + `task verify:cache-fresh` gates before `start_agent` (#1348 / #1127)
|
|
@@ -6,13 +6,14 @@ Canonical Greptile review-cycle / poller sub-agent prompt body.
|
|
|
6
6
|
Used by parent monitor agents when delegating post-PR work via the platform
|
|
7
7
|
dispatch primitive per the parent's Phase 3 runtime capability detection
|
|
8
8
|
(`spawn_subagent` for "grok-build" / Grok Build TUI, `start_agent` for
|
|
9
|
-
Warp-orchestrated,
|
|
10
|
-
`
|
|
11
|
-
|
|
9
|
+
Warp-orchestrated, `sessions_spawn` for OpenClaw, Cursor `Task` with
|
|
10
|
+
`run_in_background: true`, or equivalent in other environments). See
|
|
11
|
+
`skills/deft-directive-swarm/SKILL.md` Phase 3 + #1342 slices 1-3 / #2874
|
|
12
|
+
OpenClaw Tier 1 and the review-cycle skill's updated Approach 1.
|
|
12
13
|
|
|
13
14
|
The parent reads this file and applies Python `str.format(...)` to substitute
|
|
14
15
|
five placeholders, then passes the formatted prompt via the chosen dispatch
|
|
15
|
-
primitive (spawn_subagent, start_agent, etc.):
|
|
16
|
+
primitive (spawn_subagent, start_agent, sessions_spawn, Cursor Task, etc.):
|
|
16
17
|
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
prompt = Path("templates/swarm-greptile-poller-prompt.md").read_text(encoding="utf-8").format(
|
|
@@ -23,7 +24,9 @@ primitive (spawn_subagent, start_agent, etc.):
|
|
|
23
24
|
parent_agent_id="<parent-id>",
|
|
24
25
|
)
|
|
25
26
|
# Dispatch via the detected primitive (example for start_agent shown;
|
|
26
|
-
# use spawn_subagent + the launch adapter for grok-build per #1342
|
|
27
|
+
# use spawn_subagent + the launch adapter for grok-build per #1342;
|
|
28
|
+
# use sessions_spawn for OpenClaw per #2874 / #2879 -- completion is
|
|
29
|
+
# parent push / announce, not get_command_or_subagent_output)
|
|
27
30
|
start_agent(name=f"greptile-poller-{{N}}", prompt=prompt, execution_mode="local")
|
|
28
31
|
|
|
29
32
|
This file is the proven prompt body. Hand-authored variants have repeatedly
|
|
@@ -31,10 +34,11 @@ missed two specific parsing bugs (markdown-link `Last reviewed commit:`,
|
|
|
31
34
|
raw `\b(P0|P1)\b` substring scan with negation false-positive); the body
|
|
32
35
|
below encodes the fixes inline. See #727 (canonical encoding) and
|
|
33
36
|
`skills/deft-directive-swarm/SKILL.md` Phase 6 Sub-Agent Role Separation
|
|
34
|
-
(#1342 platform adapter unification: the platform adapter dispatches
|
|
35
|
-
`spawn_subagent` on grok-build
|
|
36
|
-
this template is platform-agnostic by
|
|
37
|
-
mandate using this template instead of
|
|
37
|
+
(#1342 / #2879 platform adapter unification: the platform adapter dispatches
|
|
38
|
+
via `spawn_subagent` on grok-build, `start_agent` on Warp-orchestrated, and
|
|
39
|
+
`sessions_spawn` on OpenClaw, so this template is platform-agnostic by
|
|
40
|
+
construction) for the rules that mandate using this template instead of
|
|
41
|
+
hand-authoring.
|
|
38
42
|
|
|
39
43
|
NOTE on `.format()` escaping: every literal curly brace in this file is
|
|
40
44
|
doubled (`{{` / `}}`) so it survives the `str.format(...)` pass. The five
|
|
@@ -48,8 +52,12 @@ DO NOT STOP until ONE of the six terminal exit conditions below fires.
|
|
|
48
52
|
## Role posture
|
|
49
53
|
|
|
50
54
|
- Single role: review-cycle agent. Read `skills/deft-directive-review-cycle/SKILL.md` and follow Phase 2 (Review/Fix Loop) end-to-end.
|
|
51
|
-
- Parent agent ID for status messages: `{parent_agent_id}`. Send status updates
|
|
52
|
-
-
|
|
55
|
+
- Parent agent ID for status messages: `{parent_agent_id}`. Send status updates at start, on each terminal exit condition, and on any blocker via the **host completion channel** for your dispatch primitive:
|
|
56
|
+
- Warp / `start_agent`: `send_message_to_agent`
|
|
57
|
+
- grok-build / `spawn_subagent`: spawn result channel / parent announce (parent may poll `get_command_or_subagent_output`)
|
|
58
|
+
- **OpenClaw / `sessions_spawn` (#2879):** parent push / announce (session announce or Control UI–visible completion) -- **not** `get_command_or_subagent_output`, and not Cursor Task completion semantics
|
|
59
|
+
- Cursor `Task` (background): Task completion-notification path
|
|
60
|
+
- Execution: local. Working directory: the worktree the parent gave you (or your `--cwd` if running under `oz agent run --cwd` / OpenClaw session cwd).
|
|
53
61
|
|
|
54
62
|
## Bounded poll loop
|
|
55
63
|
|
|
@@ -533,7 +541,7 @@ Send:
|
|
|
533
541
|
- ! Set `$env:GIT_EDITOR = "true"` (Windows PowerShell) or `GIT_EDITOR=true` (Unix) BEFORE any git command that could open an editor (rebase, commit --amend) to prevent terminal lockup.
|
|
534
542
|
- ! Use Python scripts (single `run_shell_command` call) for the poll loop, NEVER shell `Start-Sleep` + repeated tool calls. The Python script handles `time.sleep({poll_interval_seconds})` between polls and exits when a terminal condition fires.
|
|
535
543
|
- ! Always pass `do_not_summarize_output: true` semantics when fetching `gh pr view --comments` -- summarizers silently drop the Outside-Diff section.
|
|
536
|
-
- ! Send a status message to `{parent_agent_id}` at start (acknowledging the task) and at every terminal exit (CLEAN / NEW P0/P1 FINDINGS escalation / ERRORED / TIMEOUT / STALL). Do NOT silently complete.
|
|
544
|
+
- ! Send a status message to `{parent_agent_id}` at start (acknowledging the task) and at every terminal exit (CLEAN / NEW P0/P1 FINDINGS escalation / ERRORED / TIMEOUT / STALL / INFORMAL-CLEAN). Route it through the host completion channel for your primitive (see Role posture -- OpenClaw `sessions_spawn` uses parent push / announce). Do NOT silently complete.
|
|
537
545
|
|
|
538
546
|
## Implementation Notes
|
|
539
547
|
|
|
@@ -554,3 +562,4 @@ Dogfood lessons captured during the #727 self-review cycle. The template body ab
|
|
|
554
562
|
- #727 -- this template's acceptance issue and the full anti-pattern record (rm-chaining, parsing-bug recurrence, role-conflation in implementation-agent prompts).
|
|
555
563
|
- #1039 -- (5) STALL terminal exit + Tier 1 instrumentation + Tier 3 per-condition fail-loud (`clean_gate_holdout`); the third recurrence in this template's detector-gap chain after #910 (triple-tier) and #1035 (Tier 2.5 + confidence-heading).
|
|
556
564
|
- #1364 -- cohort-level CLEAN verification gate (`task swarm:verify-review-clean`, `scripts/swarm_verify_review_clean.py`). The (1) CLEAN section's swarm-orchestrated terminal contract block declares that only the exact `PR #{pr_number} CLEAN -- ready for merge` subject with `confidence > 3` on current HEAD is an acceptable "review complete" signal for the swarm monitor's Phase 5 -> 6 transition; the cohort verifier picks up any other terminal exit ((2) NEW P0/P1 FINDINGS escalation, (3) ERRORED, (4) TIMEOUT, (5) STALL) and holds the merge gate until fresh poller re-dispatch or explicit user escalation resolves it. Recurrence record: #1166 swarm execution where multiple pollers exited with `clean_gate_holdout=confidence` (confidence == 3) and the monitor still raised the Phase 5 -> 6 gate because the trigger keyed on "all pollers have reported back" rather than "every PR in the cohort is objectively CLEAN".
|
|
565
|
+
- #2879 -- OpenClaw `sessions_spawn` + parent push/announce completion channel named in Role posture (alongside Warp `start_agent` and grok-build `spawn_subagent`); heartbeat mapping in `docs/subagent-heartbeat.md` and preamble §10.5. Epic #2874.
|