pi-legion 3.1.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +382 -2
- package/CONTRIBUTING.md +4 -17
- package/README.md +127 -66
- package/agents/centurion.md +20 -16
- package/agents/scout.md +3 -1
- package/agents/worker.md +6 -8
- package/docs/contracts/declarative-phase-machine-v5.md +128 -0
- package/docs/contracts/display-liveness-v1.md +373 -0
- package/docs/contracts/drop-non-pi-kinds-v4.md +198 -0
- package/docs/contracts/esc-abort-v1.md +4 -4
- package/docs/contracts/esc-no-retire-v3.md +2 -2
- package/docs/contracts/launch-admission-queue-v1.md +839 -0
- package/docs/contracts/status-panel-v1.md +174 -0
- package/docs/contracts/subagent-renewal-v1.md +260 -0
- package/docs/headless-child-contract.md +6 -3
- package/docs/inprocess-supervisor.md +106 -27
- package/docs/legion-v2-contract.md +27 -2
- package/docs/performance-2026-10-19.md +199 -0
- package/docs/spawn-mode-visibility-v1.md +4 -1
- package/docs/vexillatio-contract.md +3 -1
- package/index.ts +1155 -120
- package/package.json +5 -3
- package/skills/pi-legion/SKILL.md +2 -3
- package/src/agents/agents.ts +310 -46
- package/src/agents/overrides.ts +3 -2
- package/src/agents/presets.ts +14 -40
- package/src/agents/settings.ts +32 -95
- package/src/agents/step-model.ts +7 -22
- package/src/api.ts +1 -35
- package/src/extension/child-guard.ts +25 -1
- package/src/extension/event-bus.ts +80 -8
- package/src/extension/legion-commands.ts +41 -17
- package/src/extension/legion-doctor.ts +1 -1
- package/src/extension/legion-stop.ts +39 -13
- package/src/extension/legion-tools.ts +87 -25
- package/src/extension/liveness.ts +200 -0
- package/src/extension/notify.ts +136 -4
- package/src/extension/playbook.ts +4 -4
- package/src/extension/recycle.ts +4 -0
- package/src/extension/runtime.ts +435 -16
- package/src/extension/slash.ts +0 -21
- package/src/extension/summary.ts +14 -5
- package/src/extension/timing.ts +8 -4
- package/src/legion/db.ts +165 -1
- package/src/legion/events.ts +81 -16
- package/src/legion/nodes.ts +13 -2
- package/src/legion/phase-conditions.ts +164 -0
- package/src/legion/phase-machine.ts +403 -0
- package/src/legion/rebuild.ts +7 -1
- package/src/legion/state-machine.ts +219 -115
- package/src/legion/usage.ts +58 -4
- package/src/runs/args.ts +32 -18
- package/src/runs/extension-inheritance.ts +220 -0
- package/src/runs/orchestrator.ts +1292 -96
- package/src/runs/progress-signal.ts +137 -0
- package/src/runs/store-lookup.ts +270 -0
- package/src/runs/worktree.ts +190 -21
- package/src/shared/ignored-kind.ts +57 -0
- package/src/shared/progress.ts +11 -0
- package/src/shared/session.ts +199 -19
- package/src/shared/types.ts +138 -69
- package/src/supervisor/admission-queue.ts +516 -0
- package/src/supervisor/child-context.ts +19 -0
- package/src/supervisor/inprocess-supervisor.ts +137 -38
- package/src/supervisor/proc-memory.ts +67 -0
- package/src/supervisor/routing-supervisor.ts +60 -2
- package/src/supervisor/rpc-supervisor.ts +2 -2
- package/src/tui/session-messages-file.ts +100 -0
- package/src/tui/status.ts +91 -18
- package/src/tui/tree-view.ts +84 -3
- package/src/tui/viz/layout.ts +54 -3
- package/src/tui/viz/model.ts +67 -14
- package/src/tui/viz/palette.ts +11 -3
- package/src/tui/viz/panels.ts +222 -8
- package/src/tui/viz/view.ts +110 -23
- package/agents/advisor.md +0 -110
- package/agents/designer.md +0 -87
- package/agents/planner.md +0 -53
- package/agents/prototype.md +0 -72
- package/agents/reviewer.md +0 -113
- package/src/backends/legacy/client.ts +0 -638
- package/src/backends/legacy/cursor-chat.ts +0 -348
- package/src/backends/legacy/runner.ts +0 -101
- package/src/backends/legacy/types.ts +0 -138
- package/src/runs/kind.ts +0 -260
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pi-legion
|
|
3
3
|
npm: "pi-legion"
|
|
4
|
-
description: "Pi Legion v2: recursive centurion
|
|
4
|
+
description: "Pi Legion v2: recursive centurion teams on Pi. Children run in-process by default (rpc only for a worktree-owning centurion); shared SQLite WAL legion.db. Declarative per-team phase machine (built-in default: planning/implementing/reviewing/verifying), parent/child/sibling legion_mail, three-layer /legion UI, upward MR trees, squad resume."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# pi-legion
|
|
@@ -30,7 +30,7 @@ shared SQLite ledger records the whole tree.
|
|
|
30
30
|
- [Team 配置](#team-配置)
|
|
31
31
|
- [Parent/child context conventions](#parentchild-context-conventions)
|
|
32
32
|
- [Delivery and resume](#delivery-and-resume)
|
|
33
|
-
- [
|
|
33
|
+
- [Supported kinds](#supported-kinds)
|
|
34
34
|
- [Changelog](CHANGELOG.md)
|
|
35
35
|
- [Development](#development)
|
|
36
36
|
|
|
@@ -49,14 +49,16 @@ User (CEO) — root Pi session (TUI)
|
|
|
49
49
|
└─ pi-legion in child mode
|
|
50
50
|
├─ LegionSupervisor for this squad
|
|
51
51
|
├─ `legion_mail` / `legion_tree` / `legion_phase` tools
|
|
52
|
-
├─ worker / scout
|
|
52
|
+
├─ worker / scout … children (`worktree: false`)
|
|
53
53
|
└─ nested centurions → recursive squads
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Transport, state, decision-making, and display are separate layers:
|
|
57
57
|
|
|
58
|
-
- **Transport:**
|
|
59
|
-
|
|
58
|
+
- **Transport:** a child is an `AgentSession` inside the parent process by
|
|
59
|
+
default; only a worktree-owning centurion runs as a separate `pi --mode rpc`
|
|
60
|
+
process. A `LegionSupervisor` owns both backends, and a centurion can lead
|
|
61
|
+
another squad recursively.
|
|
60
62
|
- **State:** all nodes in the tree share the `legion.db` SQLite ledger in WAL
|
|
61
63
|
mode. Per-run `run.json` records and session files remain the resume source
|
|
62
64
|
for each child.
|
|
@@ -65,37 +67,70 @@ Transport, state, decision-making, and display are separate layers:
|
|
|
65
67
|
- **Display:** the event bus feeds the resident tree, the `/legion` full view,
|
|
66
68
|
and an on-demand live overlay.
|
|
67
69
|
|
|
68
|
-
##
|
|
70
|
+
## Bundled roles
|
|
71
|
+
|
|
72
|
+
Three roles ship with the package:
|
|
73
|
+
|
|
74
|
+
| Role | Purpose | Tools | Default timeout |
|
|
75
|
+
| --- | --- | --- | --- |
|
|
76
|
+
| `centurion` | Team lead: freeze the contract, dispatch children, drive the phase machine, deliver a reviewable result. Holds the worktree. | pi defaults | 30 min |
|
|
77
|
+
| `worker` | Implementation: write code and run tests against a frozen plan, report a verdict. | read/edit/write/grep/find/ls/bash/codemode | 45 min |
|
|
78
|
+
| `scout` | Read-only recon: produce a fact list, no plan, no implementation. | read/grep/find/ls/bash/codemode | 10 min |
|
|
69
79
|
|
|
70
|
-
`
|
|
71
|
-
|
|
80
|
+
`worker` cannot dispatch nested agents (`maxSubagentDepth: 1`). Anything a worker
|
|
81
|
+
needs to escalate is a `verdict ok:false`, not another layer of children — one
|
|
82
|
+
level keeps the tree's cost and blast radius bounded.
|
|
83
|
+
|
|
84
|
+
Roles are not a fixed pipeline. Since the phase machine became declarative
|
|
85
|
+
(#298), nothing in the runtime keys on a role being called "worker" or
|
|
86
|
+
"reviewer"; a team shapes its workflow by declaring phases on its lead's card.
|
|
72
87
|
|
|
73
88
|
```yaml
|
|
74
|
-
# agents/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
# agents/centurion.md
|
|
90
|
+
phases:
|
|
91
|
+
- id: recon
|
|
92
|
+
next:
|
|
93
|
+
- to: build
|
|
94
|
+
require: [contract_file]
|
|
95
|
+
- id: build
|
|
96
|
+
next:
|
|
97
|
+
- to: done
|
|
98
|
+
require: [children_settled]
|
|
78
99
|
```
|
|
79
100
|
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
Omitted means the built-in four-phase pipeline
|
|
102
|
+
(`planning → implementing → reviewing → verifying → done`). Conditions are a
|
|
103
|
+
closed vocabulary — `contract_file`, `children_present`, `children_settled`,
|
|
104
|
+
`children_none_failed`, `verdict_ok`, `verdict_not_ok`, `verification_passed`,
|
|
105
|
+
`verification_failed`, `rework_available`, `children_all_failed`, `always` — and
|
|
106
|
+
`done` / `failed` / `aborted` are always available terminals so a team can
|
|
107
|
+
never lose the ability to complete or abort.
|
|
108
|
+
|
|
109
|
+
## Spawn mode
|
|
110
|
+
|
|
111
|
+
The backend is a property of the **launch**, not of a role. There is no
|
|
112
|
+
`spawnMode` frontmatter field — a card cannot pin itself to a process model —
|
|
113
|
+
and the rule is simply:
|
|
114
|
+
|
|
115
|
+
| Launch needs a worktree? | Backend |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| yes | `rpc` — a separate `pi --mode rpc` process |
|
|
118
|
+
| no | in-process `AgentSession` inside the parent Node process |
|
|
119
|
+
|
|
120
|
+
**Why rpc still exists:** it is the only backend that can host a worktree
|
|
121
|
+
child. Only the `centurion` role may hold a worktree (see
|
|
122
|
+
[Delivery and resume](#delivery-and-resume)), so a centurion is the only role
|
|
123
|
+
that can ever run on rpc — every other role runs in-process, where spawn latency
|
|
124
|
+
is lower and no second process is involved.
|
|
125
|
+
|
|
126
|
+
**A non-centurion asking for a worktree** is demoted to `worktree: false` with a
|
|
127
|
+
once-per-run warning rather than throwing, so a stale card does not break every
|
|
128
|
+
launch in the tree.
|
|
129
|
+
|
|
130
|
+
**Both backends share the same budgets.** The legion tree limits
|
|
131
|
+
(`maxDepth` / `maxChildrenPerNode` / `maxActiveNodes`) apply to every launch; the
|
|
132
|
+
in-process pools (`subagents.inprocess.*`) apply on top, and the stricter gate
|
|
133
|
+
wins. Avoiding rpc is never a way to escape a cap. See
|
|
99
134
|
[docs/inprocess-supervisor.md](docs/inprocess-supervisor.md).
|
|
100
135
|
|
|
101
136
|
## Headless child contract
|
|
@@ -130,7 +165,7 @@ subagent({
|
|
|
130
165
|
```
|
|
131
166
|
|
|
132
167
|
The centurion plans the work, writes the squad contract, dispatches ordinary
|
|
133
|
-
roles such as `worker
|
|
168
|
+
roles such as `worker` and `scout`, and coordinates the squad
|
|
134
169
|
through its phases. For a single leaf task, dispatch an ordinary role directly:
|
|
135
170
|
|
|
136
171
|
```text
|
|
@@ -167,16 +202,17 @@ controls run graceful `stop` (a stopped parent retires its own subtree on
|
|
|
167
202
|
shutdown); process exit / session shutdown also retires:
|
|
168
203
|
|
|
169
204
|
- **`/legion stop`** stops every live subagent; **`/legion stop <name>`** stops
|
|
170
|
-
one (`all` is an alias for no name).
|
|
205
|
+
one (`all` is an alias for no name). Add **`--force`** / **`-f`** for hard
|
|
206
|
+
retire (same as tool `force: true`). Names complete from the live children;
|
|
171
207
|
nested agents complete as `parent/name` and are reported as owned by their
|
|
172
208
|
parent (stop the parent to retire them).
|
|
173
209
|
- **`x`** on the selected live agent in the `/legion` view or its live
|
|
174
|
-
overlay asks `y` to confirm in place, then stops it
|
|
210
|
+
overlay asks `y` to confirm in place, then stops it (graceful; use
|
|
211
|
+
`/legion stop --force <name>` for hard retire).
|
|
175
212
|
- **Tool**: `subagent({ action: "stop", name })` is graceful; pass
|
|
176
213
|
`force: true` for hard retire (SIGTERM → SIGKILL + descendant sweep per
|
|
177
214
|
`docs/retire-hardening-contract.md`). Example:
|
|
178
215
|
`subagent({ action: "stop", name: "worker-0", force: true })`.
|
|
179
|
-
TUI `/legion stop --force` is an optional follow-up (same `force: true`).
|
|
180
216
|
|
|
181
217
|
**`wait` ≠ stop.** A `wait` timeout (or still-running result) does **not**
|
|
182
218
|
retire children. The tool result includes live child names, elapsed ms, and
|
|
@@ -184,8 +220,8 @@ suggested decisions (`extend` / `steer_again` / `stop` / `force_stop`); the
|
|
|
184
220
|
parent chooses the next tool call. See `docs/contracts/wait-not-stop.md`.
|
|
185
221
|
|
|
186
222
|
While subagents are live, the railway header can show a dim
|
|
187
|
-
`/legion stop [name|all]` hint (shortened on narrow terminals; idle
|
|
188
|
-
tree-strip coverage is a TUI follow-up).
|
|
223
|
+
`/legion stop [--force] [name|all]` hint (shortened on narrow terminals; idle
|
|
224
|
+
gating / tree-strip coverage is a TUI follow-up).
|
|
189
225
|
|
|
190
226
|
### Status (`/legion status`)
|
|
191
227
|
|
|
@@ -230,11 +266,17 @@ legion_phase({ to, note?, evidence? })
|
|
|
230
266
|
- **`legion_phase`** is available to centurions. It requests a state transition;
|
|
231
267
|
the supervisor checks the transition's invariants and records the result.
|
|
232
268
|
|
|
233
|
-
A squad moves through
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
269
|
+
A squad moves through whatever phases its lead declares. With no declaration
|
|
270
|
+
that is the built-in **planning → implementing → reviewing → verifying**:
|
|
271
|
+
planning produces a non-empty `.pi-legion/contract.md` with file ownership and
|
|
272
|
+
acceptance commands; reviewing needs a settled child that returns `ok:true`; in
|
|
273
|
+
verifying the supervisor runs the contract's `legion-verify` commands without an
|
|
274
|
+
LLM. Passing verification advances the squad to `done`.
|
|
275
|
+
|
|
276
|
+
Because the machine is data, no rule names a role: "the children are settled" and
|
|
277
|
+
"a verdict came back ok" are conditions, not "the worker" and "the reviewer".
|
|
278
|
+
That is what lets a team rename, reorder, or drop phases without touching code —
|
|
279
|
+
and it is why the bundled roster is just `centurion`, `worker`, and `scout`.
|
|
238
280
|
|
|
239
281
|
## Three-layer visualization
|
|
240
282
|
|
|
@@ -428,20 +470,35 @@ Coverage:
|
|
|
428
470
|
|
|
429
471
|
### Child extensions
|
|
430
472
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
extensions
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
473
|
+
**A child inherits every extension the parent has**, minus anything it excludes.
|
|
474
|
+
This is the opposite of the pre-4.0.1 default: children used to start with
|
|
475
|
+
`--no-extensions` and load only what a card named, which meant a role silently
|
|
476
|
+
lost host capabilities (a provider extension, a guard) it never knew to name.
|
|
477
|
+
Children now run in-process by default, so "one more extension" no longer means
|
|
478
|
+
another process's worth of memory.
|
|
437
479
|
|
|
438
480
|
| Knob | Effect |
|
|
439
481
|
| --- | --- |
|
|
440
|
-
|
|
|
441
|
-
| `
|
|
442
|
-
| `
|
|
443
|
-
|
|
444
|
-
|
|
482
|
+
| *(default)* | Inherit every host extension. |
|
|
483
|
+
| role frontmatter `excludeExtensions: [pi-lens]` | Subtract specific ones. Accepts a package **name** (`pi-lens`, matches the package dir or a loose `pi-lens.ts`) or an exact **path** (`/abs/.../index.ts`, `~` expands). |
|
|
484
|
+
| role frontmatter `inheritExtensions: false` | Load ONLY the card's own `extensions` / `subagentOnlyExtensions`. Nothing is inherited, so `excludeExtensions` has nothing to subtract. |
|
|
485
|
+
| `PI_LEGION_CHILD_INHERIT_EXTENSIONS=0` | Same as `inheritExtensions: false`, for every child. `1` forces inheritance back on. |
|
|
486
|
+
| `PI_LEGION_CHILD_EXTENSIONS=/a.ts,/b.ts` | Extra paths every child loads explicitly. |
|
|
487
|
+
|
|
488
|
+
The child-guard is appended unconditionally and is not subject to either knob —
|
|
489
|
+
a child without it breaks the prompt/format contract no matter what the card
|
|
490
|
+
asked for.
|
|
491
|
+
|
|
492
|
+
**Discovery limit.** Host extensions are found by reading `pi list` (which
|
|
493
|
+
reports package *directories*) and resolving each one the way pi's own loader
|
|
494
|
+
does: `package.json`'s `pi.extensions`, else `index.ts`/`index.js`. Single-file
|
|
495
|
+
`--extension` arguments and builtins cannot be discovered this way; name them
|
|
496
|
+
explicitly if a child needs them.
|
|
497
|
+
|
|
498
|
+
**Cost note.** Inheriting everything includes heavy extensions. pi-lens starts an
|
|
499
|
+
LSP stack (~1 GB per child, #43). If a fleet of children does not need it, add
|
|
500
|
+
`excludeExtensions: [pi-lens]` to those cards. The bundled `worker` does not list
|
|
501
|
+
`lens_*` tools; give a role those tools by adding the names to its `tools:` list.
|
|
445
502
|
|
|
446
503
|
### Extra agent directories
|
|
447
504
|
|
|
@@ -492,7 +549,7 @@ another connection holds the db.
|
|
|
492
549
|
|
|
493
550
|
## Delivery and resume
|
|
494
551
|
|
|
495
|
-
A centurion owns a Git worktree for its subtree; its worker/scout
|
|
552
|
+
A centurion owns a Git worktree for its subtree; its worker/scout
|
|
496
553
|
children work in that subtree (`worktree: false`, typically in-process), and a
|
|
497
554
|
nested centurion gets a nested worktree. **Parallel isolated writers:** dispatch
|
|
498
555
|
N centurions from the root (each owns one worktree); do not give every worker
|
|
@@ -505,17 +562,13 @@ process ends, its child processes do not become detached workers; resuming the
|
|
|
505
562
|
parent restores the squad, while already-settled children are not restarted.
|
|
506
563
|
Keep the run records and session files while the tree may need to resume.
|
|
507
564
|
|
|
508
|
-
##
|
|
565
|
+
## Supported kinds
|
|
509
566
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
[CHANGELOG.md](CHANGELOG.md#200---2026-10-14).
|
|
516
|
-
|
|
517
|
-
Pi Legion 2.x supports `kind: pi` only. Migrate a custom role that uses another
|
|
518
|
-
CLI kind by changing its frontmatter, for example:
|
|
567
|
+
Pi Legion runs `kind: pi` roles only. `kind` is still a legal frontmatter key,
|
|
568
|
+
but `pi` is the only accepted value: a non-`pi` value is ignored (one note on
|
|
569
|
+
stderr) and the role launches as `kind: pi`. The same holds for
|
|
570
|
+
`subagents.presets.<role>.kind` and `subagents.agentOverrides.<role>.kind` —
|
|
571
|
+
those three spots are the only places a role's `kind` can come from.
|
|
519
572
|
|
|
520
573
|
```yaml
|
|
521
574
|
---
|
|
@@ -524,8 +577,16 @@ kind: pi
|
|
|
524
577
|
---
|
|
525
578
|
```
|
|
526
579
|
|
|
527
|
-
|
|
528
|
-
|
|
580
|
+
Child execution is Pi either way: in-process by default, with an automatic
|
|
581
|
+
`rpc` fallback when the resolved spawn needs an OS worktree (see
|
|
582
|
+
[Spawn mode](#spawn-mode)).
|
|
583
|
+
|
|
584
|
+
Version **0.16.x was the final Herdr-era line** — it launched children in Herdr
|
|
585
|
+
panes instead of Pi processes. That backend was archived under
|
|
586
|
+
`src/backends/legacy/` for 2.x and 3.x, and is gone in v4. Pin to
|
|
587
|
+
`pi-legion@0.16.x` if a workflow must stay on that former execution model; a
|
|
588
|
+
short breaking-change summary lives in
|
|
589
|
+
[CHANGELOG.md](CHANGELOG.md#200---2026-10-14).
|
|
529
590
|
|
|
530
591
|
## Development
|
|
531
592
|
|
package/agents/centurion.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: centurion
|
|
3
|
-
description:
|
|
3
|
+
description: 百夫长/组长:带领一支子团队,负责冻结契约、调度组员、推进阶段状态机并整队交付。(仅根会话可派发)
|
|
4
4
|
kind: pi
|
|
5
5
|
allowNestedSubagents: true
|
|
6
6
|
maxSubagentDepth: 3
|
|
@@ -19,35 +19,39 @@ acceptance:
|
|
|
19
19
|
|
|
20
20
|
你是 centurion,一支子树团队的负责人。只负责自己的队伍;不得越级指挥、收割或绕过其他 centurion 管理其组员。你必须通过 `legion_phase` 请求阶段迁移,通过 `legion_mail` 沟通,通过 `legion_tree` 观察状态,不得把口头声明当作机器事实。
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 阶段职责
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
阶段由本队的 `phases:` 声明(省略则是内置四阶段:planning → implementing → reviewing → verifying → done)。**不要假定阶段名**——先看系统提示里展开的状态机,或直接用 `legion_phase` 试,被拒时拒绝信息会列出当前合法的下一步。
|
|
25
|
+
|
|
26
|
+
不论阶段怎么命名,职责是这样分层的:
|
|
27
|
+
|
|
28
|
+
### 规划阶段(内置 `planning`)
|
|
25
29
|
|
|
26
30
|
- 先完整理解目标与验收条件,再把接口、wire 字段、文件所有权、验收清单写入 `.pi-legion/contract.md`。
|
|
27
|
-
-
|
|
31
|
+
- 契约未落盘且非空,不得请求进入实现阶段;发现契约矛盾时停止派工并上报,不得自行解释或扩大文件归属。
|
|
28
32
|
- 契约中的每个写入文件只能有一个 owner;共享文件必须串行分配。
|
|
29
33
|
|
|
30
|
-
### implementing
|
|
34
|
+
### 实现阶段(内置 `implementing`)
|
|
31
35
|
|
|
32
36
|
- 按冻结契约和文件所有权并行派发互不冲突的工作;worker 任务必须逐项列出可写文件、验证要求和交付格式。
|
|
33
37
|
- 子任务只用 `subagent` 工具派发;工具的并行任务必须各自有明确边界。实现过程中监控 `legion_tree`,通过邮件解决必要的协作,不以邮件取代共享工件。
|
|
34
|
-
- 组员声明完成后,按结果收集 session/verdict;未收齐所有 worker
|
|
38
|
+
- 组员声明完成后,按结果收集 session/verdict;未收齐所有 worker 结果不得请求离开本阶段。
|
|
35
39
|
|
|
36
|
-
### reviewing
|
|
40
|
+
### 审查阶段(内置 `reviewing`)
|
|
37
41
|
|
|
38
|
-
-
|
|
39
|
-
- `
|
|
40
|
-
- 每个 `failed`
|
|
41
|
-
- 被 `legion_phase`
|
|
42
|
+
- 对抗式审查,至少覆盖正确性/回归、测试覆盖和简洁性,且必须由**未参与实现**的独立子节点做。
|
|
43
|
+
- 通过条件看阶段声明里的 `verdict_ok`:需要一个 settled 子节点回报 `ok:true`。major finding 退回实现阶段修复并复审;若是计划本身错误,可退回规划阶段,但必须通过 `legion_phase` 记录并邮件告知上级。
|
|
44
|
+
- 每个 `failed` 子节点必须先 rework 重派或由父级明确收队;不得把失败节点声明为已处理来解锁审查阶段。
|
|
45
|
+
- 被 `legion_phase` 拒绝时,按拒绝理由核实机器事实,修正条件后重试;这不是 rework,不得伪造证据或绕过状态机。
|
|
42
46
|
|
|
43
|
-
### verifying
|
|
47
|
+
### 验证与收队(内置 `verifying` / `done`)
|
|
44
48
|
|
|
45
|
-
-
|
|
46
|
-
- done
|
|
49
|
+
- 验证由 supervisor 自动运行契约中的 `legion-verify` 命令。全绿后状态机自动进入 done;不要自行宣称验证成功,也不要手动改数据库。
|
|
50
|
+
- done 后汇总全部子节点 verdict、验证结果和未决问题;把子树工作 squash 成一个 MR/PR,开给父节点/目标分支审查,并把链接写入最终 verdict。绝不在本级自行合并。
|
|
47
51
|
- 收队时保证组员结果已落盘;由父级 collect 本节点结果后 retire。worktree/session 是 resume 凭据,未获根级清理授权前不得删除。
|
|
48
52
|
|
|
49
53
|
## 止损与安全
|
|
50
54
|
|
|
51
|
-
- 同一问题重试不超过 2
|
|
52
|
-
-
|
|
55
|
+
- 同一问题重试不超过 2 次;两次仍失败,停止并向上报告(附已尝试方案、失败输出、当前假设、涉及文件),不要硬扛第三次,也不得为了绿灯绕过测试或修改冻结契约。
|
|
56
|
+
- 回滚时回到上一个检查点并记录原因。
|
|
53
57
|
- 只使用允许的工具和团队边界;不读写其他队的文件,不直接访问 legion.db,不使用越级邮件。
|
package/agents/scout.md
CHANGED
|
@@ -8,6 +8,9 @@ inheritProjectContext: true
|
|
|
8
8
|
inheritSkills: false
|
|
9
9
|
async: true
|
|
10
10
|
timeoutMs: 600000
|
|
11
|
+
# A timed-out scout means the question was too broad, not that work needs
|
|
12
|
+
# finishing — renewing it would just re-run an over-scoped search (#270 D5).
|
|
13
|
+
renewable: false
|
|
11
14
|
acceptance:
|
|
12
15
|
level: attested
|
|
13
16
|
role: read-only
|
|
@@ -17,7 +20,6 @@ acceptance:
|
|
|
17
20
|
evidence: [facts, open-questions]
|
|
18
21
|
severity: required
|
|
19
22
|
kind: pi
|
|
20
|
-
placement: split-down
|
|
21
23
|
steer: true
|
|
22
24
|
maxSubagentDepth: 1
|
|
23
25
|
---
|
package/agents/worker.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
3
|
description: 实现者:按冻结计划写代码、跑测试,完成后自报 verdict
|
|
4
|
-
tools: read, edit, write, grep, find, ls, bash,
|
|
4
|
+
tools: read, edit, write, grep, find, ls, bash, codemode
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
8
|
async: true
|
|
9
|
-
timeoutMs:
|
|
10
|
-
allowNestedSubagents: true
|
|
9
|
+
timeoutMs: 2700000
|
|
11
10
|
acceptance:
|
|
12
11
|
level: verified
|
|
13
12
|
role: writer
|
|
@@ -17,10 +16,9 @@ acceptance:
|
|
|
17
16
|
evidence: [verification-output]
|
|
18
17
|
severity: required
|
|
19
18
|
kind: pi
|
|
20
|
-
placement: split-down
|
|
21
19
|
steer: true
|
|
22
20
|
worktree: false
|
|
23
|
-
maxSubagentDepth:
|
|
21
|
+
maxSubagentDepth: 1
|
|
24
22
|
---
|
|
25
23
|
|
|
26
24
|
你是 worker,一个实现 agent。你按已冻结的计划把代码写出来并证明它能跑。
|
|
@@ -36,8 +34,8 @@ maxSubagentDepth: 3
|
|
|
36
34
|
- **严格按计划**:接口/签名已被冻结,不要擅自更改。发现计划有错时,**停下来报告**(verdict `ok: false`,reason 写明冲突),不要自行"顺手修正"。
|
|
37
35
|
- **只碰计划授权的文件**。其他模块的文件一律不动。
|
|
38
36
|
- **跑不动的命令**(交互式、需要确认)走默认放行,不要挂起等待。
|
|
39
|
-
-
|
|
40
|
-
|
|
37
|
+
- **不派任何子 agent**。失败止损靠自己重试与向上报告(verdict `ok: false` 写明冲突),
|
|
38
|
+
不要为了"咨询"再开一层。
|
|
41
39
|
- **工作区**:在 centurion 子树 worktree(或父会话 cwd)**原地**改代码;隔离与 MR 由 centurion(或根会话)收队。不要本地 merge,不要 push 到 main/master。
|
|
42
40
|
- **bugfix 先红后绿**:修 bug 类任务,第一步先写一个能复现该 bug 的失败测试并跑出失败,修复后同一测试必须转绿;两次输出都原样贴进报告。不复现就修复的,视为未验收。
|
|
43
41
|
|
|
@@ -47,7 +45,7 @@ maxSubagentDepth: 3
|
|
|
47
45
|
2. **用项目自己的方式验证,分两档,别每轮都跑全量**:
|
|
48
46
|
- 先发现项目怎么验证:看 `.pi/verify.sh`、Makefile/justfile target、CI 配置(.github/workflows 等)、package.json scripts、项目 README/CONTRIBUTING。项目明确的验证入口就是唯一权威,不要自己发明替代命令。
|
|
49
47
|
- 每轮改动结束:跑项目的**轻量档**(typecheck/lint/vet 级别,如 `make lint`、`npm run typecheck`、`go vet ./...`);秒级反馈,失败直接修,不计入重试升级。
|
|
50
|
-
- 全部步骤完成、交活前才跑一次项目的**全量档**(完整测试套件/CI 等效命令);交活后插件会自动再验证一遍判定验收,不需要中途反复跑全量。全量失败按「失败止损」处理:重试不超过 2
|
|
48
|
+
- 全部步骤完成、交活前才跑一次项目的**全量档**(完整测试套件/CI 等效命令);交活后插件会自动再验证一遍判定验收,不需要中途反复跑全量。全量失败按「失败止损」处理:重试不超过 2 次,仍失败则 `ok: false` 上报。
|
|
51
49
|
- 项目找不到任何验证入口时,在报告里写明依据(查过哪些地方),不要自己编命令冒充。
|
|
52
50
|
3. 把最终那次 full 验证输出**原样**(含命令与结果)放进最终报告。
|
|
53
51
|
4. 交活前逐文件重读完整 diff:检查遗留的调试代码、console.log/print、注释掉的老逻辑、无关改动混入;发现问题先修。
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Declarative phase machine (v5)
|
|
2
|
+
|
|
3
|
+
Status: draft, layer 3 (#298).
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
The legion phase machine is hard-coded in three places that must agree:
|
|
8
|
+
|
|
9
|
+
| Place | Hard-codes |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `src/legion/state-machine.ts:1` | The seven phase names and every transition rule |
|
|
12
|
+
| `src/agents/settings.ts:117` | A duplicate copy of the phase names, for `phaseTimeouts` validation |
|
|
13
|
+
| `src/extension/legion-tools.ts:47` | The `legion_phase` tool's `to` enum |
|
|
14
|
+
|
|
15
|
+
Worse, the *rules inside a phase* are keyed on **role names**:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
implementing → reviewing requires every `role === "worker"` to be settled
|
|
19
|
+
reviewing → verifying requires a settled `role === "reviewer"` with verdict ok:true
|
|
20
|
+
planning → implementing requires no `role === "planner"` still running
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
So a team cannot re-shape its workflow without editing source, and a role that
|
|
24
|
+
merely *exists* acquires workflow meaning. "worker" is not "a worker" — it is a
|
|
25
|
+
specific slot in a fixed pipeline.
|
|
26
|
+
|
|
27
|
+
## Goal
|
|
28
|
+
|
|
29
|
+
A centurion declares its team's phases and the conditions for leaving them.
|
|
30
|
+
Defaults preserve today's behaviour exactly, so an undeclared machine is the
|
|
31
|
+
four-phase pipeline above.
|
|
32
|
+
|
|
33
|
+
## Non-goals
|
|
34
|
+
|
|
35
|
+
- Arbitrary scripting. Conditions are a closed vocabulary of predicates, not code.
|
|
36
|
+
- Per-node machines. One machine per team root; children inherit it read-only.
|
|
37
|
+
- Changing how children are spawned. Phases gate *progress*, not dispatch.
|
|
38
|
+
|
|
39
|
+
## Where the declaration lives
|
|
40
|
+
|
|
41
|
+
Role frontmatter, on the team root card:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
---
|
|
45
|
+
name: centurion
|
|
46
|
+
phases:
|
|
47
|
+
- id: planning
|
|
48
|
+
require: [contract_file]
|
|
49
|
+
next: [implementing]
|
|
50
|
+
timeoutMs: 900000
|
|
51
|
+
- id: implementing
|
|
52
|
+
require: [children_settled]
|
|
53
|
+
next: [reviewing, failed]
|
|
54
|
+
- id: reviewing
|
|
55
|
+
require: [verdict_ok]
|
|
56
|
+
next: [verifying, implementing]
|
|
57
|
+
- id: verifying
|
|
58
|
+
require: [verification_passed]
|
|
59
|
+
next: [done]
|
|
60
|
+
---
|
|
61
|
+
```text
|
|
62
|
+
|
|
63
|
+
Kept on the card rather than in `settings` because the machine is a property of
|
|
64
|
+
*this team*, like its roster — two centurions in one settings file may run
|
|
65
|
+
different workflows.
|
|
66
|
+
|
|
67
|
+
Resolution order: card `phases` → `settings.legion.phases` → built-in default.
|
|
68
|
+
|
|
69
|
+
## Condition vocabulary
|
|
70
|
+
|
|
71
|
+
A condition answers "may this node leave phase X for phase Y?" over a snapshot of
|
|
72
|
+
the node and its children. Closed set, each with one meaning:
|
|
73
|
+
|
|
74
|
+
| Condition | True when |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `contract_file` | `contract_path` is set and the file exists and is non-empty |
|
|
77
|
+
| `children_settled` | every child of this node is terminal (settled/failed/retired) |
|
|
78
|
+
| `children_none_failed` | no child is `failed`, or every failed child is listed in `handled` |
|
|
79
|
+
| `verdict_ok` | some settled child's last turn parsed to `{ok: true}` |
|
|
80
|
+
| `verdict_not_ok` | some settled child's last turn parsed to `{ok: false}` |
|
|
81
|
+
| `verification_passed` | the node's stored verification result is `pass` |
|
|
82
|
+
| `verification_failed` | the node's stored verification result is `fail` |
|
|
83
|
+
| `rework_available` | `rework_count < maxRework` |
|
|
84
|
+
| `children_all_failed` | there is ≥1 child and all are `failed` |
|
|
85
|
+
| `always` | unconditional |
|
|
86
|
+
|
|
87
|
+
`require` is a conjunction: all listed conditions must hold.
|
|
88
|
+
`next` is the allowed successor set; a transition to anything outside it is
|
|
89
|
+
refused with `invalid_transition`.
|
|
90
|
+
|
|
91
|
+
**Role names do not appear anywhere.** `verdict_ok` asks "did any settled child
|
|
92
|
+
return ok:true", not "did the reviewer". That is what lets `worker` become a
|
|
93
|
+
general worker.
|
|
94
|
+
|
|
95
|
+
## Terminal phases
|
|
96
|
+
|
|
97
|
+
Exactly three are terminal and are always available regardless of `next`:
|
|
98
|
+
|
|
99
|
+
- `done` — only when the phase's `require` holds
|
|
100
|
+
- `failed` — parent decision, all children failed, or rework exhausted
|
|
101
|
+
- `aborted` — parent retire only
|
|
102
|
+
|
|
103
|
+
## Safety rails (unchanged)
|
|
104
|
+
|
|
105
|
+
These are invariants, not configuration:
|
|
106
|
+
|
|
107
|
+
- A new team starts in the machine's **first** phase.
|
|
108
|
+
- `rework_count` still caps at `maxRework` (default 2).
|
|
109
|
+
- `centurion`-only gates stay: a child cannot advance the team.
|
|
110
|
+
- Phase timeouts still only *report*; they never kill work.
|
|
111
|
+
- A declared machine is validated at load time. Unknown condition, empty `next`,
|
|
112
|
+
duplicate id, unreachable phase, or a terminal phase used as a start → the card
|
|
113
|
+
is rejected (same posture as unknown frontmatter).
|
|
114
|
+
|
|
115
|
+
## Migration
|
|
116
|
+
|
|
117
|
+
The default machine reproduces today's table, so no behaviour change without a
|
|
118
|
+
declaration. The role-name predicates become condition predicates:
|
|
119
|
+
|
|
120
|
+
| Old rule | New condition |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| all `worker` settled before reviewing | `children_settled` |
|
|
123
|
+
| settled `reviewer` with ok:true | `verdict_ok` |
|
|
124
|
+
| no `planner` still running | covered by `children_settled` |
|
|
125
|
+
| verification pass before done | `verification_passed` |
|
|
126
|
+
|
|
127
|
+
Once this lands, `planner` and `reviewer` stop being load-bearing and their
|
|
128
|
+
bundled cards can be deleted.
|