specpi 0.11.2 → 0.13.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 +21 -1
- package/NPM_RELEASE.md +3 -1
- package/README.md +41 -29
- package/SECURITY_MODEL.md +36 -0
- package/THIRD_PARTY.md +18 -2
- package/docs/browser-testing.md +76 -0
- package/docs/delegation/README.md +264 -0
- package/docs/delegation/design-protocol.md +382 -0
- package/docs/delegation/design.md +525 -0
- package/docs/delegation/evaluation.md +307 -0
- package/docs/delegation/protocol.md +271 -0
- package/docs/delegation/research.md +216 -0
- package/extensions/browser/core.d.mts +64 -0
- package/extensions/browser/diagnostics.ts +275 -0
- package/extensions/browser/index.ts +349 -57
- package/extensions/browser/interactions.ts +118 -0
- package/extensions/browser/lifecycle.ts +28 -0
- package/extensions/command-guard/index.ts +118 -33
- package/extensions/delegation/core.mjs +772 -0
- package/extensions/delegation/errors.mjs +8 -0
- package/extensions/delegation/extension.mjs +475 -0
- package/extensions/delegation/index.ts +9 -0
- package/extensions/delegation/managed-files.mjs +13 -0
- package/extensions/delegation/native.mjs +155 -0
- package/extensions/delegation/presentation.mjs +315 -0
- package/extensions/delegation/protocol.mjs +296 -0
- package/extensions/delegation/provider.mjs +689 -0
- package/extensions/delegation/snapshot.mjs +532 -0
- package/extensions/delegation/worker.mjs +218 -0
- package/extensions/tool-wishlist/verification.mjs +1 -0
- package/extensions/workflow-controls/index.ts +5 -1
- package/package.json +17 -4
- package/scripts/check-package.mjs +29 -3
- package/scripts/check-pi-package.mjs +5 -0
- package/scripts/check-syntax.mjs +61 -0
- package/scripts/run-browser-tests.mjs +61 -0
- package/scripts/setup-browser-tests.mjs +38 -0
- package/scripts/site-browser.mjs +272 -0
- package/scripts/specpi.mjs +24 -0
- package/site/logo.svg +1 -9
- package/templates/AGENTS.md +1 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Bounded delegation
|
|
2
|
+
|
|
3
|
+
Status: experimental in SpecPi 0.13.0. Disabled by default.
|
|
4
|
+
The package remains `specpi`; no separate npm package or background service is required.
|
|
5
|
+
|
|
6
|
+
SpecPi keeps one agent responsible for changes and acceptance. This extension adds
|
|
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.
|
|
10
|
+
|
|
11
|
+
## Use normal Pi startup
|
|
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
|
+
## Enable deliberately
|
|
66
|
+
|
|
67
|
+
In the interactive session:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
/delegate on
|
|
71
|
+
/delegate status
|
|
72
|
+
/delegate limits
|
|
73
|
+
/delegate cancel <batchId>
|
|
74
|
+
/delegate off
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
In Pi's terminal UI, a small panel above the editor shows each worker's ID, role,
|
|
78
|
+
state, elapsed time, model calls and source-tool calls. `1/2 workers` means one of
|
|
79
|
+
two slots is occupied; it is not a completion percentage. Model calls are SDK
|
|
80
|
+
invocations, not tokens. Completed jobs remain visible as **ready for review** until
|
|
81
|
+
the parent resolves them. A cancelled worker shows **stopping** while its SDK request
|
|
82
|
+
still occupies a slot. The panel disappears when no work needs attention.
|
|
83
|
+
|
|
84
|
+
Tool output uses compact summaries. Expand it with Pi's normal tool-output shortcut
|
|
85
|
+
to read answers, findings, evidence references and missing context. These remain
|
|
86
|
+
advisory worker reports. `/delegate status` shows the selected model, process budgets
|
|
87
|
+
and batch IDs; use an ID with `/delegate cancel <batchId>` to cancel that batch.
|
|
88
|
+
|
|
89
|
+
The panel follows Pi's theme and adapts to terminal width. It refreshes at most once
|
|
90
|
+
per second between lifecycle changes, stops its timer when workers settle and is
|
|
91
|
+
removed on shutdown or reload. It reads counters without checking files or providers;
|
|
92
|
+
it does not retain or display live child reasoning. RPC and print mode keep the same
|
|
93
|
+
structured tool responses and do not mount terminal widgets. The UI uses Pi's public
|
|
94
|
+
[widget and tool-rendering APIs](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md).
|
|
95
|
+
|
|
96
|
+
`on` grants the displayed experimental calls/time envelope. There is no model-call
|
|
97
|
+
permission toggle in the model-facing tool. `limits` is read-only; the shipped ceilings
|
|
98
|
+
cannot be raised by prompts. Turning delegation off, changing guard policy, switching
|
|
99
|
+
sessions or models, navigating branches, and changing task/scope bindings revoke the
|
|
100
|
+
current generation. Off/on, `/reload` and session switches do not reset the Pi process's
|
|
101
|
+
counters or free requests that are still settling. The same in-memory controller remains
|
|
102
|
+
in use; restart Pi to load changed runtime code. Normal conversation leaf advancement
|
|
103
|
+
does not invalidate workers.
|
|
104
|
+
|
|
105
|
+
Once enabled, delegation follows changes to the parent's provider, model and thinking
|
|
106
|
+
level without another `/delegate on`. Each change revokes old worker results, retains
|
|
107
|
+
unsettled slots and consumed quotas, and checks the new host before resuming dispatch.
|
|
108
|
+
Old jobs are not retried. An unsupported selection pauses delegation with a reason;
|
|
109
|
+
selecting a compatible model resumes it automatically. `/delegate off` remains off
|
|
110
|
+
through later model changes. Guard, task/scope and session lifecycle changes still
|
|
111
|
+
revoke activation. Status separates the user's `requested` choice from `enabled`
|
|
112
|
+
dispatch, with `updating` and `pauseReason` for model setup.
|
|
113
|
+
|
|
114
|
+
While delegation is off, its tool is removed from the parent's active tool list.
|
|
115
|
+
The command remains available, but the delegation tool schema is included in model
|
|
116
|
+
requests only after activation. Other active tools are preserved.
|
|
117
|
+
|
|
118
|
+
Command Guard is optional: delegation can run when Guard is absent or Off. When
|
|
119
|
+
active, Command Guard continues to intercept the parent `delegate` tool. Strict mode presents
|
|
120
|
+
the effective capability envelope and binds approval to its policy fingerprint and
|
|
121
|
+
the exact call. A locked, unready or ambiguous installed Guard still blocks activation;
|
|
122
|
+
the error identifies that state. `/delegate status` reports the observed Guard state.
|
|
123
|
+
Worker tool restrictions and resource limits are enforced independently of Guard. A worker result
|
|
124
|
+
cannot authorize a write, a commit, a deployment, or an improvement.
|
|
125
|
+
|
|
126
|
+
## Admit a specific purpose
|
|
127
|
+
|
|
128
|
+
| Mode | Required structure | Context and tools |
|
|
129
|
+
| -------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
130
|
+
| `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. |
|
|
131
|
+
| `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. |
|
|
132
|
+
|
|
133
|
+
The packet declares one benefit: `independent_review` for review jobs, or
|
|
134
|
+
`parallel_analysis` / `context_isolation` for scout jobs. It includes a nonempty `why`.
|
|
135
|
+
`parallel_analysis` also requires useful `parentWork`; this may be empty for the other
|
|
136
|
+
benefits. A final review can be useful even when the parent waits. The controller checks
|
|
137
|
+
this structure, not whether the claimed benefit will materialize. Duplicate questions
|
|
138
|
+
after trimming and case normalization are rejected; distinct text is not proof of
|
|
139
|
+
independent work.
|
|
140
|
+
|
|
141
|
+
Each job names its assigned global requirement IDs and receives only those requirements,
|
|
142
|
+
plus the fixed decisions and non-goals. Transfer original constraints and evidence,
|
|
143
|
+
not the parent's reasoning or verdict. Do not delegate routine lookups, small understood
|
|
144
|
+
edits, coupled mutable work, generic second opinions or repeated role-based answers.
|
|
145
|
+
Use parallel parent tool calls when retrieval alone answers the question.
|
|
146
|
+
|
|
147
|
+
Workers have no shell, writes, arbitrary plugin tools or recursive delegation.
|
|
148
|
+
The parent obtains and selects source material. Model routing, automatic retries,
|
|
149
|
+
live-web access, monetary admission and automatic policy tuning remain unimplemented.
|
|
150
|
+
|
|
151
|
+
`/task` remains optional. Changes to an active task contract invalidate delegation,
|
|
152
|
+
but the parent is still responsible for faithfully transferring the task into the packet.
|
|
153
|
+
|
|
154
|
+
Use `delegate run`, continue useful parent work, then `collect`. Collection can wait
|
|
155
|
+
up to 30 seconds without another model request. Do not poll on a fixed schedule.
|
|
156
|
+
Check the referenced evidence and `resolve` each report, including per-finding
|
|
157
|
+
dispositions. One changed-input `follow_up` is available under the original deadline
|
|
158
|
+
and counters. [Protocol and executable examples](protocol.md) define the exact fields.
|
|
159
|
+
|
|
160
|
+
## Enforced resource envelope
|
|
161
|
+
|
|
162
|
+
| Resource | Ceiling |
|
|
163
|
+
| ------------------------- | ---------------------------------------------------------------------------- |
|
|
164
|
+
| Active worker requests | 2 per Pi process, including cancelled requests still settling |
|
|
165
|
+
| Batches / jobs | 4 batches per Pi process; one unresolved batch; 2 jobs per batch |
|
|
166
|
+
| SDK model invocations | 32 per Pi process, 8 per batch; 4 per logical job including follow-up |
|
|
167
|
+
| Follow-ups / retries | 1 changed-input follow-up per job; provider and session retries disabled |
|
|
168
|
+
| Time | 120 seconds per logical job; 300 seconds per batch, including follow-up time |
|
|
169
|
+
| Packet / child context | 256 KiB, checked before dispatch |
|
|
170
|
+
| Selected sources | 200 files and 8 MiB per batch |
|
|
171
|
+
| Tools | 12 calls and 64 KiB total returned JSON per logical job |
|
|
172
|
+
| Tool response | Bounded reads/search; 16 KiB per snapshot read/search response |
|
|
173
|
+
| Final report | 16 KiB; 8 findings; coverage for each assigned requirement |
|
|
174
|
+
| Requested provider output | 8,192 tokens, clamped to the model maximum |
|
|
175
|
+
| SDK-visible response | 256 KiB acceptance limit on observed response content |
|
|
176
|
+
|
|
177
|
+
These are conservative experiment limits, not empirically optimal values. Each SDK
|
|
178
|
+
invocation is admitted before dispatch. Automatic provider/session retries and
|
|
179
|
+
compaction are disabled, so they cannot silently create another SDK request.
|
|
180
|
+
Pi authentication preflight occurs before the model-invocation counter; these quotas
|
|
181
|
+
do not count or bound Pi's authentication/OAuth preparation.
|
|
182
|
+
|
|
183
|
+
The native SDK stream is observed while the child runs. Its response checks are not
|
|
184
|
+
hard bounds on raw transport, hidden provider attempts, billing or process memory.
|
|
185
|
+
Bytes may already be buffered before an SDK event becomes visible. Stream checks count
|
|
186
|
+
recognized deltas incrementally; full response validation occurs at content/terminal
|
|
187
|
+
boundaries, before tool execution and before publication. This relies on Pi's parsed
|
|
188
|
+
stream contract, not arbitrary inconsistent partial objects. Cheap lease checks run
|
|
189
|
+
per event; full root, model and provider-policy checks run at protected boundaries.
|
|
190
|
+
The parsed stream allows at most 64 content blocks, 512 structural nodes per partial,
|
|
191
|
+
65,536 events and 130 non-delta boundaries per invocation. These are implementation
|
|
192
|
+
ceilings, not empirically optimal values.
|
|
193
|
+
Cost is unavailable; available token fields are retained even when others are missing.
|
|
194
|
+
Never-reported fields are `null`, and per-field `usageReportedCalls` distinguishes
|
|
195
|
+
partial totals from complete accounting. This version cannot satisfy a policy
|
|
196
|
+
requiring those unsupported guarantees.
|
|
197
|
+
|
|
198
|
+
Cancellation revokes broker access and requests SDK abort. Slots remain held through
|
|
199
|
+
SDK-visible stream/result and prompt settlement; that does not prove physical remote
|
|
200
|
+
execution has ended. Late content is discarded. A non-cooperative SDK/provider can
|
|
201
|
+
require ending Pi; a timeout does not launch a replacement behind its back. Completed
|
|
202
|
+
reports keep their original source bindings after the deadline, but child sessions are
|
|
203
|
+
released at the deadline and later follow-up is rejected.
|
|
204
|
+
|
|
205
|
+
## Evidence and retention
|
|
206
|
+
|
|
207
|
+
Snapshots contain only exact selected regular text files under the fixed canonical
|
|
208
|
+
working root of the Pi process. The broker rejects traversal, symlinks/junctions,
|
|
209
|
+
hardlinks, binary content, private path
|
|
210
|
+
names, unknown source IDs, and oversized reads. Each worker can search only its own
|
|
211
|
+
selection. Capture verifies content digests. Each tool call checks canonical paths,
|
|
212
|
+
file identity and change metadata against the immutable capture, without rereading
|
|
213
|
+
all selected bytes. Publication, collection, follow-up and disposition also recheck
|
|
214
|
+
content digests. Changed source bindings require a fresh batch. A content change that
|
|
215
|
+
evades filesystem metadata is detected at the next digest check, not by each tool call.
|
|
216
|
+
|
|
217
|
+
This is a trusted-local-filesystem contract, not an operating-system sandbox or an
|
|
218
|
+
atomic filesystem snapshot. Filename restrictions cannot detect secrets embedded in
|
|
219
|
+
an ordinary source file. The parent must select appropriate material for the configured
|
|
220
|
+
model provider. Trusted Pi extensions remain privileged in the shared process despite
|
|
221
|
+
being absent from the child's resource loader. Only the submitted packet is inherited
|
|
222
|
+
automatically, not the parent transcript.
|
|
223
|
+
|
|
224
|
+
Each report separates worker claims from a host receipt: job/attempt identity, packet
|
|
225
|
+
digest, generation, result revision, route, state, counters and usage completeness.
|
|
226
|
+
Source references are validated for identity and line range; their truth is still a
|
|
227
|
+
verification question for the parent. `accept` records a parent assessment, not human
|
|
228
|
+
approval or verified task completion.
|
|
229
|
+
|
|
230
|
+
Child conversations use in-memory sessions. A final disposition, cancellation, exhausted
|
|
231
|
+
follow-up or original deadline releases the child; active SDK work retains its slot until
|
|
232
|
+
settlement. Teardown failures do not escape into Pi's event loop. Shared snapshot text
|
|
233
|
+
is destroyed once no job can continue, including failed jobs at their original deadline.
|
|
234
|
+
Packet and job-input references are dropped when owned workers settle. Source metadata
|
|
235
|
+
and digests still validate completed reports after text is destroyed. Starting the next
|
|
236
|
+
accepted batch retires the previous batch's reports; invalidation retires old generations
|
|
237
|
+
after their workers settle. Retired batches cannot be collected or followed up.
|
|
238
|
+
Only bounded state summaries, quota counters and the idempotency journal remain for
|
|
239
|
+
the Pi process lifetime, including `/reload` and session switches. They cannot recreate
|
|
240
|
+
retired work. SDK setup errors are replaced with generic diagnostics before reaching
|
|
241
|
+
status, command notices or model-facing errors; code-owned policy errors stay specific.
|
|
242
|
+
There is no child session database, raw metrics log,
|
|
243
|
+
credential copy, automatic resume, or secure memory-erasure claim. Normal Pi parent
|
|
244
|
+
tool results may be retained in its ordinary session. Turning delegation off does not
|
|
245
|
+
remove results already retained by Pi; review the session before sharing it.
|
|
246
|
+
|
|
247
|
+
## Implementation and evaluation
|
|
248
|
+
|
|
249
|
+
The modules under `extensions/delegation/` integrate Pi AgentSession with admission,
|
|
250
|
+
snapshot tools and closed result validation. There are no additional runtime dependencies
|
|
251
|
+
or separate host process. Compatibility requires verification against the supported
|
|
252
|
+
Pi SDK and ordinary package discovery, not merely a passing mock provider.
|
|
253
|
+
|
|
254
|
+
The evaluation plan separates deterministic runtime/security fixtures from comparative
|
|
255
|
+
task outcomes. Use isolated state and synthetic providers for contract tests; live
|
|
256
|
+
inference needs separate authorization. Such fixtures do not establish parity with
|
|
257
|
+
the parent's full inference pipeline or every production provider.
|
|
258
|
+
|
|
259
|
+
The [evaluation plan](evaluation.md) compares selective delegation with strong single
|
|
260
|
+
agents, serial workflows and always-delegate baselines using matched resource budgets.
|
|
261
|
+
No production quality, speed or cost improvement is claimed until those experiments run.
|
|
262
|
+
The [original design](design.md) and [target protocol](design-protocol.md) preserve the
|
|
263
|
+
broader proposal and its currently unimplemented proof obligations. The implemented
|
|
264
|
+
[calls/time protocol](protocol.md) is the source of truth for this release's behavior.
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# Delegation protocol: archived version 1 target proposal
|
|
2
|
+
|
|
3
|
+
This is the original target design contract, not the implemented API. The normative
|
|
4
|
+
words **must** and **must not** specify requirements for that stronger future contract.
|
|
5
|
+
Use the [implemented calls/time protocol](protocol.md) and [guide](README.md) for the
|
|
6
|
+
current experimental interface. It does not supply this proposal's hard raw-transport,
|
|
7
|
+
per-provider-attempt or monetary admission guarantees, live web adapter, or alternative
|
|
8
|
+
model routes. The schemas and command examples below must not be submitted as if they
|
|
9
|
+
were the implemented protocol.
|
|
10
|
+
|
|
11
|
+
The current `bounded-pi-sessions-v1` implementation checks public SDK capabilities and uses actual Pi AgentSession workers,
|
|
12
|
+
fresh standard ModelRuntime configuration, explicit parent model/thinking and SDK-visible
|
|
13
|
+
streaming. It does not claim full parent-hook/ephemeral-setting inheritance or hard
|
|
14
|
+
raw-transport, hidden-attempt or invoice limits. It admits only `review` and `scout`,
|
|
15
|
+
with assigned requirement subsets. Its controller survives reloads; the implemented
|
|
16
|
+
guide specifies restart, fixed-root and SDK-settlement boundaries. The custom loop,
|
|
17
|
+
four-profile schema and stronger port contracts below remain historical proposals.
|
|
18
|
+
|
|
19
|
+
See the [archived architecture](design.md) for target policy and
|
|
20
|
+
[evaluation](evaluation.md) for the distinction between current fixtures and unmet
|
|
21
|
+
proof obligations.
|
|
22
|
+
|
|
23
|
+
## 1. Authority and ownership
|
|
24
|
+
|
|
25
|
+
Separate three objects:
|
|
26
|
+
|
|
27
|
+
1. **Request:** a parent-model proposal. All fields are untrusted and can only request
|
|
28
|
+
capabilities already granted by the human.
|
|
29
|
+
2. **Envelope:** a host-created record binding a validated request to identities,
|
|
30
|
+
permissions, sources and resource reservations. A model cannot replace its fields.
|
|
31
|
+
3. **Result:** a worker's claims plus separately generated host observations. Worker
|
|
32
|
+
prose cannot manufacture host observations or acceptance.
|
|
33
|
+
|
|
34
|
+
Use closed schemas, explicit version numbers, bounded strings and arrays, and rejection
|
|
35
|
+
of unknown fields. Validate input before dispatch and output before collection. This
|
|
36
|
+
is an in-process protocol with structured objects; no HTTP listener, RPC server, or
|
|
37
|
+
message serialization framework is required.
|
|
38
|
+
|
|
39
|
+
## 2. Parent request
|
|
40
|
+
|
|
41
|
+
One tool named `delegate` accepts this discriminated union:
|
|
42
|
+
|
|
43
|
+
| Operation | Required input | Outcome |
|
|
44
|
+
| ----------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
45
|
+
| `run` | Objective, job proposals, selected input references, requested limits | Admit one batch; return IDs and effective limits, or a deterministic rejection |
|
|
46
|
+
| `status` | Batch ID | Compact states, coverage counts, usage and accounting availability |
|
|
47
|
+
| `collect` | Batch ID, optional job IDs, acknowledged revision cursor and bounded wait | Return applicable payloads after the caller's acknowledged cursor; no destructive dequeue |
|
|
48
|
+
| `follow_up` | Existing job/result binding, correction or new evidence, idempotency key | Admit one additional attempt under the original job limits and deadline |
|
|
49
|
+
| `resolve` | Exact result binding, disposition and per-finding decisions, idempotency key | Record parent adjudication; never authorize a new action |
|
|
50
|
+
| `cancel` | Batch or job ID | Revoke admission and request cancellation; report requests still settling |
|
|
51
|
+
|
|
52
|
+
For stage 1, the single review call may finish within `run`; it uses the same envelope
|
|
53
|
+
and result schema. Stage 2 adds asynchronous return without changing the result contract.
|
|
54
|
+
`collect` can wait at most 30 seconds; it does not create polling timers or new model
|
|
55
|
+
turns. Collect immediately before consuming the relevant evidence, not on a fixed loop.
|
|
56
|
+
|
|
57
|
+
`collect` returns a revision cursor without advancing the caller's acknowledgment.
|
|
58
|
+
Only the next request's explicit cursor acknowledges receipt. Repeating the old cursor
|
|
59
|
+
returns the same applicable payload, so a response lost before consumption can be
|
|
60
|
+
recovered. Results remain available within bounded session retention until resolved,
|
|
61
|
+
discarded or explicitly expired; advertise any expiration rather than silently
|
|
62
|
+
returning an empty successful result.
|
|
63
|
+
|
|
64
|
+
`follow_up` requires `batchId`, `jobId`, `attemptId`, `packetDigest`, `resultRevision`,
|
|
65
|
+
`taskGeneration`, and an idempotency key. It is admitted only from `incomplete` with an
|
|
66
|
+
explicit context gap, or `invalid` with a correctable format error. The controller
|
|
67
|
+
validates that the correction addresses that outcome, that prior provider resources
|
|
68
|
+
have settled, and that the original task/policy bindings, deadline and counters permit
|
|
69
|
+
another attempt. Authority and new source grants are rechecked. An atomic transition
|
|
70
|
+
records the new immutable attempt and debits the **existing** job, batch and session
|
|
71
|
+
ledgers. It does not create another batch or refresh the deadline. The same idempotency
|
|
72
|
+
key and payload return the existing outcome; reuse with a different payload is rejected.
|
|
73
|
+
|
|
74
|
+
Transient transport retries are controller-owned attempts under the same job, not a
|
|
75
|
+
parent `follow_up`. Cancelled, expired, stale, accepted and discarded jobs cannot be
|
|
76
|
+
revived through this operation. A materially new task requires a new admission and
|
|
77
|
+
still consumes the existing session allowance. A renamed request does not authorize
|
|
78
|
+
automatic recovery of a cancelled job.
|
|
79
|
+
|
|
80
|
+
`resolve` binds to those same exact result identity fields and includes a disposition
|
|
81
|
+
(`accept`, `discard`, or `needs_check`) plus decisions for every presented finding
|
|
82
|
+
(`confirmed`, `rejected`, or `needs_check`, with reasons and evidence IDs). The host
|
|
83
|
+
rejects stale revisions and mismatched task generations. An accepted result must have
|
|
84
|
+
required coverage and no unresolved material finding. Accepting a review report means
|
|
85
|
+
its evidence has been adjudicated; it does not assert that the code is ready or that
|
|
86
|
+
confirmed defects have been fixed. Incomplete, invalid and failed results can be
|
|
87
|
+
discarded or held for investigation but cannot be accepted as complete. Apply each
|
|
88
|
+
idempotent resolution atomically. Host state does not infer acceptance from prose,
|
|
89
|
+
collection, silence, or a worker verdict. Finding decisions remain separate from the
|
|
90
|
+
overall disposition. Ordinary task completion still follows SpecPi's existing gates.
|
|
91
|
+
|
|
92
|
+
Proposed request example:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"version": 1,
|
|
97
|
+
"op": "run",
|
|
98
|
+
"objective": "Resolve two independent causes of the observed regression",
|
|
99
|
+
"jobs": [
|
|
100
|
+
{
|
|
101
|
+
"key": "cache-invalidation",
|
|
102
|
+
"mode": "investigate",
|
|
103
|
+
"question": "Can the cache retain a value after its source changes?",
|
|
104
|
+
"requirements": ["R1"],
|
|
105
|
+
"sourceIds": ["src-cache", "src-cache-callers", "src-cache-tests"],
|
|
106
|
+
"acceptance": "Identify the relevant path and evidence, or state what prevents a conclusion.",
|
|
107
|
+
"decisions": ["Public cache API behavior must remain compatible."],
|
|
108
|
+
"nonGoals": ["Implementing a fix", "Changing public API behavior"],
|
|
109
|
+
"independence": "The parent is separately investigating event ordering.",
|
|
110
|
+
"parentAlternative": "Read these same sources sequentially in the parent.",
|
|
111
|
+
"reason": "A substantial independent source investigation can run while event ordering is inspected."
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"limits": {
|
|
115
|
+
"maxRequests": 4,
|
|
116
|
+
"deadlineMs": 120000
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Source IDs must already refer to a host-validated manifest prepared under the session
|
|
122
|
+
grant. The model does not create that manifest by inventing IDs. A repository capture
|
|
123
|
+
interface validates requested paths before issuing IDs. User-provided attachments or
|
|
124
|
+
parent-selected excerpts get explicit provenance distinct from broker observations.
|
|
125
|
+
|
|
126
|
+
The example's acceptance criteria permit an honest unknown. An instruction to prove a
|
|
127
|
+
preferred conclusion is not an acceptable evidence task.
|
|
128
|
+
|
|
129
|
+
## 3. Host envelope
|
|
130
|
+
|
|
131
|
+
| Field | Meaning |
|
|
132
|
+
| ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
133
|
+
| `version` | Protocol version; reject unsupported versions |
|
|
134
|
+
| `batchId`, `jobId`, `attemptId` | Host-generated opaque identities |
|
|
135
|
+
| `policyGeneration` | Immutable human policy and capability selection |
|
|
136
|
+
| `taskGeneration` | Active task identity, requirement revision, scope grant and session epoch |
|
|
137
|
+
| `taskBinding` | Exact card digest and requirement IDs, or an explicit ephemeral requirement set |
|
|
138
|
+
| `packetDigest` | SHA-256 of canonical packet content and selected source manifest |
|
|
139
|
+
| `modelRoute` | Bound model and effective configuration identity; no secrets or raw authorization headers |
|
|
140
|
+
| `capabilities` | Closed broker operations and source/network grants |
|
|
141
|
+
| `limits` | Effective job and batch reservations, deadlines and output limits |
|
|
142
|
+
| `question`, `acceptance`, `decisions`, `nonGoals` | Validated task content |
|
|
143
|
+
| `sources` | Opaque IDs, hashes, media type, coverage, captured location and provenance |
|
|
144
|
+
| `priorAttempt` | Optional parent-approved correction or additional evidence from the same logical job |
|
|
145
|
+
|
|
146
|
+
Canonical serialization must define UTF-8 encoding, key ordering, numeric handling and
|
|
147
|
+
array order. Hash the exact bytes supplied to a worker, including explicit omitted or
|
|
148
|
+
unavailable inputs. A digest detects accidental drift; it is not a signature or proof
|
|
149
|
+
against a compromised host extension. Do not expose reversible configuration secrets
|
|
150
|
+
through fingerprints; use a host-owned opaque generation for sensitive configuration.
|
|
151
|
+
|
|
152
|
+
Fresh context contains the task contract, mode instructions, admitted tools and source
|
|
153
|
+
references. Tool outputs are appended as data. A webpage or source comment cannot
|
|
154
|
+
alter the envelope by resembling its JSON syntax.
|
|
155
|
+
|
|
156
|
+
## 4. Evidence references
|
|
157
|
+
|
|
158
|
+
Every accepted reference resolves through a host-managed evidence table:
|
|
159
|
+
|
|
160
|
+
| Kind | Required binding | Limit of the evidence |
|
|
161
|
+
| ------------------ | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
162
|
+
| Snapshot source | Source ID, exact hash, one-based line or byte range | Supports claims about captured bytes only |
|
|
163
|
+
| Public source | Fetch receipt, final URL, retrieval time, source date when available, extracted range and hash | Retrieval does not establish factual correctness |
|
|
164
|
+
| Parent observation | Receipt ID, origin, observed result, bound source generation when relevant | A parent-authored description is not an independently executed check |
|
|
165
|
+
| Host check receipt | Fixed validator identity, actual outcome, environment/source binding | Valid only for the recorded check and inputs |
|
|
166
|
+
|
|
167
|
+
The worker can cite a receipt ID it received; it cannot register an observation as if
|
|
168
|
+
the host executed it. The host rejects nonexistent IDs, impossible ranges, wrong
|
|
169
|
+
hashes and references outside the grant. Mark exact quotations separately from
|
|
170
|
+
paraphrase or inference. Preserve relevant source-version distinctions.
|
|
171
|
+
|
|
172
|
+
Source text may include malicious instructions. The broker supplies it as bounded tool
|
|
173
|
+
data. The model-facing worker has no tool for shell execution, filesystem mutation,
|
|
174
|
+
credential lookup, delegation, persistent memory, or capability expansion. This is a
|
|
175
|
+
closed tool interface under a trusted process, not a claim of perfect prompt-injection
|
|
176
|
+
resistance or OS containment.
|
|
177
|
+
|
|
178
|
+
## 5. Worker result and host receipt
|
|
179
|
+
|
|
180
|
+
The worker returns:
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
status: complete | partial | needs_context
|
|
184
|
+
answer: bounded answer to the assigned question
|
|
185
|
+
coverage[]:
|
|
186
|
+
requirementId, covered | uncovered | not_applicable, explanation, evidenceIds[]
|
|
187
|
+
findings[]:
|
|
188
|
+
findingId, claim, trigger, consequence,
|
|
189
|
+
observed | inferred | unverified,
|
|
190
|
+
evidenceIds[], contraryEvidenceIds[], limitations
|
|
191
|
+
missing[]:
|
|
192
|
+
neededEvidence, affectedConclusion, reason
|
|
193
|
+
suggestedNextStep: optional bounded text, never an executable action
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
For review, add severity based on impact and the affected source location. No confidence
|
|
197
|
+
percentage or aggregate self-score is required. For research, distinguish publication
|
|
198
|
+
status and source date, and include evidence against the proposed conclusion. For
|
|
199
|
+
investigation, report failed hypotheses that affect the answer. For consultation,
|
|
200
|
+
prefer a discriminating next experiment to unsupported certainty.
|
|
201
|
+
|
|
202
|
+
The host separately attaches:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
hostStatus: ready | incomplete | invalid | failed | cancelled | expired | stale
|
|
206
|
+
identity: batchId, jobId, attemptId, packetDigest, taskGeneration, resultRevision
|
|
207
|
+
observations: sourceReceipts[], toolOutcomes[], stopReason
|
|
208
|
+
usage: perRequestRecords[], totals, availabilityByCategory
|
|
209
|
+
responseLimits: rawBytesReceived, parsedBytesRetained, overflow, bufferingBoundVerified
|
|
210
|
+
timing: queuedAt, startedAt, settledAt, elapsedMs
|
|
211
|
+
limits: admitted, consumed, reserved, stillSettling
|
|
212
|
+
validation: schema, references, coverage, generation, truncation
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The collection response separately supplies `collectionCursor`, a batch event position
|
|
216
|
+
used to acknowledge delivery. It is not the job's `resultRevision`: follow-up and
|
|
217
|
+
resolution bind the exact result revision even if a batch cursor advances because a
|
|
218
|
+
different job produces an event.
|
|
219
|
+
|
|
220
|
+
Persist original assistant/tool message structures in the worker's bounded in-memory
|
|
221
|
+
loop as required by the provider, including opaque signatures. Do not fabricate,
|
|
222
|
+
rewrite or transplant provider reasoning blocks. The parent sees the bounded result,
|
|
223
|
+
not hidden chain-of-thought or the entire worker transcript.
|
|
224
|
+
|
|
225
|
+
For usage, separate input, output, cache reads/writes, tool charges and cost. Preserve
|
|
226
|
+
provider category semantics: Pi's output accounting can already include reasoning,
|
|
227
|
+
so adding reasoning a second time would inflate totals. Distinguish known zero from
|
|
228
|
+
missing data and estimated cost from reported cost. A returned error can still have
|
|
229
|
+
billable usage. Include unsuccessful and cancelled attempts.
|
|
230
|
+
|
|
231
|
+
## 6. Lifecycle
|
|
232
|
+
|
|
233
|
+
```mermaid
|
|
234
|
+
stateDiagram-v2
|
|
235
|
+
[*] --> proposed
|
|
236
|
+
proposed --> rejected: admission fails
|
|
237
|
+
proposed --> queued: envelope and reservation created
|
|
238
|
+
queued --> running: capacity available; preconditions rechecked
|
|
239
|
+
queued --> cancelled: grant revoked or user cancels
|
|
240
|
+
running --> ready: complete payload and host validation
|
|
241
|
+
running --> incomplete: partial answer or missing context
|
|
242
|
+
running --> invalid: schema, evidence or truncation error
|
|
243
|
+
running --> failed: provider or broker failure
|
|
244
|
+
running --> cancelled: cancellation
|
|
245
|
+
running --> expired: deadline
|
|
246
|
+
ready --> stale: task or required source binding changes
|
|
247
|
+
ready --> accepted: parent adjudicates
|
|
248
|
+
ready --> discarded: parent rejects result
|
|
249
|
+
incomplete --> discarded
|
|
250
|
+
invalid --> discarded
|
|
251
|
+
failed --> discarded
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The diagram shows logical result state. Resource settlement is tracked separately:
|
|
255
|
+
`reserved`, `in_flight`, `settled`, or `uncertain`. `cancelled` does not assert that the
|
|
256
|
+
provider stopped billing. A cancelled or expired request cannot publish a late result.
|
|
257
|
+
An adapter that ignores cancellation retains its slot as still settling; do not start
|
|
258
|
+
new work under the fiction that no request is running.
|
|
259
|
+
|
|
260
|
+
Review output is accepted against its frozen target. On any relevant source change,
|
|
261
|
+
revalidate or mark it stale before use as completion evidence. Research citations may
|
|
262
|
+
remain informative after an unrelated code edit, but requirement/policy drift always
|
|
263
|
+
requires explicit parent reassessment. Scope determines relevance; a changed unrelated
|
|
264
|
+
file must not invalidate every independent research result.
|
|
265
|
+
|
|
266
|
+
Ordinary advancement of a session leaf is not branch navigation. Use a controller
|
|
267
|
+
epoch changed on actual task/policy navigation, not a rule that invalidates jobs after
|
|
268
|
+
each normal parent tool result. Pi 0.84.4 exposes `session_before_switch`,
|
|
269
|
+
`session_before_fork`, `session_before_tree`, `session_tree`, `session_start`, and
|
|
270
|
+
`session_shutdown`; there is no assumed `session_switch` or `session_fork` after-event.
|
|
271
|
+
Before-events may conservatively cancel work even if navigation is later declined.
|
|
272
|
+
Restarting after that is explicit, never a hidden retry.
|
|
273
|
+
[Pinned lifecycle contracts](https://github.com/earendil-works/pi/blob/v0.84.4/packages/coding-agent/src/core/extensions/types.ts#L522).
|
|
274
|
+
|
|
275
|
+
## 7. Retries, follow-ups, cancellation and deduplication
|
|
276
|
+
|
|
277
|
+
Retry only a classified failure, with its reservation intact. Honor provider backoff
|
|
278
|
+
inside the original deadline. A transport retry after uncertain dispatch can duplicate
|
|
279
|
+
billing; label it accordingly. Do not promise exactly-once provider execution.
|
|
280
|
+
|
|
281
|
+
A `needs_context` follow-up creates a new immutable attempt under the same job ID. It
|
|
282
|
+
includes what changed and why that addresses the gap. The old result remains marked
|
|
283
|
+
incomplete. Call, tool, byte and deadline counters remain attached to the logical job
|
|
284
|
+
and batch; a follow-up cannot reset them. Limit it to one generation initially.
|
|
285
|
+
|
|
286
|
+
Deduplicate only exact active equivalents: same task and policy generation, mode,
|
|
287
|
+
question/acceptance contract, source hashes, model route and relevant settings. Return
|
|
288
|
+
the existing job identity for a repeated request. Do not infer that semantically similar
|
|
289
|
+
questions are equivalent. Cross-session result reuse is out of scope.
|
|
290
|
+
|
|
291
|
+
Cancellation must revoke broker access before awaiting provider settlement. Combine
|
|
292
|
+
the parent signal with job and batch deadlines. Recheck revocation and counters before
|
|
293
|
+
every complete tool invocation and model request. Partial streamed tool arguments are
|
|
294
|
+
never executable. Check terminal `stopReason` as well as rejected promises: Pi streams
|
|
295
|
+
can resolve an assistant message with `error` or `aborted` status. The scheduler's own
|
|
296
|
+
abort state remains authoritative when setup errors obscure cancellation.
|
|
297
|
+
|
|
298
|
+
## 8. Scheduling and provider interface
|
|
299
|
+
|
|
300
|
+
The following pseudocode expresses ordering, not an available Pi API:
|
|
301
|
+
|
|
302
|
+
```text
|
|
303
|
+
admit(request):
|
|
304
|
+
validate closed request and current human policy
|
|
305
|
+
bind immutable task, source and model generation
|
|
306
|
+
check exact deduplication key
|
|
307
|
+
reserve batch capacity atomically
|
|
308
|
+
enqueue only ready independent jobs
|
|
309
|
+
|
|
310
|
+
run(job):
|
|
311
|
+
acquire concurrency slot
|
|
312
|
+
recheck authority, generation, deadline and source binding
|
|
313
|
+
build explicit child context and broker schemas
|
|
314
|
+
while another request is allowed:
|
|
315
|
+
reserve next request before dispatch
|
|
316
|
+
response = InferencePort.request(context, admittedOptions, signal,
|
|
317
|
+
admissionBeforeEveryUnderlyingAttempt, rawByteLimit)
|
|
318
|
+
account for response, terminal status and uncertainty
|
|
319
|
+
reject incomplete tool calls or oversized messages
|
|
320
|
+
if final result: validate and stop
|
|
321
|
+
for each complete tool call in this response:
|
|
322
|
+
recheck grant, counters and cancellation
|
|
323
|
+
execute through EvidencePort; append bounded tool result
|
|
324
|
+
settle or quarantine outstanding resources
|
|
325
|
+
publish only if the job generation remains valid
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`InferencePort` and `EvidencePort` are proposed injected interfaces. The former must
|
|
329
|
+
be host-owned and preserve request-policy behavior; the latter is the closed broker.
|
|
330
|
+
The Pi 0.84.4 public registry completion facade is insufficient to claim full host
|
|
331
|
+
pipeline parity. [Target architecture compatibility gate](design.md#8-pi-runtime-and-package-boundary).
|
|
332
|
+
|
|
333
|
+
Each underlying inference attempt, including an internal SDK retry, must obtain a
|
|
334
|
+
controller reservation immediately before dispatch. Disable opaque retries when the
|
|
335
|
+
adapter cannot call this admission hook. Initial dispatch and each admitted retry get
|
|
336
|
+
separate attempt receipts; admission must not debit the initial attempt twice. The
|
|
337
|
+
same retry classifier, job retry count, deadlines, provider backoff and batch/session
|
|
338
|
+
ledgers apply. If the adapter cannot enforce this boundary, it cannot claim hard
|
|
339
|
+
attempt limits and must be rejected for the default policy. Silent provider fallback
|
|
340
|
+
to another model is also forbidden.
|
|
341
|
+
|
|
342
|
+
The port's raw-byte ceiling covers the entire decoded application response, including
|
|
343
|
+
stream framing, tool arguments, thinking, text and metadata, across bounded chunks.
|
|
344
|
+
Also bound decompression and transport buffering before handing bytes to a parser;
|
|
345
|
+
reject adapters with opaque unbounded buffering. Stop accumulating and signal abort
|
|
346
|
+
as soon as the next chunk would exceed the allowance. Do not parse or append the
|
|
347
|
+
oversized content, and do not truncate it into an apparently valid final object.
|
|
348
|
+
Record overflow and keep uncertain billing and non-cooperative requests in settlement
|
|
349
|
+
tracking. The byte bound is not a guarantee about provider-side generation or billing.
|
|
350
|
+
|
|
351
|
+
For asynchronous work, the host issues a job-lifetime lease containing immutable
|
|
352
|
+
admitted route data and cancellation hooks. Do not retain a stale invocation-scoped
|
|
353
|
+
extension context after `run` returns. The lease is revoked by actual task/policy
|
|
354
|
+
invalidation, user cancellation, shutdown or deadline; a normal parent tool return
|
|
355
|
+
must not accidentally expire it. Its lifetime and hook behavior are part of the
|
|
356
|
+
proposed host bridge, to be proven by integration fixtures.
|
|
357
|
+
|
|
358
|
+
Serialize tool calls within one worker initially. Parallelism is across admitted jobs.
|
|
359
|
+
If `pi-agent-core` is used to preserve message protocol correctness, explicitly configure
|
|
360
|
+
its tool execution policy; its default is parallel. Limits require pre-call enforcement,
|
|
361
|
+
not only `shouldStopAfterTurn`, which is evaluated after work already occurred.
|
|
362
|
+
|
|
363
|
+
No automatic sibling steering is necessary. If a finding invalidates another job's
|
|
364
|
+
premise, the parent cancels that job and submits an explicitly revised contract, charging
|
|
365
|
+
all abandoned work to the same evaluated task.
|
|
366
|
+
|
|
367
|
+
All batches also debit the session allowance. Starting another batch, changing an
|
|
368
|
+
ephemeral requirement set, or toggling the tool cannot reset consumed usage. A human
|
|
369
|
+
policy change must explicitly renew an exhausted allowance; it cannot erase the
|
|
370
|
+
reported cost of prior work.
|
|
371
|
+
|
|
372
|
+
## 9. Protocol acceptance tests
|
|
373
|
+
|
|
374
|
+
Before a real provider is enabled, fixtures must demonstrate rejection of forged host
|
|
375
|
+
fields, unsupported versions, oversized or truncated output, nonexistent source IDs,
|
|
376
|
+
stale revisions, duplicate results, recursive delegation, denied tools and exhausted
|
|
377
|
+
reservations. Race tests must cover simultaneous admission, cancellation between a tool
|
|
378
|
+
decision and execution, and late results after task navigation.
|
|
379
|
+
|
|
380
|
+
A valid schema is only the beginning. An answer with valid references can still be
|
|
381
|
+
wrong. Parent adjudication and actual task checks are required for acceptance; a
|
|
382
|
+
protocol receipt must never be displayed as proof that the task itself is correct.
|