taskforce-loop-engineering 0.9.1 → 0.12.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 +23 -0
- package/MIGRATING.md +47 -2
- package/README.md +81 -7
- package/bin/loop-engineering.mjs +181 -0
- package/docs/architecture.md +444 -0
- package/docs/multi-agent-control-plane.md +31 -0
- package/docs/operator-dashboard.md +27 -0
- package/docs/release-0.12-acceptance.md +35 -0
- package/lib/action-reservations.mjs +196 -0
- package/lib/core.mjs +230 -14
- package/lib/operator-dashboard.mjs +198 -0
- package/lib/todo-control-plane.mjs +287 -0
- package/package.json +3 -2
- package/scripts/action-reservation-self-test.mjs +65 -0
- package/scripts/hermes-install-self-test.mjs +2 -0
- package/scripts/hermes-install.mjs +40 -25
- package/scripts/human-gate-lifecycle-v2-self-test.mjs +81 -0
- package/scripts/openclaw-install-self-test.mjs +19 -5
- package/scripts/openclaw-install.mjs +101 -37
- package/scripts/openclaw-manage.mjs +1 -1
- package/scripts/operator-dashboard-self-test.mjs +74 -0
- package/scripts/route-notify-self-test.mjs +7 -0
- package/scripts/todo-control-plane-self-test.mjs +74 -0
- package/templates/operator-projection.schema.json +1 -0
- package/templates/todo.schema.json +28 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
# Taskforce Loop Engineering Architecture
|
|
2
|
+
|
|
3
|
+
## P3 derived operator plane
|
|
4
|
+
|
|
5
|
+
`lib/operator-dashboard.mjs` is a one-way projection boundary above durable Loop artifacts. It reads P0 gate, P1 reservation, P2 control-plane, queue and project files and emits projection schema v1. It never calls their mutation functions and never serves raw artifacts. Live HTTP and static export share the same projection function, so the UI cannot become a source of truth.
|
|
6
|
+
|
|
7
|
+
Loop engineering wraps repeated agent work in a small, inspectable cycle:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Trigger -> Load state -> Sense -> Choose -> Act/Check -> Verify -> Record -> Stop or schedule next run
|
|
11
|
+
|
|
12
|
+
## Parked waits and recovery
|
|
13
|
+
|
|
14
|
+
Human-Gate Lifecycle v2 stores both human-input and external-condition waits in
|
|
15
|
+
the existing `waiting/` queue directory. A v2 task has a `parked` envelope with
|
|
16
|
+
its wait kind, policy, reminder/escalation counters, authorization snapshot,
|
|
17
|
+
recovery proof hash, and exactly-once execution boundary. `queue-wait-tick`
|
|
18
|
+
writes one evidence artifact per notification sequence before another process
|
|
19
|
+
can advance that sequence; repeated or restarted ticks are throttled or observe
|
|
20
|
+
the existing evidence. A timeout parks and escalates—it is not task failure and
|
|
21
|
+
does not authorize action retry.
|
|
22
|
+
|
|
23
|
+
Recovery is a separate transition. `queue-wait-resume` requires an explicit
|
|
24
|
+
verified signal, hashes the signal into durable state, preserves authorization
|
|
25
|
+
and execution metadata, then atomically writes the task back to `inbox/` before
|
|
26
|
+
removing the waiting copy. Repeating resume after a crash returns
|
|
27
|
+
`already_resumed`, keeping the action boundary exactly once.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This package implements the conservative foundation of that idea for OpenClaw
|
|
31
|
+
and Codex-style agents:
|
|
32
|
+
|
|
33
|
+
- deterministic CLI runner, no hidden model call
|
|
34
|
+
- JSON loop specs
|
|
35
|
+
- local state and append-only run artifacts
|
|
36
|
+
- command, file, and structured JSON value checks
|
|
37
|
+
- circuit breaker for repeated failures
|
|
38
|
+
- generic queue runner for explicit task handoffs
|
|
39
|
+
- assisted code queues that isolate edits in git worktrees
|
|
40
|
+
- cron wrapper that stays silent on success and surfaces non-zero exits
|
|
41
|
+
- bundled skill that teaches agents when to use the loop workflow
|
|
42
|
+
|
|
43
|
+
Structured `json-value` checks use RFC 6901 pointers and preserve expected and
|
|
44
|
+
actual values in run evidence. The read-only `repair-plan` command turns failed
|
|
45
|
+
checks into review findings; it deliberately has no apply mode.
|
|
46
|
+
|
|
47
|
+
## Levels
|
|
48
|
+
|
|
49
|
+
- `L1`: report-only. May run read-only checks and write local run artifacts.
|
|
50
|
+
- `L2`: assisted action. May prepare local changes in isolated worktrees,
|
|
51
|
+
run verification, and leave artifacts for human review.
|
|
52
|
+
- `L3`: unattended-capable. Intended for future explicit allowlists,
|
|
53
|
+
verification budgets, human gates, and proven run history.
|
|
54
|
+
|
|
55
|
+
The loop-spec runner remains designed around `L1`. The queue runner supports a
|
|
56
|
+
bounded `L2` mode through `worktree.enabled`: it creates local worktrees and
|
|
57
|
+
records evidence, but it does not push, merge, delete worktrees, or perform
|
|
58
|
+
external writes.
|
|
59
|
+
|
|
60
|
+
## Dev / Acceptance Split
|
|
61
|
+
|
|
62
|
+
The next queue architecture for non-trivial tasks is a two-team loop:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Task intake
|
|
66
|
+
-> task contract
|
|
67
|
+
-> acceptance plan + development plan
|
|
68
|
+
-> development checkpoint
|
|
69
|
+
-> acceptance review
|
|
70
|
+
-> development revision
|
|
71
|
+
-> final judge
|
|
72
|
+
-> report / gate / apply
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Development owns implementation and local evidence. Acceptance owns proof:
|
|
76
|
+
functional checks, regression checks, edge cases, negative tests, manual review,
|
|
77
|
+
and automation suggestions. The final judge is separate from both and verifies
|
|
78
|
+
that the result still matches the original task contract and risk gates.
|
|
79
|
+
|
|
80
|
+
The important artifact names are:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
task_contract.json
|
|
84
|
+
acceptance_plan.json
|
|
85
|
+
dev_plan.json
|
|
86
|
+
checkpoint_review.json
|
|
87
|
+
final_judgement.json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This model should fit on top of the current queue runner rather than replace
|
|
91
|
+
it. The queue still owns leases, preflight, active/done/failed state, and run
|
|
92
|
+
artifacts; the task subdirectory owns multi-round collaboration evidence.
|
|
93
|
+
|
|
94
|
+
`v0.4` starts with deterministic planning artifacts. `run-queue` writes
|
|
95
|
+
`runtime/loops/<queue>/tasks/<task_id>/task_contract.json`,
|
|
96
|
+
`acceptance_plan.json`, `dev_plan.json`, `checkpoints/`, and `reviews/` before
|
|
97
|
+
preflight and dispatch, then writes `final_judgement.json` after acceptance
|
|
98
|
+
review and `revision_request.json` when the final judgement needs another
|
|
99
|
+
development pass. It exposes the planning directories to the dispatcher as
|
|
100
|
+
`LOOP_TASK_CONTRACT_FILE`, `LOOP_ACCEPTANCE_PLAN_FILE`, `LOOP_DEV_PLAN_FILE`,
|
|
101
|
+
`LOOP_CHECKPOINTS_DIR`, and `LOOP_REVIEWS_DIR`, then records the contract path,
|
|
102
|
+
inferred risk level, human-gate flag, acceptance plan path, check counts, dev
|
|
103
|
+
plan path, planned checkpoint count, produced checkpoint files, and acceptance
|
|
104
|
+
review files, final judgement outcome, and revision request summary in the run
|
|
105
|
+
artifact. A completed dispatch whose acceptance review still needs changes is
|
|
106
|
+
marked `needs_revision` instead of completed.
|
|
107
|
+
|
|
108
|
+
`queue-revision-next` turns a failed `needs_revision` task into a fresh queued
|
|
109
|
+
revision task using `revision_request.json`. It preserves the failed source
|
|
110
|
+
task and run artifacts, then embeds the revision goals and next checkpoint id
|
|
111
|
+
in the new task body.
|
|
112
|
+
|
|
113
|
+
`revisionPolicy` is checked at this handoff point so persistence does not become
|
|
114
|
+
mechanical repetition. The default policy allows up to 3 revision rounds and
|
|
115
|
+
blocks another next-round enqueue when two consecutive attempts have the same
|
|
116
|
+
revision-goal signature. Revision task bodies include anti-loop instructions
|
|
117
|
+
requiring the next agent to change diagnosis, tactic, evidence, or verification;
|
|
118
|
+
a human can still override the guard with `queue-revision-next --force`.
|
|
119
|
+
|
|
120
|
+
`queue-lineage` is the read-only attempt graph view. It can start from any task
|
|
121
|
+
in the chain and returns the root task id, current path, revision edges, known
|
|
122
|
+
attempts, checkpoint/review summaries, final judgement outcomes, and revision
|
|
123
|
+
request status. Every queue run artifact also embeds the same lineage summary
|
|
124
|
+
after the task is moved to its final state.
|
|
125
|
+
|
|
126
|
+
`queue-lineage-bundle` renders that attempt graph into a Markdown human review
|
|
127
|
+
bundle and JSON sidecar under `runtime/loops/<queue>/lineage-bundles/`. The
|
|
128
|
+
bundle is intended for handoff: it summarizes what changed in each round, why
|
|
129
|
+
acceptance failed, how the next round was requested, and whether the latest
|
|
130
|
+
round is ready for human review.
|
|
131
|
+
|
|
132
|
+
`queue-human-decision` is the explicit human gate. It records `approve`,
|
|
133
|
+
`request_changes`, or `reject` in
|
|
134
|
+
`runtime/loops/<queue>/tasks/<task_id>/human_review_decision.json`. When the
|
|
135
|
+
decision is `request_changes`, it also writes `human_revision_request.json`
|
|
136
|
+
with the human feedback converted into revision goals. `queue-revision-next`
|
|
137
|
+
can use that human request to create the next round, so mid-project feedback is
|
|
138
|
+
tracked as first-class lineage rather than lost in chat. The dispatcher also
|
|
139
|
+
receives `LOOP_HUMAN_REVIEW_DECISION_FILE` and
|
|
140
|
+
`LOOP_HUMAN_REVISION_REQUEST_FILE`, so long-running development agents can
|
|
141
|
+
poll for human feedback while the task is still active.
|
|
142
|
+
|
|
143
|
+
## Project Intake Layer
|
|
144
|
+
|
|
145
|
+
`project-intake` sits above the queue runner. Queue task intake turns one
|
|
146
|
+
already-scoped task into a task contract, acceptance plan, and development plan.
|
|
147
|
+
Project intake turns an unscoped project brief into the first queue-ready shape:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
human brief
|
|
151
|
+
-> project spec
|
|
152
|
+
-> conservative action policy
|
|
153
|
+
-> queue config
|
|
154
|
+
-> initial backlog
|
|
155
|
+
-> existing queue runner / scheduler
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Project specs live under:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
configs/loops/projects/<project>.json
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Project artifacts live under:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
runtime/loops/projects/<project>/intake/
|
|
168
|
+
runtime/loops/projects/<project>/plans/
|
|
169
|
+
runtime/loops/projects/<project>/backlog/
|
|
170
|
+
runtime/loops/projects/<project>/status/
|
|
171
|
+
runtime/loops/projects/<project>/reports/
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Conversation-facing integrations use a deterministic provenance layer:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
source message
|
|
178
|
+
-> route-message (status | execute | direct)
|
|
179
|
+
-> status: summarize only
|
|
180
|
+
-> execute: enqueue with source metadata and model_assessed risk
|
|
181
|
+
-> queue terminal state
|
|
182
|
+
-> queue-terminal-notify
|
|
183
|
+
-> source conversation
|
|
184
|
+
|
|
185
|
+
checkpoint marked blocked / needs_human_input
|
|
186
|
+
-> queue-human-input-notify
|
|
187
|
+
|
|
188
|
+
The OpenClaw installer generates a channel-neutral notifier. It uses the
|
|
189
|
+
recorded task source with `openclaw message send` after each wrapper tick, so a
|
|
190
|
+
later terminal state or human gate can return to the originating conversation.
|
|
191
|
+
Notification ledgers keep retries idempotent, and missing channel/target data
|
|
192
|
+
fails closed rather than guessing a recipient.
|
|
193
|
+
-> waiting_for_human gate + source-bound prompt
|
|
194
|
+
-> correlated `LOOP <gate-id> <input>` reply
|
|
195
|
+
-> queue-human-input-resolve
|
|
196
|
+
-> response ledger + blocked task requeue
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The router owns intent and provenance, not topic-level safety classification.
|
|
200
|
+
Concrete action assessment belongs to the planner/executor and their applicable
|
|
201
|
+
authorization policy. Terminal delivery is idempotent per task/status and can
|
|
202
|
+
be recovered by rescanning the queue.
|
|
203
|
+
|
|
204
|
+
## Goal-directed execution
|
|
205
|
+
|
|
206
|
+
A queue dispatcher should treat an attempt failure as evidence, not as proof
|
|
207
|
+
that the task goal failed. Goal-oriented controllers use this state machine:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
goal -> plan -> attempt -> verify/diagnose
|
|
211
|
+
^ |
|
|
212
|
+
|-- replan <---|
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The diagnoser emits one of `goal_achieved`, `retry_same_strategy`,
|
|
216
|
+
`change_strategy`, `investigate`, `waiting_for_human`, or `goal_unreachable`.
|
|
217
|
+
Only achieved, proven unreachable, or a concrete human-input gate closes the
|
|
218
|
+
online exploration loop. Budget exhaustion becomes `exploration_exhausted`,
|
|
219
|
+
which remains actionable rather than being collapsed into a generic failure.
|
|
220
|
+
Every changed strategy carries a normalized fingerprint so repeated plans can
|
|
221
|
+
trip a bounded breaker.
|
|
222
|
+
|
|
223
|
+
The intake layer is deterministic and conservative. It classifies the brief
|
|
224
|
+
into a project type, chooses a template, writes deliverables, acceptance
|
|
225
|
+
criteria, risk gates, checks, assumptions, and a first backlog. It only stops
|
|
226
|
+
for blocking questions; non-blocking uncertainty becomes explicit assumptions
|
|
227
|
+
so the project can start with safe defaults. It does not enqueue or execute
|
|
228
|
+
work by itself.
|
|
229
|
+
|
|
230
|
+
`project-plan` is the solidification step. It writes the project config, creates
|
|
231
|
+
or updates the queue config, writes the initial backlog artifact, and refreshes
|
|
232
|
+
the human-readable project plan. Code-oriented projects use code worktree
|
|
233
|
+
queues. Research, content, operations, QA, knowledge-base, infra-audit, and
|
|
234
|
+
assistant workflows use standard artifact queues.
|
|
235
|
+
|
|
236
|
+
`project-status` gives a read-only project-level view across queues. It
|
|
237
|
+
aggregates queue counts, the initial backlog artifact, the latest intake
|
|
238
|
+
artifact, and simple attention reasons. It intentionally delegates detailed
|
|
239
|
+
execution state to existing queue commands such as `queue-status`,
|
|
240
|
+
`code-task-status`, `code-task-dashboard`, and `summarize`.
|
|
241
|
+
|
|
242
|
+
## Queue Runner
|
|
243
|
+
|
|
244
|
+
`v0.2.0` added a durable queue for explicit loop-managed task handoffs:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
loop-engineering enqueue \
|
|
248
|
+
--queue agent-tasks \
|
|
249
|
+
--title "Check target app logs" \
|
|
250
|
+
--task "Inspect the latest logs and summarize blockers."
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
loop-engineering run-queue \
|
|
255
|
+
--queue agent-tasks \
|
|
256
|
+
--preflight-config configs/loops/workspace-health.json \
|
|
257
|
+
--dispatcher "node scripts/dispatch-task.mjs" \
|
|
258
|
+
--timeout-ms 1800000
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`run-queue-drain` is available for explicit batch and daemon workflows. It
|
|
262
|
+
repeatedly invokes the single-task runner until the inbox is empty or the
|
|
263
|
+
bounded `--max-tasks` limit is reached. Conversation-facing integrations use a
|
|
264
|
+
different rule: a new explicit loop request supersedes the active task. The
|
|
265
|
+
router writes `supersede_request.json`, links the replacement with
|
|
266
|
+
`supersedesTaskId`, and the runner stops the old dispatcher process group or
|
|
267
|
+
stops at the next planning/preflight checkpoint. The old task reaches the
|
|
268
|
+
auditable `superseded` state before the replacement acquires the queue lock.
|
|
269
|
+
An explicit continuation such as `继续当前 loop,补充要求:…` follows a separate
|
|
270
|
+
amendment path. It does not enqueue or cancel anything. The router appends a
|
|
271
|
+
versioned amendment artifact, updates all three planning artifacts, and exposes
|
|
272
|
+
the live amendment file to the existing dispatcher session. Checkpoints record
|
|
273
|
+
the applied amendment version so acceptance can prove the supplement was used.
|
|
274
|
+
|
|
275
|
+
The conversation adapter also supplies a live progress notifier. Queue progress
|
|
276
|
+
events are filtered into ordered milestones and returned to the task's recorded
|
|
277
|
+
source. A five-minute dispatch heartbeat prevents silent long runs, while a
|
|
278
|
+
checkpoint watcher immediately surfaces new worker checkpoints. Per-task
|
|
279
|
+
notification ledgers make milestone delivery idempotent and auditable.
|
|
280
|
+
|
|
281
|
+
The dispatcher is deliberately external to the package. It receives task data
|
|
282
|
+
through environment variables such as `LOOP_TASK_BODY`, `LOOP_TASK_FILE`, and
|
|
283
|
+
`LOOP_RUN_ID`, so each workspace can decide how to hand off work without baking
|
|
284
|
+
private machine paths or credentials into public templates.
|
|
285
|
+
|
|
286
|
+
Queue command execution uses an isolated process group. When a dispatcher,
|
|
287
|
+
preflight, or verification command times out, the runner sends SIGTERM and then
|
|
288
|
+
SIGKILL to the whole process group so child processes do not survive the failed
|
|
289
|
+
run. This matters for device and instrumentation work where a shell wrapper may
|
|
290
|
+
spawn long-lived `adb`, `frida`, `tcpdump`, or proxy processes.
|
|
291
|
+
|
|
292
|
+
Dispatcher retry is also failure-aware. The queue `retry` config can list
|
|
293
|
+
`requiresHumanActionPatterns`; matching output marks the run
|
|
294
|
+
`needs_human_input` and stops retry. Defaults cover common device authorization,
|
|
295
|
+
permission, and explicit human-approval blockers, including
|
|
296
|
+
`INSTALL_FAILED_USER_RESTRICTED`. These states are treated as blocked human
|
|
297
|
+
gates rather than development failures, so `queue-revision-next` does not turn a
|
|
298
|
+
phone permission prompt into repeated automated attempts.
|
|
299
|
+
|
|
300
|
+
Recoverable model-runtime failures use a separate path. Transcript-compaction
|
|
301
|
+
timeouts, command timeouts, selected transport failures, and rate limits are
|
|
302
|
+
classified as `runtime_interrupted`; they do not create a development revision
|
|
303
|
+
request or invalidate accepted checkpoints. The same task returns to `inbox/`
|
|
304
|
+
with an incremented session generation, so the workspace dispatcher creates a
|
|
305
|
+
fresh worker session and resumes from the durable contract, amendments,
|
|
306
|
+
checkpoints, and reviews. `retry.runtimeRecoveryMaxAttempts` bounds automatic
|
|
307
|
+
recovery before the task becomes `runtime_blocked`. Long project sessions also
|
|
308
|
+
rotate proactively after `retry.sessionMaxTicks` successful continuation ticks
|
|
309
|
+
(default 10), preventing transcript growth from becoming project state.
|
|
310
|
+
|
|
311
|
+
## Code Worktree Queue
|
|
312
|
+
|
|
313
|
+
`v0.3.0` adds assisted code queues:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
loop-engineering code-queue-init --queue code-tasks
|
|
317
|
+
loop-engineering enqueue --queue code-tasks --title "Fix parser" --task "Patch the parser and run tests."
|
|
318
|
+
loop-engineering run-queue --config configs/loops/queues/code-tasks.json
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
When `worktree.enabled` is true, the runner:
|
|
322
|
+
|
|
323
|
+
1. Runs the optional preflight loop in the main workspace.
|
|
324
|
+
2. Creates `git worktree add -b <branch> <path> HEAD`.
|
|
325
|
+
3. Runs the dispatcher with cwd set to the worktree.
|
|
326
|
+
4. Runs configured `verifyCommands`.
|
|
327
|
+
5. Records branch, worktree path, verification results, git status, diff
|
|
328
|
+
summaries, and untracked files in the run artifact.
|
|
329
|
+
|
|
330
|
+
This keeps code-changing work reviewable without giving the loop authority to
|
|
331
|
+
ship changes.
|
|
332
|
+
|
|
333
|
+
`v0.3.1` adds read-only worktree artifact inspection:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
loop-engineering code-worktree-list --queue code-tasks
|
|
337
|
+
loop-engineering code-worktree-inspect --queue code-tasks --task-id <id>
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
These commands summarize the recorded branch, path, dirty state, verification
|
|
341
|
+
status, diff summaries, and untracked files. They do not remove worktrees or
|
|
342
|
+
change git state.
|
|
343
|
+
|
|
344
|
+
`v0.3.2` adds read-only patch review:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
loop-engineering code-worktree-diff --queue code-tasks --task-id <id>
|
|
348
|
+
loop-engineering code-worktree-diff --queue code-tasks --run-id <id> --json
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The command resolves the recorded worktree path from the run artifact, keeps it
|
|
352
|
+
inside the workspace root, and prints `git diff --stat HEAD`, `git diff
|
|
353
|
+
--name-status HEAD`, `git diff --binary HEAD`, and untracked file names. It
|
|
354
|
+
does not checkout, stage, commit, push, merge, delete, or modify queue state.
|
|
355
|
+
|
|
356
|
+
`v0.3.3` adds durable patch export artifacts:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
loop-engineering code-worktree-export --queue code-tasks --task-id <id>
|
|
360
|
+
loop-engineering code-worktree-export --queue code-tasks --run-id <id> --output review.patch --json
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
The command writes a patch file plus JSON manifest for the recorded worktree.
|
|
364
|
+
By default the files go under `runtime/loops/<queue>/patches/`, and existing
|
|
365
|
+
exports are not overwritten unless `--force` is set. This gives humans and
|
|
366
|
+
follow-up tools a stable review artifact while still avoiding checkout, stage,
|
|
367
|
+
commit, push, merge, deletion, or queue-state changes.
|
|
368
|
+
|
|
369
|
+
## Artifacts
|
|
370
|
+
|
|
371
|
+
Loop specs store state and runs under the target workspace:
|
|
372
|
+
|
|
373
|
+
```text
|
|
374
|
+
runtime/loops/<loop_id>/state.json
|
|
375
|
+
runtime/loops/<loop_id>/runs/*.json
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Queue runs use:
|
|
379
|
+
|
|
380
|
+
```text
|
|
381
|
+
runtime/loops/<queue>/inbox/
|
|
382
|
+
runtime/loops/<queue>/active/
|
|
383
|
+
runtime/loops/<queue>/done/
|
|
384
|
+
runtime/loops/<queue>/failed/
|
|
385
|
+
runtime/loops/<queue>/canceled/
|
|
386
|
+
runtime/loops/<queue>/runs/
|
|
387
|
+
runtime/loops/<queue>/worktrees/
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Run artifacts are meant to be compact evidence, not raw logs. Long-term memory
|
|
391
|
+
or external summaries should keep only distilled facts, such as recurring
|
|
392
|
+
failure signatures, accepted human gates, or a loop's current health status.
|
|
393
|
+
|
|
394
|
+
## Cron Pattern
|
|
395
|
+
|
|
396
|
+
Install the package globally, then run one tick from cron or a scheduler:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
LOOP_WORKDIR=/path/to/workspace \
|
|
400
|
+
run-loop-cron.sh configs/loops/workspace-health.json
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Set `LOOP_ALERT_COMMAND` to a command that accepts one message argument if your
|
|
404
|
+
environment should send an alert when the runner exits non-zero.
|
|
405
|
+
|
|
406
|
+
## Adaptive Queue Scheduler
|
|
407
|
+
|
|
408
|
+
`queue-scheduler-tick` adds a durable cadence layer for queue runners without
|
|
409
|
+
turning the package into a resident daemon:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
loop-engineering queue-scheduler-tick --config configs/loops/queues/agent-tasks.json
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
The command treats 10 minutes as the bootstrap interval, then records
|
|
416
|
+
`runtime/loops/<queue>/scheduler/state.json` with the latest queue status,
|
|
417
|
+
outcome group, current interval, reasons, and `nextRunAt`. External schedulers
|
|
418
|
+
can wake it frequently; the tick itself decides whether the queue is due.
|
|
419
|
+
|
|
420
|
+
Cadence changes are outcome-driven:
|
|
421
|
+
|
|
422
|
+
- successful work with more queued tasks speeds up toward `minInterval`
|
|
423
|
+
- empty queues back off toward `maxInterval`
|
|
424
|
+
- failures back off
|
|
425
|
+
- human gates back off harder than ordinary failures
|
|
426
|
+
- long runs force the next interval above the observed duration
|
|
427
|
+
|
|
428
|
+
Queue config can set strategy bounds such as `initialInterval`, `minInterval`,
|
|
429
|
+
`maxInterval`, factors, and jitter. These are guardrails, not a fixed interval;
|
|
430
|
+
the persisted scheduler state owns the live cadence.
|
|
431
|
+
# Action Reservation Contract
|
|
432
|
+
|
|
433
|
+
Side-effect adapters use a shared durable state machine:
|
|
434
|
+
|
|
435
|
+
`reserved -> claimed -> settled` or `reserved/claimed -> released`.
|
|
436
|
+
|
|
437
|
+
A claim whose lease expires transitions to `unknown`; it cannot be claimed
|
|
438
|
+
again until authoritative reconciliation reports `accepted` or `not_accepted`.
|
|
439
|
+
Atomic per-key mutation, monotonic fencing tokens, immutable request and
|
|
440
|
+
authorization fingerprints, and terminal evidence make replay across restart,
|
|
441
|
+
revision, resume, and concurrent workers logically exactly once. Physical
|
|
442
|
+
exactly-once behavior still requires the upstream provider to honor the same
|
|
443
|
+
idempotency key or expose a read-only outcome lookup; absent that, the action
|
|
444
|
+
stays unknown rather than risking a duplicate.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Multi-Agent Control Plane (P2)
|
|
2
|
+
|
|
3
|
+
P2 stores typed todos, registered agents, leases, handoffs, and ownership history in `runtime/loops/control-plane/state.json`. Every mutation is serialized by an atomic filesystem mutex and committed with rename. `audit.jsonl` records each ownership transition.
|
|
4
|
+
|
|
5
|
+
## Todo contract
|
|
6
|
+
|
|
7
|
+
Every todo has a stable id, dependencies, deterministic priority, risk and authority class, required capabilities, an acceptance contract, evidence requirements, a quota/cost envelope, lineage/context, authorization, idempotency keys, and an explicit state. See `templates/todo.schema.json`.
|
|
8
|
+
|
|
9
|
+
Eligibility is deterministic: descending priority, then creation time, then id. A todo is claimable only when dependencies are complete, the agent has every capability and the authority grant, quota is sufficient, the P0 human gate is runnable, and every P1 action outcome is safe. An unknown or stale in-flight action requires reconciliation before reassignment.
|
|
10
|
+
|
|
11
|
+
Claims carry a monotonically increasing fencing token. Renew/release require the active owner, current token, and live lease. Expired claims are recovered as runnable only when no parked gate or unresolved action can cause duplicate effects.
|
|
12
|
+
|
|
13
|
+
Handoff packets durably preserve lineage, context, evidence, authorization, idempotency keys, and the source fencing token. The target rechecks eligibility on acceptance and receives a new fencing token. Rejection restores the source claim while its lease is live.
|
|
14
|
+
|
|
15
|
+
## CLI
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
agent-register --agent-json agent.json
|
|
19
|
+
todo-create --todo-json todo.json
|
|
20
|
+
todo-list [--state runnable]
|
|
21
|
+
todo-inspect --todo-id ID
|
|
22
|
+
todo-claim --agent-id AGENT [--todo-id ID] [--lease-ms N]
|
|
23
|
+
todo-renew --todo-id ID --agent-id AGENT --fencing-token N [--lease-ms N]
|
|
24
|
+
todo-release --todo-id ID --agent-id AGENT --fencing-token N [--completed] [--evidence TEXT]
|
|
25
|
+
todo-handoff --todo-id ID --agent-id AGENT --target-agent-id AGENT --fencing-token N [--handoff-id ID]
|
|
26
|
+
todo-accept|todo-reject --handoff-id ID --agent-id AGENT
|
|
27
|
+
todo-recover [--now EPOCH_MS]
|
|
28
|
+
todo-import-legacy
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`--todo-json` and `--agent-json` accept either an inline JSON object or a file path. All commands accept `--root` and emit JSON.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Operator Dashboard and projection API
|
|
2
|
+
|
|
3
|
+
P3 provides a local-first, read-only view over durable Loop Engineering artifacts. It does not maintain a database, lock queue state, or write beneath `runtime/loops`. Every live request rebuilds a normalized projection; static export writes only to the explicitly selected output directory.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
loop-engineering dashboard-inspect --root /path/to/workspace --json
|
|
9
|
+
loop-engineering dashboard-inspect --state waiting_for_human --query approval --root /path/to/workspace --json
|
|
10
|
+
loop-engineering dashboard-health --max-age-seconds 3600 --root /path/to/workspace --json
|
|
11
|
+
loop-engineering dashboard-export --output-dir /tmp/loop-dashboard --root /path/to/workspace --json
|
|
12
|
+
loop-engineering dashboard-serve --root /path/to/workspace
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`dashboard-serve` binds to `127.0.0.1` and an ephemeral port by default. A wider bind is rejected unless `--allow-non-loopback` is explicit. The server has no authentication and is intended for trusted local use. The CLI never starts it during checks or installation.
|
|
16
|
+
|
|
17
|
+
Endpoints are `GET /api/v1/overview`, `/api/v1/health`, `/api/v1/todos`, `/api/v1/todos/:id`, and `/api/v1/actions`. Overview and todo lists support `q` and `state` filters. Private raw files are not served.
|
|
18
|
+
|
|
19
|
+
## Projection and security rules
|
|
20
|
+
|
|
21
|
+
The schema is versioned as `1.0.0` in `templates/operator-projection.schema.json`. P0 parked human/external gates, reminders/escalations and next wake metadata are normalized alongside P1 reservations/reconciliation and P2 typed todos, owners, fencing leases and handoffs. Existing queue/project artifacts are projected as version 1 inputs when no source version exists.
|
|
22
|
+
|
|
23
|
+
Operator states remain distinct: `runnable`, `active`, `parked`, `waiting_for_human`, `waiting_for_external_condition`, `timed_out_or_escalated`, `reconciliation_required`, `blocked`, `completed`, and `failed`. Unknown action outcomes and expired active leases become `reconciliation_required`; the dashboard never repairs them.
|
|
24
|
+
|
|
25
|
+
Malformed artifacts produce degraded health instead of crashing the overview. `freshness_seconds` derives from the newest projected timestamp. Reads retry once to tolerate atomic replacement and warn when the runtime directory changes during a projection.
|
|
26
|
+
|
|
27
|
+
Secret/token/password/credential/API/private-key/provider fields are recursively replaced with `[REDACTED]`. Evidence links are safe workspace-relative paths; no arbitrary file reader exists. HTML uses DOM `textContent`, API responses are JSON, path traversal is rejected, and restrictive response headers are enabled.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Taskforce Loop Engineering 0.12 release acceptance
|
|
2
|
+
|
|
3
|
+
Status: local release candidate accepted on 2026-08-13. Publication and deployment are explicitly out of scope for this acceptance.
|
|
4
|
+
|
|
5
|
+
## Terminal outcome
|
|
6
|
+
|
|
7
|
+
Version 0.12 provides one coherent local package containing:
|
|
8
|
+
|
|
9
|
+
- P0 Human-Gate Lifecycle v2 with parked waits, throttled reminders and escalations, verified recovery, and restart-safe authorization preservation.
|
|
10
|
+
- P1 Action Idempotency and Reservation Contract with immutable request fingerprints, authorization settlement, fenced claims, and unknown-outcome reconciliation.
|
|
11
|
+
- P2 Multi-Agent Control Plane with typed todos, capability and authority matching, dependency/quota scheduling, fenced leases, handoff, and orphan recovery.
|
|
12
|
+
- P3 read-only Operator Dashboard with normalized P0/P1/P2 projections, loopback serving, static export, redaction, and traversal/XSS protections.
|
|
13
|
+
|
|
14
|
+
## Acceptance ledger
|
|
15
|
+
|
|
16
|
+
| Item | Status | Evidence |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| P0 implementation and crash/recovery behavior | accepted | `scripts/human-gate-lifecycle-v2-self-test.mjs` |
|
|
19
|
+
| P1 reservation, concurrency, fencing, crash recovery, and reconciliation | accepted | `scripts/action-reservation-self-test.mjs` |
|
|
20
|
+
| P2 ownership, scheduling, lease, handoff, and P0/P1 safety | accepted | `scripts/todo-control-plane-self-test.mjs` |
|
|
21
|
+
| P3 projection, security, restart, and large-queue behavior | accepted | `scripts/operator-dashboard-self-test.mjs` |
|
|
22
|
+
| OpenClaw and Hermes installer compatibility | accepted | `scripts/openclaw-install-self-test.mjs`, `scripts/hermes-install-self-test.mjs` |
|
|
23
|
+
| Full package regression suite | accepted | `npm run check` on 2026-08-13 |
|
|
24
|
+
| Package contents and clean registry-style installation | accepted | `npm pack --dry-run` plus installation from the generated 0.12.0 tarball |
|
|
25
|
+
| Documentation and migration boundary | accepted | `README.md`, `CHANGELOG.md`, `MIGRATING.md`, and `docs/` |
|
|
26
|
+
|
|
27
|
+
## Completion boundary
|
|
28
|
+
|
|
29
|
+
The local release candidate is complete when every ledger item above is accepted and there are no code or documentation failures. A milestone alone cannot satisfy this contract.
|
|
30
|
+
|
|
31
|
+
Git commit, tag, GitHub release, npm/ClawHub publication, and installation into a production agent are separate externally visible release actions. They require an explicit release decision and are not implied by local acceptance.
|
|
32
|
+
|
|
33
|
+
Unmet local items: none.
|
|
34
|
+
|
|
35
|
+
External release gates: publish/tag/push/deploy decision.
|