pi-agent-fleet 0.3.0 → 0.5.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/README.md +99 -23
- package/assets/canvas-node-peek.png +0 -0
- package/assets/canvas.png +0 -0
- package/examples/json-number-pipeline.json +35 -0
- package/package.json +11 -3
- package/src/canvas-client.tsx +820 -0
- package/src/canvas.ts +740 -401
- package/src/command.ts +56 -14
- package/src/contracts.ts +68 -16
- package/src/controller.ts +33 -6
- package/src/dag.ts +85 -2
- package/src/edits.ts +8 -9
- package/src/fleet-recovery.ts +73 -0
- package/src/fleet-store.ts +11 -2
- package/src/insert.ts +2 -8
- package/src/model-resolution.ts +27 -2
- package/src/preferences.ts +10 -1
- package/src/prompts.ts +10 -0
- package/src/report.ts +28 -1
- package/src/scheduler.ts +116 -2
- package/src/tools.ts +67 -14
- package/src/types.ts +8 -0
- package/src/worktree.ts +81 -0
package/README.md
CHANGED
|
@@ -9,6 +9,16 @@ DAG-of-agents fleets for [pi](https://github.com/earendil-works/pi-coding-agent)
|
|
|
9
9
|
└─ ○ reviewer (k3) · waiting on builder-relaunch
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
## Demo
|
|
13
|
+
|
|
14
|
+
Live browser canvas — per-node status, turns, tokens, cost, and click-to-peek session tail:
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
Node detail side panel — peek a running node's recent session without leaving the canvas:
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
12
22
|
## Why
|
|
13
23
|
|
|
14
24
|
One agent is a tool. A **fleet** is a workflow: researchers feed builders, builders feed reviewers, reviewers gate quality — all visible, all recorded, all contract-checked. Fleets run in-process via pi's SDK: any provider pi is logged into (Claude, Codex, Kimi, …) works per-node.
|
|
@@ -32,26 +42,57 @@ Ask your pi session (the LLM drives the tools):
|
|
|
32
42
|
> combiner (depends on both) writes output/sum.md with the total.
|
|
33
43
|
> Each declares its output as a markdown contract.
|
|
34
44
|
|
|
35
|
-
The agent calls `fleet_plan` (
|
|
45
|
+
The agent calls `fleet_design` (if you describe it in prose) or `fleet_plan` (if you already have JSON), you confirm the preview, then `fleet_launch` runs it. Plan and launch responses include a fleet canvas link by default; the in-chat widget is hidden until you run `/fleet viz`. Read the report at `.fleet/<name>-<ts>/report.md`.
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
JSON pipeline variant — a numeric handoff chain where workers pass typed JSON, verified by schemas at contract check:
|
|
48
|
+
|
|
49
|
+
> Plan and launch the fleet defined in `examples/json-number-pipeline.json`.
|
|
38
50
|
|
|
39
|
-
|
|
51
|
+
One writer emits `{"values":[3,5,8]}`, two parallel consumers add and subtract, a synthesizer combines the results — each output declared as a `json` contract with a `schema` naming its required and numeric keys.
|
|
52
|
+
|
|
53
|
+
## Writing a fleet
|
|
40
54
|
|
|
41
55
|
```json
|
|
42
56
|
{
|
|
43
57
|
"fleet_name": "auth-research",
|
|
44
58
|
"type": "dag",
|
|
45
|
-
"config": {
|
|
59
|
+
"config": {
|
|
60
|
+
"max_concurrent": 4,
|
|
61
|
+
"model": "gpt-5.4-mini",
|
|
62
|
+
"effort": "medium",
|
|
63
|
+
"warn_cost_usd": 10
|
|
64
|
+
},
|
|
46
65
|
"workers": [
|
|
47
|
-
{
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
"
|
|
66
|
+
{
|
|
67
|
+
"id": "research",
|
|
68
|
+
"type": "research",
|
|
69
|
+
"task": "…",
|
|
70
|
+
"outputs": [{ "path": "output/findings.md", "kind": "markdown", "required": true }]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "build",
|
|
74
|
+
"type": "code-run",
|
|
75
|
+
"task": "…",
|
|
76
|
+
"depends_on": ["research"],
|
|
77
|
+
"model": "kimi-coding/k3",
|
|
78
|
+
"effort": "high",
|
|
79
|
+
"outputs": [{ "path": "src/auth/login.ts", "kind": "file-exists", "required": true }]
|
|
80
|
+
}
|
|
51
81
|
]
|
|
52
82
|
}
|
|
53
83
|
```
|
|
54
84
|
|
|
85
|
+
- `config.model` / `config.effort` — fleet-wide defaults; per-worker `model` and `effort` override.
|
|
86
|
+
- `effort` maps to pi thinking levels: `off | minimal | low | medium | high | xhigh | max`.
|
|
87
|
+
- `config.warn_cost_usd` — soft cost guardrail surfaced in the canvas and report.
|
|
88
|
+
- `iterate: false` — run the node once at iteration 1 and carry its outputs forward.
|
|
89
|
+
- `worktree: true` — run the node in a dedicated git worktree.
|
|
90
|
+
- Worker types `research`, `code-run`, `reviewer`, `write`, `read-only` each get a tailored tool set.
|
|
91
|
+
|
|
92
|
+
## Fleet modes
|
|
93
|
+
|
|
94
|
+
**One-shot DAG** — static dependency graph, parallel layers, contracts at exit.
|
|
95
|
+
|
|
55
96
|
**Iterative fleet** — reviewer-gated replay until quality passes:
|
|
56
97
|
|
|
57
98
|
```json
|
|
@@ -64,7 +105,7 @@ The agent calls `fleet_plan` (validates + ASCII preview), you confirm, `fleet_la
|
|
|
64
105
|
|
|
65
106
|
A reviewer node writes a verdict contract (`verdict: lgtm | iterate | escalate` + actionable body). `iterate` → builders get the review injected as feedback next iteration. `lgtm` × `lgtm_count` consecutive → completed. `escalate` → fleet pauses and notifies you. `gate: "none"` → free-running loop (autoresearch pattern: eval instructions live in the worker's task text).
|
|
66
107
|
|
|
67
|
-
**Worktree mode** — `worktree: true` on a node: the worker
|
|
108
|
+
**Worktree mode** — `worktree: true` on a node: the worker runs in a dedicated git worktree on a deterministic branch (`fleet/<fleet-name>/<node-id>`). The extension creates the worktree, commits the worker's changes, and, when two or more worktree workers exist, auto-injects a `fleet-integrator` node that merges their branches in dependency order before the agent runs. Overlapping repo-relative output paths without an ordered handoff are rejected at plan time. Merge conflicts surface as a failed integrator with a `status_note` listing the files, so the operator can resolve and relaunch.
|
|
68
109
|
|
|
69
110
|
**Run-once vs replay nodes** — `iterate: false`: node runs at iteration 1 only, outputs carry over (e.g. research that doesn't change).
|
|
70
111
|
|
|
@@ -77,7 +118,15 @@ Every worker declares `outputs[]` with kinds, verified in code at worker exit be
|
|
|
77
118
|
| `markdown` | exists, non-empty, starts with `#` |
|
|
78
119
|
| `file-exists` | exists, non-empty (repo-relative paths = code edits) |
|
|
79
120
|
| `verdict` | `verdict: lgtm\|iterate\|escalate` line + non-empty body |
|
|
80
|
-
| `json`
|
|
121
|
+
| `json` | parses as JSON; optional `schema` checks (below) |
|
|
122
|
+
| `yaml` | parses as YAML |
|
|
123
|
+
|
|
124
|
+
JSON outputs may declare a `schema` with `required_keys` (keys that must exist) and `number_keys` (keys that must be numbers or arrays of numbers). Schemas are only allowed on `kind: "json"` outputs, are injected into the worker's prompt, and are enforced at contract check. When a `schema` is present, the JSON must be a top-level object (arrays and scalars fail):
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{ "path": "output/sum.json", "kind": "json", "required": true,
|
|
128
|
+
"schema": { "required_keys": ["operation", "result"], "number_keys": ["result"] } }
|
|
129
|
+
```
|
|
81
130
|
|
|
82
131
|
Failed required contract → `contract_failed`, dependents blocked, orchestrator notified. No silent passes.
|
|
83
132
|
|
|
@@ -85,37 +134,64 @@ Failed required contract → `contract_failed`, dependents blocked, orchestrator
|
|
|
85
134
|
|
|
86
135
|
| tool | purpose |
|
|
87
136
|
|---|---|
|
|
137
|
+
| `fleet_design` | draft a fleet DAG from plain-language requirements (planner agent → validated JSON + preview) |
|
|
88
138
|
| `fleet_plan` | validate + preview a fleet definition (no launch) |
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
139
|
+
| `fleet_models` | list available model refs (provider/id) from the live registry — call before `fleet_plan` if you don't know exact model IDs |
|
|
140
|
+
| `fleet_launch` | launch the planned fleet after user confirmation; `skip_confirm` for unattended runs |
|
|
141
|
+
| `fleet_status` | live DAG status and text summary |
|
|
142
|
+
| `fleet_continue` | resume a failed/killed fleet from current state without restarting completed nodes |
|
|
143
|
+
| `fleet_pause` / `fleet_resume` | pause/resume loop fleets at the next iteration boundary |
|
|
144
|
+
| `fleet_kill` | kill all, or kill a single node by worker id |
|
|
145
|
+
| `fleet_relaunch` | re-run a failed/killed node and its blocked downstream; optional model override |
|
|
146
|
+
| `fleet_add_node` | insert new workers into a running fleet mid-flight |
|
|
147
|
+
| `fleet_edit` | edit a pending node's model/effort/task, or fleet config mid-run |
|
|
148
|
+
| `fleet_report` | regenerate the fleet markdown report |
|
|
149
|
+
| `fleet_canvas` | open a browser canvas; `?demo=1` shows synthetic data for UI iteration |
|
|
150
|
+
|
|
151
|
+
`/fleet viz | status | clear | pause | resume | continue | kill all|<node_id> | relaunch <id> [model] | add <json> | edit <node_id>|config ... | configure [show|set k v] | canvas [open|url|stop]`
|
|
152
|
+
|
|
153
|
+
## Runtime mutation
|
|
154
|
+
|
|
155
|
+
Fleets are not frozen after launch. You can kill a single stuck node, relaunch it with a stronger model, edit a pending node's task, or inject new workers with `fleet_add_node`. Inserted nodes validate against the existing DAG (unique ids, acyclic, loop-gate rules) and start dispatching as soon as their dependencies complete.
|
|
156
|
+
|
|
157
|
+
## Preferences
|
|
95
158
|
|
|
96
|
-
|
|
159
|
+
Set fleet-wide defaults in `~/.pi/agent/fleet.json`:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"max_concurrent": 4,
|
|
164
|
+
"model": "gpt-5.4-mini",
|
|
165
|
+
"effort": "medium",
|
|
166
|
+
"warn_cost_usd": 10
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
These are merged into `fleet_plan` results. Manage them with `/fleet configure show | set <key> <value>`.
|
|
97
171
|
|
|
98
172
|
## Records
|
|
99
173
|
|
|
100
|
-
Everything lands in `.fleet/<name>-<ts>/` (git-ignored): `state.json` (single source of truth, atomic writes), per-worker `prompt.md` + `session.jsonl` + outputs, per-iteration archives, and a machine-written `report.md` with per-worker turns/tokens/cost, contract results, verdict history, and git diff stats.
|
|
174
|
+
Everything lands in `.fleet/<name>-<ts>/` (git-ignored): `state.json` (single source of truth, atomic writes), per-worker `prompt.md` + `session.jsonl` + outputs, per-iteration archives, and a machine-written `report.md` with per-worker turns/tokens/cost, contract results, verdict history, and git diff stats. Completed nodes keep their stats visible in the canvas and report after the fleet ends.
|
|
101
175
|
|
|
102
|
-
## Model selection
|
|
176
|
+
## Model selection and effort
|
|
103
177
|
|
|
104
|
-
Fleet-wide default via `config.model`; per-node override via `worker.model`. Any model pi can resolve
|
|
178
|
+
Fleet-wide default via `config.model` and `config.effort`; per-node override via `worker.model` and `worker.effort`. Any model pi can resolve works, including any provider pi is logged into. Cheap models for trivial writers, strong models for reviewers:
|
|
105
179
|
|
|
106
180
|
```json
|
|
107
|
-
{ "id": "reviewer", "type": "reviewer", "model": "kimi-coding/k3",
|
|
181
|
+
{ "id": "reviewer", "type": "reviewer", "model": "kimi-coding/k3", "effort": "high" }
|
|
108
182
|
```
|
|
109
183
|
|
|
184
|
+
Model refs are validated at plan and launch time so bad names fail fast. There is no baked-in default provider: the extension uses whatever pi has configured.
|
|
185
|
+
|
|
110
186
|
## Development
|
|
111
187
|
|
|
112
188
|
```bash
|
|
113
189
|
npm install
|
|
114
|
-
npm test #
|
|
190
|
+
npm test # 274 tests, zero-API (fake session factory)
|
|
115
191
|
npm run typecheck
|
|
116
192
|
```
|
|
117
193
|
|
|
118
|
-
Design docs
|
|
194
|
+
Design docs are archived locally under `.archive/docs/superpowers/` (not tracked); experiment history in `docs/experiments/`.
|
|
119
195
|
|
|
120
196
|
## License
|
|
121
197
|
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fleet_name": "json-number-pipeline",
|
|
3
|
+
"type": "dag",
|
|
4
|
+
"config": { "max_concurrent": 2 },
|
|
5
|
+
"workers": [
|
|
6
|
+
{
|
|
7
|
+
"id": "write-numbers",
|
|
8
|
+
"type": "write",
|
|
9
|
+
"task": "Write output/numbers.json containing exactly {\"values\":[3,5,8]}. No markdown. No commentary.",
|
|
10
|
+
"depends_on": [],
|
|
11
|
+
"outputs": [{ "path": "output/numbers.json", "kind": "json", "required": true, "schema": { "required_keys": ["values"], "number_keys": ["values"] } }]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "add-numbers",
|
|
15
|
+
"type": "write",
|
|
16
|
+
"task": "Read output/numbers.json from write-numbers. Write output/sum.json containing {\"operation\":\"add\",\"result\":16}.",
|
|
17
|
+
"depends_on": ["write-numbers"],
|
|
18
|
+
"outputs": [{ "path": "output/sum.json", "kind": "json", "required": true, "schema": { "required_keys": ["operation", "result"], "number_keys": ["result"] } }]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "subtract-numbers",
|
|
22
|
+
"type": "write",
|
|
23
|
+
"task": "Read output/numbers.json from write-numbers. Write output/difference.json containing {\"operation\":\"subtract\",\"result\":-10} using first value minus the rest.",
|
|
24
|
+
"depends_on": ["write-numbers"],
|
|
25
|
+
"outputs": [{ "path": "output/difference.json", "kind": "json", "required": true, "schema": { "required_keys": ["operation", "result"], "number_keys": ["result"] } }]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "synthesize",
|
|
29
|
+
"type": "write",
|
|
30
|
+
"task": "Read output/sum.json and output/difference.json. Write output/final.json containing {\"sum\":16,\"difference\":-10,\"combined\":6} where combined = sum + difference.",
|
|
31
|
+
"depends_on": ["add-numbers", "subtract-numbers"],
|
|
32
|
+
"outputs": [{ "path": "output/final.json", "kind": "json", "required": true, "schema": { "required_keys": ["sum", "difference", "combined"], "number_keys": ["sum", "difference", "combined"] } }]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-fleet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "DAG-of-agents fleets for pi — parallel workers with contracts, reviewer-gated iteration loops, and live progress",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"pi": {
|
|
24
24
|
"extensions": [
|
|
25
25
|
"./src/index.ts"
|
|
26
|
-
]
|
|
26
|
+
],
|
|
27
|
+
"image": "https://raw.githubusercontent.com/sagarsrc/pi-agent-fleet/v0.5.0/assets/canvas.png"
|
|
27
28
|
},
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"author": "Sagar Sarkale",
|
|
@@ -45,8 +46,15 @@
|
|
|
45
46
|
],
|
|
46
47
|
"files": [
|
|
47
48
|
"src/",
|
|
49
|
+
"assets/",
|
|
48
50
|
"examples/",
|
|
49
51
|
"README.md",
|
|
50
52
|
"LICENSE"
|
|
51
|
-
]
|
|
53
|
+
],
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@xyflow/react": "^12.11.2",
|
|
56
|
+
"esbuild": "^0.21.5",
|
|
57
|
+
"react": "^19.2.8",
|
|
58
|
+
"react-dom": "^19.2.8"
|
|
59
|
+
}
|
|
52
60
|
}
|