specpi 0.17.0 → 0.18.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 +14 -0
- package/NPM_RELEASE.md +23 -91
- package/README.md +4 -2
- package/SECURITY.md +6 -81
- package/SECURITY_MODEL.md +5 -1
- package/THIRD_PARTY.md +2 -2
- package/docs/browser-testing.md +3 -11
- package/docs/delegation/README.md +41 -322
- package/docs/delegation/protocol.md +24 -2
- package/extensions/command-guard/index.ts +3 -3
- package/extensions/delegation/core.mjs +26 -3
- package/extensions/delegation/extension.mjs +54 -3
- package/extensions/delegation/presentation.mjs +82 -0
- package/extensions/tool-wishlist/index.ts +3 -64
- package/package.json +4 -3
- package/scripts/specpi.mjs +6 -0
- package/docs/delegation/design-protocol.md +0 -382
- package/docs/delegation/design.md +0 -525
- package/docs/delegation/evaluation.md +0 -307
- package/docs/delegation/research.md +0 -216
- package/scripts/check-package.mjs +0 -528
- package/scripts/check-pi-package.mjs +0 -327
- package/scripts/check-release-order.mjs +0 -97
- package/scripts/check-syntax.mjs +0 -66
- package/scripts/pi-test-harness.mjs +0 -309
- package/scripts/run-browser-tests.mjs +0 -61
- package/scripts/setup-browser-tests.mjs +0 -38
- package/scripts/site-browser.mjs +0 -291
- package/scripts/verify-artifact.mjs +0 -21
- package/site/self-improvement-loop-v2.svg +0 -108
|
@@ -1,360 +1,79 @@
|
|
|
1
1
|
# Bounded delegation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
The package remains `specpi`; no separate npm package or background service is required.
|
|
3
|
+
Experimental; enabled by default at normal `pi` startup. No measured quality, speed or cost benefit is claimed.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
bounded, read-only workers for independent questions. It does not add a second writer,
|
|
8
|
-
an automatic planner, or a permanent team. The [research](research.md) supports testing
|
|
9
|
-
selective delegation; it does not establish that this implementation improves outcomes.
|
|
5
|
+
The parent remains the sole writer and verifies workers' evidence. Use delegation for a substantial independent question or frozen review, not routine lookups, small edits, coupled work or generic second opinions. Workers are real Pi SDK sessions with in-memory storage, selected-source read/search tools, no shell, writes, live web, ambient extensions or parent history.
|
|
10
6
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
pi
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
The native extension is discovered through the ordinary Pi package and SpecPi
|
|
18
|
-
install/update lifecycle. Existing Pi startup, UI, resources, trust decisions and
|
|
19
|
-
proxy configuration remain Pi-owned. Delegation needs no alternate launcher, extra
|
|
20
|
-
SDK host, separate runtime process or new setup path.
|
|
21
|
-
|
|
22
|
-
Delegation checks **SDK capabilities, not an exact Pi version list**. New Pi versions
|
|
23
|
-
can activate when the required public session, runtime, settings and thinking APIs are
|
|
24
|
-
available. Missing APIs produce an error naming the unavailable capability; session
|
|
25
|
-
construction and each request still enforce the tool, model and resource policy.
|
|
26
|
-
The [compatibility record](research.md#pi-compatibility-evidence) records tested versions
|
|
27
|
-
separately; API presence does not prove every future SDK behavior. Normal SpecPi installation
|
|
28
|
-
keeps its separately documented host floor and 0.84.4 bootstrap pin.
|
|
29
|
-
Restart Pi after updating SpecPi to load a changed delegation
|
|
30
|
-
runtime version or change its working root. The broker uses the canonical working
|
|
31
|
-
directory captured for this Pi process.
|
|
32
|
-
|
|
33
|
-
Workers are actual SDK `createAgentSession` instances with in-memory session storage.
|
|
34
|
-
Pi runs their model/tool loop. SpecPi supplies admission, selected-source tools and
|
|
35
|
-
result checks; it does not implement a second conversation loop. Children load no
|
|
36
|
-
ambient extensions, skills, AGENTS files or parent session history.
|
|
37
|
-
|
|
38
|
-
```mermaid
|
|
39
|
-
flowchart LR
|
|
40
|
-
parent["Parent Pi agent · sole writer"] -->|bounded question| controller["SpecPi admission and receipts"]
|
|
41
|
-
controller --> child["Pi AgentSession · memory only"]
|
|
42
|
-
child -->|admitted SDK invocation| runtime["Pi ModelRuntime"]
|
|
43
|
-
child -->|selected list/read/search| broker["Snapshot broker"]
|
|
44
|
-
child -->|claims and evidence| parent
|
|
45
|
-
parent --> checks["Verification and final decision"]
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
The child uses a fresh Pi `ModelRuntime` with standard authentication, environment
|
|
49
|
-
and `models.json` resolution. Its settings take transport and thinking budgets from
|
|
50
|
-
Pi's configured global settings; project settings are not loaded. The parent model and
|
|
51
|
-
thinking level are explicit. Pi's public thinking-level clamp determines the effective
|
|
52
|
-
child level, which the adapter verifies. Pi handles authentication
|
|
53
|
-
and OAuth; SpecPi does not copy credentials or inspect private runtime fields.
|
|
54
|
-
Preflight rejects runtime-only authentication, selected extension-registered provider
|
|
55
|
-
overrides, model-specific headers, startup proxy configuration and mismatched safe
|
|
56
|
-
model descriptors because the fresh runtime cannot faithfully reproduce those parent
|
|
57
|
-
routes. Parent configuration is left unchanged; an unsupported route disables delegation.
|
|
58
|
-
|
|
59
|
-
This is **not full parent inference parity**. Parent request hooks, ephemeral runtime
|
|
60
|
-
settings and session affinity are not automatically transferred. A workflow requiring
|
|
61
|
-
those inherited controls for every request must keep delegation disabled. Receipts
|
|
62
|
-
bind supported model and source descriptors; they cannot certify an unchanged remote
|
|
63
|
-
service or every configuration change behind a stable provider identity.
|
|
64
|
-
|
|
65
|
-
## Control delegation
|
|
66
|
-
|
|
67
|
-
The first session start of each Pi process enables delegation after settings, host and
|
|
68
|
-
Guard checks, in TUI, RPC, print and JSON modes. Startup does not launch workers or
|
|
69
|
-
model inference. Preflight may perform Pi-owned authentication/OAuth preparation.
|
|
70
|
-
Use one agent for small or sequential work; delegate only a justified independent question.
|
|
71
|
-
|
|
72
|
-
In an interactive session:
|
|
7
|
+
## Controls
|
|
73
8
|
|
|
74
9
|
```text
|
|
75
10
|
/delegate status
|
|
76
11
|
/delegate limits
|
|
77
12
|
/delegate cancel <batchId>
|
|
78
13
|
/delegate off
|
|
14
|
+
/delegate on
|
|
79
15
|
```
|
|
80
16
|
|
|
81
|
-
|
|
82
|
-
state, elapsed time, model calls and source-tool calls. `1/2 workers` means one of
|
|
83
|
-
two slots is occupied; it is not a completion percentage. Model calls are SDK
|
|
84
|
-
invocations, not tokens. Completed jobs remain visible as **ready for review** until
|
|
85
|
-
the parent resolves them. A cancelled worker shows **stopping** while its SDK request
|
|
86
|
-
still occupies a slot. The panel disappears when no work needs attention.
|
|
87
|
-
|
|
88
|
-
Tool output uses compact summaries. Expand it with Pi's normal tool-output shortcut
|
|
89
|
-
to read answers, findings, evidence references and missing context. These remain
|
|
90
|
-
advisory worker reports. `/delegate status` shows the selected model, process budgets
|
|
91
|
-
and batch IDs; use an ID with `/delegate cancel <batchId>` to cancel that batch.
|
|
92
|
-
|
|
93
|
-
The panel follows Pi's theme and adapts to terminal width. It refreshes at most once
|
|
94
|
-
per second between lifecycle changes, stops its timer when workers settle and is
|
|
95
|
-
removed on shutdown or reload. It reads counters without checking files or providers;
|
|
96
|
-
it does not retain or display live child reasoning. RPC and print mode keep the same
|
|
97
|
-
structured tool responses and do not mount terminal widgets. The UI uses Pi's public
|
|
98
|
-
[widget and tool-rendering APIs](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md).
|
|
17
|
+
Startup enables dispatch only after host, settings and Guard checks; it launches no workers. Preflight may perform Pi-owned authentication/OAuth preparation. Off and safety revocations survive reload/session switches; restarting Pi restores the on default. While off, the tool is absent from model requests.
|
|
99
18
|
|
|
100
|
-
The
|
|
101
|
-
`/delegate off` to revoke it and `/delegate on` to explicitly re-enable it. Off and
|
|
102
|
-
safety revocations survive `/reload` and session switches; restarting Pi reapplies the
|
|
103
|
-
on default. No on/off preference is written to disk. There is no model-call
|
|
104
|
-
permission toggle in the model-facing tool. `limits` is read-only; prompts cannot
|
|
105
|
-
change timeouts or raise other ceilings. Turning delegation off, changing guard policy, switching
|
|
106
|
-
sessions or models, navigating branches, and changing task/scope bindings revoke the
|
|
107
|
-
current generation. Off/on, `/reload` and session switches do not reset the Pi process's
|
|
108
|
-
counters or free requests that are still settling. The same in-memory controller remains
|
|
109
|
-
in use; restart Pi to load changed runtime code. Normal conversation leaf advancement
|
|
110
|
-
does not invalidate workers.
|
|
19
|
+
The TUI panel shows worker state, elapsed time and call counts. **Ready for review** requires a parent disposition; **stopping** still occupies a slot. RPC mode additionally publishes bounded, versioned worker metadata for SpecPi Chat's live Delegates panel; print/JSON modes do not mount widgets. Chat shows expandable tasks/metrics, attempt-bound Stop controls, and advisory transcript summaries. Update both Chat and the harness, then restart Pi. Expand tool output for findings and evidence.
|
|
111
20
|
|
|
112
|
-
|
|
113
|
-
level without another `/delegate on`. Each change revokes old worker results, retains
|
|
114
|
-
unsettled slots and consumed quotas, and checks the new host before resuming dispatch.
|
|
115
|
-
Old jobs are not retried. An unsupported selection pauses delegation with a reason;
|
|
116
|
-
selecting a compatible model resumes it automatically. `/delegate off` remains off
|
|
117
|
-
through later model changes. Guard, task/scope and session lifecycle changes still
|
|
118
|
-
revoke activation. Status separates the default or human `requested` choice from `enabled`
|
|
119
|
-
dispatch, with `updating` and `pauseReason` for model setup.
|
|
21
|
+
Model/thinking changes revoke old results and preflight the new route. Unsupported routes pause dispatch; compatible selections resume it unless explicitly off. Guard, session, branch and task/scope changes revoke the current generation. Ordinary conversation advancement does not. Reload/off/on never reset spent process quotas or release unsettled requests. Restart Pi to load changed runtime code or a different working root.
|
|
120
22
|
|
|
121
|
-
|
|
122
|
-
The command remains available, but the delegation tool schema is included in model
|
|
123
|
-
requests only after activation. Other active tools are preserved.
|
|
23
|
+
Command Guard is optional. Active Strict Guard binds approval to the exact call and effective policy; locked, unready or ambiguous installed Guard blocks activation. Workers remain restricted independently of Guard. Neither worker output nor parent acceptance grants human approval.
|
|
124
24
|
|
|
125
|
-
|
|
126
|
-
active, Command Guard continues to intercept the parent `delegate` tool. Strict mode presents
|
|
127
|
-
the effective capability envelope and binds approval to its policy fingerprint and
|
|
128
|
-
the exact call. A locked, unready or ambiguous installed Guard still blocks activation;
|
|
129
|
-
the error identifies that state. `/delegate status` reports the observed Guard state.
|
|
130
|
-
Worker tool restrictions and resource limits are enforced independently of Guard. A worker result
|
|
131
|
-
cannot authorize a write, a commit, a deployment, or an improvement.
|
|
25
|
+
## Persistent limits
|
|
132
26
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
The default is **10 minutes per logical job** (previously 2 minutes). In Pi:
|
|
27
|
+
Change settings only while delegation is off:
|
|
136
28
|
|
|
137
29
|
```text
|
|
138
30
|
/delegate off
|
|
139
31
|
/delegate timeout 15
|
|
32
|
+
/delegate budget 16
|
|
140
33
|
/delegate on
|
|
141
34
|
```
|
|
142
35
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
timeout (20 minutes by default), so it does not truncate the configured job window.
|
|
147
|
-
Both deadlines start at batch admission and include queue and follow-up time; a
|
|
148
|
-
follow-up never gets a fresh timeout. Provider requests use the remaining job window,
|
|
149
|
-
not a separate two-minute cap. Provider-side limits may still end requests sooner.
|
|
150
|
-
|
|
151
|
-
Changes require delegation to be off, including when model setup is pending or paused.
|
|
152
|
-
They apply to this process and future Pi starts; they cannot extend old jobs, reset
|
|
153
|
-
call quotas or free requests still settling. `/delegate on`, `status`, `limits` and
|
|
154
|
-
Strict Guard policy summaries display the effective timeout. Only the human command
|
|
155
|
-
can configure it; the model-facing tool has no timeout-setting operation.
|
|
156
|
-
|
|
157
|
-
The preference is stored in `<agent-dir>/specpi/delegation/settings.json`, where
|
|
158
|
-
`<agent-dir>` is `PI_CODING_AGENT_DIR` or `~/.pi/agent`. It contains only
|
|
159
|
-
`{"schema":1,"timeoutMinutes":15}`. Saves atomically replace this file and keep the
|
|
160
|
-
previous contents plus their SHA-256 in `settings.json.bak`. No Pi settings,
|
|
161
|
-
authentication, sessions or history are read or changed by this preference store.
|
|
162
|
-
The human-selected agent directory is resolved once, supporting platform path aliases.
|
|
163
|
-
Preference files and SpecPi subdirectories must not be links. Malformed, oversized or
|
|
164
|
-
unreadable settings block activation rather than silently using another timeout. Repair them manually
|
|
165
|
-
and restart Pi. Manual edits and changes from another Pi process take effect on
|
|
166
|
-
restart; `/reload` preserves the current process policy and counters. The preference
|
|
167
|
-
survives uninstall as user-owned configuration.
|
|
168
|
-
|
|
169
|
-
## Admit a specific purpose
|
|
170
|
-
|
|
171
|
-
| Mode | Required structure | Context and tools |
|
|
172
|
-
| -------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
173
|
-
| `review` | A frozen artifact, original requirements, relevant constraints and actual validation facts. The parent checks findings before acting. | Nonempty inline context or selected files; selected-source tools when files are supplied. |
|
|
174
|
-
| `scout` | A bounded evidence question with an independently checkable answer and a reason to separate the analysis. | At least one selected file; list/read/literal-search only, with no live web access. |
|
|
175
|
-
|
|
176
|
-
The packet declares one benefit: `independent_review` for review jobs, or
|
|
177
|
-
`parallel_analysis` / `context_isolation` for scout jobs. It includes a nonempty `why`.
|
|
178
|
-
`parallel_analysis` also requires useful `parentWork`; this may be empty for the other
|
|
179
|
-
benefits. A final review can be useful even when the parent waits. The controller checks
|
|
180
|
-
this structure, not whether the claimed benefit will materialize. Duplicate questions
|
|
181
|
-
after trimming and case normalization are rejected; distinct text is not proof of
|
|
182
|
-
independent work.
|
|
183
|
-
|
|
184
|
-
Each job names its assigned global requirement IDs and receives only those requirements,
|
|
185
|
-
plus the fixed decisions and non-goals. Transfer original constraints and evidence,
|
|
186
|
-
not the parent's reasoning or verdict. Do not delegate routine lookups, small understood
|
|
187
|
-
edits, coupled mutable work, generic second opinions or repeated role-based answers.
|
|
188
|
-
Use parallel parent tool calls when retrieval alone answers the question.
|
|
189
|
-
|
|
190
|
-
Workers have no shell, writes, arbitrary plugin tools or recursive delegation.
|
|
191
|
-
The parent obtains and selects source material. Model routing, automatic provider retries,
|
|
192
|
-
live-web access, monetary admission and automatic policy tuning remain unimplemented.
|
|
193
|
-
|
|
194
|
-
`/task` remains optional. Changes to an active task contract invalidate delegation,
|
|
195
|
-
but the parent is still responsible for faithfully transferring the task into the packet.
|
|
196
|
-
|
|
197
|
-
Use `delegate run`, continue useful parent work, then `collect`. Collection can wait
|
|
198
|
-
up to 30 seconds without another model request. Do not poll on a fixed schedule.
|
|
199
|
-
Check the referenced evidence and `resolve` each report, including per-finding
|
|
200
|
-
dispositions. One changed-input `follow_up` is available under the original deadline
|
|
201
|
-
and counters. [Protocol and executable examples](protocol.md) define the exact fields.
|
|
202
|
-
|
|
203
|
-
## Enforced resource envelope
|
|
204
|
-
|
|
205
|
-
| Resource | Ceiling |
|
|
206
|
-
| ------------------------- | ---------------------------------------------------------------------------- |
|
|
207
|
-
| Active worker requests | 2 per Pi process, including cancelled requests still settling |
|
|
208
|
-
| Batches / jobs | 32 batches per Pi process; one unresolved batch; 2 jobs per batch |
|
|
209
|
-
| SDK model invocations | 256 per Pi process, 64 per batch; 32 per logical job including follow-up |
|
|
210
|
-
| Follow-ups / retries | 1 changed-input follow-up per job; provider and session retries disabled |
|
|
211
|
-
| Time | 10 minutes per job by default (human configurable 1–60); batch twice that; queue/follow-up included |
|
|
212
|
-
| Packet / child context | 256 KiB handoff; 2 MiB serialized child context, checked before dispatch |
|
|
213
|
-
| Selected sources | 200 files and 8 MiB per batch |
|
|
214
|
-
| Tools | 96 calls and 512 KiB total returned JSON per logical job |
|
|
215
|
-
| Tool response | Bounded reads/search; 16 KiB per snapshot read/search response |
|
|
216
|
-
| Final report | 16 KiB; 8 findings; coverage for each assigned requirement |
|
|
217
|
-
| Requested provider output | Pi's normal provider/model output and thinking settings |
|
|
218
|
-
| SDK-visible response | 1 MiB acceptance limit on observed response content; scales with budget |
|
|
219
|
-
|
|
220
|
-
These use the default budget multiplier of 8, not empirically optimal values. Each SDK
|
|
221
|
-
invocation is admitted before dispatch. Automatic provider/session retries and
|
|
222
|
-
compaction are disabled, so they cannot silently create another SDK request.
|
|
223
|
-
Ordinary source-argument mistakes return corrective feedback. Invalid or truncated
|
|
224
|
-
reports trigger a correction in the same child session with its passages preserved.
|
|
225
|
-
These corrections consume the existing model-call, context and deadline budgets;
|
|
226
|
-
they do not create a fresh job or reset usage. Only a validated report can complete.
|
|
227
|
-
|
|
228
|
-
Use `/delegate off`, `/delegate budget 16`, then `/delegate on` for a larger review:
|
|
229
|
-
192 source tool calls, 1 MiB source output, and 64 model turns per job. The human-only
|
|
230
|
-
budget command saves a multiplier from 1 to 64; `budget reset` restores 8. It scales
|
|
231
|
-
tool calls/output, model turns per job/batch/process, process batches, and serialized
|
|
232
|
-
child context and SDK response bytes together. It leaves concurrency, tool-response/packet/result limits,
|
|
233
|
-
and timeouts unchanged. Existing settings files use 8 when no budget is saved.
|
|
234
|
-
Budget changes invalidate old jobs and preserve spent process counters. Use a fresh
|
|
235
|
-
batch afterward. Increasing budgets can increase model usage, cost, and retained
|
|
236
|
-
context; provider context-window limits still apply.
|
|
36
|
+
- `timeout`: whole minutes 1–60, default 10; `timeout reset` restores it. Batch deadline is twice the job timeout. Both begin at admission, including queue/follow-up time.
|
|
37
|
+
- `budget`: multiplier 1–64, default 8; `budget reset` restores it. Scales call/byte/context allowances, not concurrency, deadlines or per-response limits. Higher budgets can increase cost.
|
|
38
|
+
- Commands without values show current settings. Models cannot change them. Changes preserve consumed process counters and cannot extend existing jobs.
|
|
237
39
|
|
|
238
|
-
|
|
239
|
-
total beyond the allowance. Budget exhaustion reports the specific allowance and
|
|
240
|
-
blocks a follow-up before launching a child. Successful follow-ups retain their
|
|
241
|
-
existing passages and share the original budget/deadline. A failed child is released;
|
|
242
|
-
when another attempt is eligible it starts with the original handoff, not the failed
|
|
243
|
-
child's transcript.
|
|
244
|
-
Pi authentication preflight occurs before the model-invocation counter; these quotas
|
|
245
|
-
do not count or bound Pi's authentication/OAuth preparation.
|
|
40
|
+
Preferences live in `<agent-dir>/specpi/delegation/settings.json`, with an atomic backup and checksum; `<agent-dir>` is `PI_CODING_AGENT_DIR` or `~/.pi/agent`. They survive uninstall. Linked, malformed, oversized or unreadable preferences block activation. Repair manually and restart; external edits are loaded on restart, not reload. Pi credentials/settings/history are not modified.
|
|
246
41
|
|
|
247
|
-
|
|
248
|
-
hard bounds on raw transport, hidden provider attempts, billing or process memory.
|
|
249
|
-
Bytes may already be buffered before an SDK event becomes visible. Stream checks count
|
|
250
|
-
recognized deltas incrementally; full response validation occurs at content/terminal
|
|
251
|
-
boundaries, before tool execution and before publication. This relies on Pi's parsed
|
|
252
|
-
stream contract, not arbitrary inconsistent partial objects. Cheap lease checks run
|
|
253
|
-
per event; full root, model and provider-policy checks run at protected boundaries.
|
|
254
|
-
The parsed stream allows at most 64 content blocks, 512 structural nodes per partial,
|
|
255
|
-
65,536 events and 130 non-delta boundaries per invocation. These are implementation
|
|
256
|
-
ceilings, not empirically optimal values.
|
|
257
|
-
Cost is unavailable; available token fields are retained even when others are missing.
|
|
258
|
-
Never-reported fields are `null`, and per-field `usageReportedCalls` distinguishes
|
|
259
|
-
partial totals from complete accounting. This version cannot satisfy a policy
|
|
260
|
-
requiring those unsupported guarantees.
|
|
42
|
+
Default envelope (`/delegate limits` reports the effective policy):
|
|
261
43
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
44
|
+
| Resource | Ceiling |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| Concurrent requests | 2, including cancelled requests still settling |
|
|
47
|
+
| Batches | 32/process; one unresolved batch; 2 jobs/batch |
|
|
48
|
+
| SDK model calls | 256/process, 64/batch, 32/job including follow-up |
|
|
49
|
+
| Follow-up | One changed-input attempt, original budgets/deadline |
|
|
50
|
+
| Handoff / child context | 256 KiB / 2 MiB |
|
|
51
|
+
| Selected sources | 200 files, 8 MiB/batch |
|
|
52
|
+
| Source tools | 96 calls, 512 KiB returned JSON/job; 16 KiB/read or search |
|
|
53
|
+
| Final report | 16 KiB, 8 findings, coverage of every assigned requirement |
|
|
54
|
+
| SDK-visible response | 1 MiB acceptance limit |
|
|
268
55
|
|
|
269
|
-
|
|
56
|
+
Provider/session retries and compaction are disabled. Correctable source arguments and malformed reports can consume further calls within the same job. A failed attempt is not a review. Exhaustion, revocation and source changes terminate it. These are SDK-visible limits, not guarantees about raw transport, memory, remote attempts or billing. Cost is unavailable; missing token fields are `null` and receipts identify partial usage.
|
|
270
57
|
|
|
271
|
-
|
|
272
|
-
working root of the Pi process. The broker rejects traversal, symlinks/junctions,
|
|
273
|
-
hardlinks, binary content, private path
|
|
274
|
-
names, unknown source IDs, and oversized reads. Each worker can search only its own
|
|
275
|
-
selection. Capture verifies content digests. Each tool call checks canonical paths,
|
|
276
|
-
file identity and change metadata against the immutable capture, without rereading
|
|
277
|
-
all selected bytes. Publication, collection, follow-up and disposition also recheck
|
|
278
|
-
content digests. Changed source bindings require a fresh batch. A content change that
|
|
279
|
-
evades filesystem metadata is detected at the next digest check, not by each tool call.
|
|
58
|
+
## Workflow and evidence
|
|
280
59
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
unsupported file types, missing or inaccessible files, links, quotas, or changed or
|
|
286
|
-
non-text content. The diagnostic never includes raw filesystem errors or file contents.
|
|
287
|
-
Rejection starts no worker and consumes no batch or inference allowance. It provides
|
|
288
|
-
no independent review. Check the reported cause before submitting corrected inputs;
|
|
289
|
-
do not rename or copy restricted files to bypass the source policy.
|
|
60
|
+
1. `run`: supply requirements, decisions, non-goals and distinct jobs. `review` needs frozen inline context or files; `scout` needs selected files. Explain the independent-review, parallel-analysis or context-isolation benefit; parallel work also names useful parent work.
|
|
61
|
+
2. `collect`: wait up to 30 seconds for advisory reports; avoid fixed polling.
|
|
62
|
+
3. Verify source citations and findings against the original requirements.
|
|
63
|
+
4. `resolve`: record acceptance/discard/check-needed and each finding's disposition. One changed-input `follow_up` shares the original budget and deadline.
|
|
290
64
|
|
|
291
|
-
|
|
292
|
-
`credential-url.json`, and `sessions/` are allowed across supported text formats.
|
|
293
|
-
The parent chooses the review material. Private namespaces such as `.pi`, `.ssh`,
|
|
294
|
-
and SpecPi Chat storage, the configured Pi agent directory (including its canonical
|
|
295
|
-
alias target), `.env` files, credential stores such as `auth.json` and
|
|
296
|
-
`credentials.json`, and private keys remain blocked. An inaccessible configured
|
|
297
|
-
Pi storage boundary must be repaired before capture. All selected-file scope,
|
|
298
|
-
containment, link, text, size, and freshness checks still apply. Source naming is
|
|
299
|
-
not proof that a file contains no secrets. Workers have no ambient source access;
|
|
300
|
-
using the parent's provider does not grant them the parent's tools or transcript.
|
|
65
|
+
See [protocol.md](protocol.md) for exact request and receipt fields.
|
|
301
66
|
|
|
302
|
-
|
|
303
|
-
atomic filesystem snapshot. Filename restrictions cannot detect secrets embedded in
|
|
304
|
-
an ordinary source file. The parent must select appropriate material for the configured
|
|
305
|
-
model provider. Trusted Pi extensions remain privileged in the shared process despite
|
|
306
|
-
being absent from the child's resource loader. Only the submitted packet is inherited
|
|
307
|
-
automatically, not the parent transcript.
|
|
67
|
+
Only exact regular text files under the startup working root are selectable. Traversal, links/hardlinks, binary/oversized files, private runtime storage and credential stores are rejected. Ordinary authentication/session *source code* names are allowed. Filenames cannot prove absence of secrets: the parent must select material appropriate for the provider. Workers see only their own selected snapshot. Paths/identity/change metadata are checked during tools; content digests are rechecked at publication, collection, follow-up and resolution. Changed bindings require a fresh batch.
|
|
308
68
|
|
|
309
|
-
|
|
310
|
-
digest, generation, result revision, route, state, counters and usage completeness.
|
|
311
|
-
Source references are validated for identity and line range; their truth is still a
|
|
312
|
-
verification question for the parent. `accept` records a parent assessment, not human
|
|
313
|
-
approval or verified task completion.
|
|
69
|
+
Selection errors identify a safe reason and source position, without raw paths/errors; no worker starts or inference allowance is spent. Fix the cause, never rename or copy restricted material to evade policy. Source references are checked for identity/range, not truth. Parent acceptance is not independent proof or task completion.
|
|
314
70
|
|
|
315
|
-
|
|
316
|
-
follow-up or original deadline releases the child; active SDK work retains its slot until
|
|
317
|
-
settlement. Teardown failures do not escape into Pi's event loop. Shared snapshot text
|
|
318
|
-
is destroyed once no job can continue, including failed jobs at their original deadline.
|
|
319
|
-
Packet and job-input references are dropped when owned workers settle. Source metadata
|
|
320
|
-
and digests still validate completed reports after text is destroyed. Starting the next
|
|
321
|
-
accepted batch retires the previous batch's reports; invalidation retires old generations
|
|
322
|
-
after their workers settle. Retired batches cannot be collected or followed up.
|
|
323
|
-
Only bounded state summaries, quota counters and the idempotency journal remain for
|
|
324
|
-
the Pi process lifetime, including `/reload` and session switches. They cannot recreate
|
|
325
|
-
retired work. SDK setup errors are replaced with generic diagnostics before reaching
|
|
326
|
-
status, command notices or model-facing errors; code-owned policy errors stay specific.
|
|
327
|
-
Worker failures identify the failing stage: source tools, provider requests, stream or
|
|
328
|
-
context/response limits, missing/truncated output, or final JSON/schema/evidence validation.
|
|
329
|
-
Known source and report-validation reasons are included; raw provider errors, rejected
|
|
330
|
-
report text, and filesystem paths are not. A tool failure keeps its original diagnostic
|
|
331
|
-
even when Pi aborts the session. A low tool-call count therefore does not imply a reading
|
|
332
|
-
budget failure. Delegation does not impose its own output-token cap. Ordinary argument
|
|
333
|
-
errors and invalid reports can be corrected within the same session; source changes,
|
|
334
|
-
revocation, unavailable tools and exhausted allowances still terminate it. No failure
|
|
335
|
-
is a completed review or independent sign-off. Provider failures do not trigger automatic
|
|
336
|
-
retries; a changed-input follow-up still shares the original job allowances
|
|
337
|
-
and deadline, and a released failed child starts from its original handoff.
|
|
338
|
-
There is no child session database, raw metrics log,
|
|
339
|
-
credential copy, automatic resume, or secure memory-erasure claim. Normal Pi parent
|
|
340
|
-
tool results may be retained in its ordinary session. Turning delegation off does not
|
|
341
|
-
remove results already retained by Pi; review the session before sharing it.
|
|
71
|
+
Cancellation revokes access and requests SDK abort. Slots remain held until SDK-visible settlement; this cannot prove remote execution ended. Late content is discarded. Non-cooperative providers may require ending Pi. Sessions are released on final disposition, cancellation, exhausted follow-up or deadline; settled text/packets are dropped when no job can continue. Completed reports retain source bindings; a new accepted batch retires previous reports. Only bounded summaries, counters and idempotency records remain for the process lifetime. No child database, raw metrics log, automatic resume or secure-erasure guarantee exists. Parent tool results may remain in Pi history even after delegation is off.
|
|
342
72
|
|
|
343
|
-
##
|
|
73
|
+
## Host limitations
|
|
344
74
|
|
|
345
|
-
The
|
|
346
|
-
snapshot tools and closed result validation. There are no additional runtime dependencies
|
|
347
|
-
or separate host process. Compatibility requires verification against the supported
|
|
348
|
-
Pi SDK and ordinary package discovery, not merely a passing mock provider.
|
|
75
|
+
Activation checks required public SDK capabilities, not an exact version allowlist. The installer retains its separate Pi 0.84.4 bootstrap pin. Restart after updating the runtime.
|
|
349
76
|
|
|
350
|
-
|
|
351
|
-
task outcomes. Use isolated state and synthetic providers for contract tests; live
|
|
352
|
-
inference needs separate authorization. Such fixtures do not establish parity with
|
|
353
|
-
the parent's full inference pipeline or every production provider.
|
|
77
|
+
Children use fresh Pi `ModelRuntime` instances with standard authentication/environment/models resolution and global transport/thinking settings. Project settings are not loaded. Parent model/thinking are explicit and checked through Pi's public APIs. Runtime-only authentication, selected extension-provider overrides, model headers, startup proxy configuration and mismatched model descriptors are rejected rather than silently approximated.
|
|
354
78
|
|
|
355
|
-
|
|
356
|
-
agents, serial workflows and always-delegate baselines using matched resource budgets.
|
|
357
|
-
No production quality, speed or cost improvement is claimed until those experiments run.
|
|
358
|
-
The [original design](design.md) and [target protocol](design-protocol.md) preserve the
|
|
359
|
-
broader proposal and its currently unimplemented proof obligations. The implemented
|
|
360
|
-
[calls/time protocol](protocol.md) is the source of truth for this release's behavior.
|
|
79
|
+
Parent hooks, ephemeral settings and session affinity are **not inherited**. Keep delegation off if they are required on every request. Stable provider identity cannot certify an unchanged remote service. Trusted extensions still share Pi's privileged process; this is a trusted-local-filesystem contract, not an OS sandbox. See [SECURITY_MODEL.md](../../SECURITY_MODEL.md) for the authoritative boundaries and [THIRD_PARTY.md](../../THIRD_PARTY.md) for dependency compatibility.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Delegation protocol: bounded-pi-sessions-v1
|
|
2
2
|
|
|
3
3
|
This is the implemented in-process API. It has no HTTP listener, daemon, child process,
|
|
4
|
-
or child session store.
|
|
5
|
-
proposal; its stronger transport/attempt/cost gates are not supplied by this version.
|
|
4
|
+
or child session store.
|
|
6
5
|
|
|
7
6
|
The extension loads through normal `pi` package discovery and enables delegation at
|
|
8
7
|
the first session start of each Pi process, including noninteractive modes. Startup
|
|
@@ -241,6 +240,29 @@ cache. After eviction, those operations are revalidated against current state; t
|
|
|
241
240
|
cannot start inference or restore cancelled jobs. Generation and source checks still
|
|
242
241
|
apply. Neither cache eviction nor failed attempts reset quotas or block cancellation.
|
|
243
242
|
|
|
243
|
+
## RPC display metadata
|
|
244
|
+
|
|
245
|
+
In RPC mode, the extension emits `setWidget` with key `specpi-delegation-v1`
|
|
246
|
+
and a single JSON string in `widgetLines`. Version 1 contains `enabled`, occupied
|
|
247
|
+
`active` slots, `concurrency`, process `calls`/`callLimit`, and at most eight job rows.
|
|
248
|
+
Rows contain batch/job/attempt IDs, mode, state, settlement, call/tool counters,
|
|
249
|
+
elapsed milliseconds, a shortened task label, public provider/model names,
|
|
250
|
+
parent disposition and code-owned diagnostics. No source snapshots, full prompts,
|
|
251
|
+
child transcript or provider query is part of this channel. Sampling is at most
|
|
252
|
+
once a second between lifecycle updates and stops when no slots are occupied.
|
|
253
|
+
Invalidated-generation job identities/tasks are omitted; their unsettled slots still
|
|
254
|
+
count. A replaced batch in the same generation remains visible until settlement.
|
|
255
|
+
Shutdown/rebinding clears the old widget and timer. No new persistent store is added.
|
|
256
|
+
|
|
257
|
+
Chat treats this payload as untrusted, accepts one bounded versioned record, strips
|
|
258
|
+
controls and renders text only. Its Stop button invokes
|
|
259
|
+
`/delegate cancel-worker <batchId> <jobId> <attemptId>` through normal RPC command
|
|
260
|
+
dispatch. This human UI command checks the exact current queued/running attempt
|
|
261
|
+
before cancellation; it cannot cancel a later follow-up under the same job name,
|
|
262
|
+
start inference, raise limits or alter the user's draft/attachments. Parent Stop and
|
|
263
|
+
worker Stop are separate controls. Neither stopping nor settlement proves remote
|
|
264
|
+
termination. Existing model-facing `cancel` requests are unchanged.
|
|
265
|
+
|
|
244
266
|
## Cancellation and lifecycle
|
|
245
267
|
|
|
246
268
|
```json
|
|
@@ -163,7 +163,7 @@ export default function registerCommandGuard(
|
|
|
163
163
|
approvalTimeoutMs?: number;
|
|
164
164
|
} = {},
|
|
165
165
|
): void {
|
|
166
|
-
//
|
|
166
|
+
// The terminal startup chooser falls back to Guard, so it stays short; RPC starts off without a dialog.
|
|
167
167
|
// An approval waits on a person reading severity, category, cwd, affected paths, reason, and alternative;
|
|
168
168
|
// withTimeout cannot cancel the underlying prompt, so a short bound would deny work mid-decision and leave
|
|
169
169
|
// a live selector on screen. Both directions still fail closed, just on a human timescale.
|
|
@@ -230,14 +230,14 @@ export default function registerCommandGuard(
|
|
|
230
230
|
try {
|
|
231
231
|
subscribeGuardState();
|
|
232
232
|
// Pi RPC binds session_start before it starts reading UI responses.
|
|
233
|
-
// Begin
|
|
233
|
+
// Begin off without a startup dialog; /guard remains available
|
|
234
234
|
// for explicit changes once the RPC client is connected.
|
|
235
235
|
const choice = ctx.hasUI && ctx.mode !== "rpc" ? await startupChoice(ctx, startupTimeoutMs) : undefined;
|
|
236
236
|
if (state.generation !== startupGeneration) {
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
let mode: "guard" | "strict" | "off" = "guard";
|
|
240
|
+
let mode: "guard" | "strict" | "off" = ctx.mode === "rpc" ? "off" : "guard";
|
|
241
241
|
if (choice === "Strict") {
|
|
242
242
|
mode = "strict";
|
|
243
243
|
} else if (choice === "Off for this session") {
|
|
@@ -86,8 +86,9 @@ export function createDelegationController({
|
|
|
86
86
|
cost: "unavailable; no invoice cap",
|
|
87
87
|
batches: [...[...history.values()].map((item) => structuredClone(item)), ...[...batches.values()].map(summary)],
|
|
88
88
|
});
|
|
89
|
-
// Presentation
|
|
90
|
-
|
|
89
|
+
// Presentation samples bounded metadata only: no source checks or provider queries.
|
|
90
|
+
// RPC includes terminal rows so a stopped worker does not silently disappear.
|
|
91
|
+
const presentation = ({ includeInactive = false } = {}) => ({
|
|
91
92
|
enabled,
|
|
92
93
|
active,
|
|
93
94
|
concurrency: policy.concurrency,
|
|
@@ -95,9 +96,24 @@ export function createDelegationController({
|
|
|
95
96
|
callLimit: policy.sessionCalls,
|
|
96
97
|
jobs: [...batches.values()].flatMap((batch) =>
|
|
97
98
|
[...batch.jobs.values()]
|
|
98
|
-
.filter((job) =>
|
|
99
|
+
.filter((job) =>
|
|
100
|
+
includeInactive
|
|
101
|
+
? batch.generation === generation
|
|
102
|
+
: job.settling || (!batch.retired && !quiet.has(job.state) && !job.disposition),
|
|
103
|
+
)
|
|
99
104
|
.map((job) => ({
|
|
100
105
|
id: job.spec.id,
|
|
106
|
+
...(includeInactive
|
|
107
|
+
? {
|
|
108
|
+
batchId: batch.id,
|
|
109
|
+
attemptId: job.attemptId,
|
|
110
|
+
task: job.spec.question?.slice(0, 240) || "",
|
|
111
|
+
provider: batch.model?.provider,
|
|
112
|
+
model: batch.model?.id,
|
|
113
|
+
disposition: job.disposition?.decision ?? null,
|
|
114
|
+
error: job.error ?? null,
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
101
117
|
mode: job.mode,
|
|
102
118
|
state: job.state,
|
|
103
119
|
settling: job.settling,
|
|
@@ -395,6 +411,13 @@ export function createDelegationController({
|
|
|
395
411
|
}
|
|
396
412
|
|
|
397
413
|
active -= 1;
|
|
414
|
+
// A replaced batch can still own a stopping worker. Publish
|
|
415
|
+
// its settlement before cleanup removes it, but never expose
|
|
416
|
+
// an invalidated generation to the new context.
|
|
417
|
+
if (batch.retired && batch.generation === generation) {
|
|
418
|
+
changed();
|
|
419
|
+
}
|
|
420
|
+
|
|
398
421
|
cleanupBatch(batch);
|
|
399
422
|
changed();
|
|
400
423
|
pump();
|