pi-delegation-policy 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 +16 -0
- package/README.md +6 -4
- package/SECURITY.md +2 -2
- package/package.json +1 -1
- package/src/agent-launch.ts +39 -7
- package/src/context-shunt-executor.ts +1 -1
- package/src/prompt.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.0 - 2026-10-08
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Restore the ContextShunt reader with `pi-subagents` `0.76.1`. The reader accepts only that build's launch contract: the packaged profile, the prompt runtime as its only extension, no inherited global context, no required child extensions, and the child's Intercom bridge off. Any other build fails closed with `reader-unavailable` before a request is sent.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Ask the main agent not to paste workflow scripts, child briefs, or other internal orchestration material into the chat. Scripts stay in private files and are launched by path. The instruction applies to normal, aggressive, and orchestrator intensities; delegation off still injects nothing.
|
|
12
|
+
|
|
13
|
+
### Compatibility and limits
|
|
14
|
+
|
|
15
|
+
- Breaking for the reader: `pi-subagents` `0.69.0` no longer works with it and returns `reader-unavailable`. Upgrade the external executor to `0.76.1`. The extension's Pi minimum, `0.87.1`, is unchanged.
|
|
16
|
+
- Verified only on Pi `1.1.0` with `pi-subagents` `0.76.1`, in an offline loopback harness with a synthetic provider. Pi `0.87.1` is not verified for the reader, and no real provider was used.
|
|
17
|
+
- A child that loads a permission extension is rejected, so the reader returns `reader-unavailable`. This path was not exercised with pi-subagents permission rules.
|
|
18
|
+
|
|
3
19
|
## 0.17.0 - 2026-10-07
|
|
4
20
|
|
|
5
21
|
### Added
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ models to use for Small, Medium, Large, and the optional Visual Design and Advis
|
|
|
5
5
|
subagent runner: it never routes, supervises, or collects the results of delegated work.
|
|
6
6
|
|
|
7
7
|
> **Docs:** [yivas.github.io/pi-delegation-policy](https://yivas.github.io/pi-delegation-policy/).
|
|
8
|
-
> Version **0.
|
|
8
|
+
> Version **0.18.0** requires Pi `0.87.1` or later (`>=0.87.1`); it re-applies its marked policy block in the final provider payload.
|
|
9
9
|
> Version `0.14.1` supports Pi `0.84.3` or later (`>=0.84.3`).
|
|
10
10
|
>
|
|
11
11
|
> Independent Advisor mode and its companion file are available from version `0.17.0`.
|
|
@@ -14,7 +14,7 @@ subagent runner: it never routes, supervises, or collects the results of delegat
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
pi install npm:pi-delegation-policy@0.
|
|
17
|
+
pi install npm:pi-delegation-policy@0.18.0
|
|
18
18
|
# restart Pi, or run /reload
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -163,8 +163,10 @@ one bounded line or byte range. Errors, structured results, images, binaries, mi
|
|
|
163
163
|
unknown tool contracts stay unchanged, and nothing is launched from a hook. The reader keys
|
|
164
164
|
`readerEnabled`, `readerRole`, and `answerMaxBytes` control the optional
|
|
165
165
|
`context_shunt_delegate`/`context_shunt_recover` pair, which needs `enforce`, an active delegation
|
|
166
|
-
intensity, a valid configuration, and a compatible external executor
|
|
167
|
-
|
|
166
|
+
intensity, a valid configuration, and a compatible external executor. The only verified executor is
|
|
167
|
+
`pi-subagents` `0.76.1` on Pi `1.1.0`; Pi `0.87.1`, the declared minimum, is not verified for the
|
|
168
|
+
reader. Other executor builds, including `0.69.0`, fail closed with `reader-unavailable`. Delegation
|
|
169
|
+
`off` suspends the layer.
|
|
168
170
|
|
|
169
171
|
The [limits and privacy reference](https://yivas.github.io/pi-delegation-policy/limits-and-privacy/)
|
|
170
172
|
states the caps, the answer contract, and what one request sends.
|
package/SECURITY.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Scope
|
|
4
4
|
|
|
5
|
-
This project is a local Pi extension. It stores delegation policy data, model identifiers, and any configured per-role thinking policy in global defaults and session entries; it does not store the thinking level chosen for an individual run. ContextShunt is off by default. When explicitly enforced, it may keep a known successful text result in a private, session-only temporary file to serve bounded recovery; the file has an opaque ID, quota, cancellation check, and an absolute 30-minute TTL from creation. Cleanup is scheduled while the process is active and runs at shutdown, but crashes or OS suspension can delay deletion. It does not store credentials and makes no network request of its own; when one of its explicit tools asks an external executor to answer a bounded question, that executor performs the call.
|
|
5
|
+
This project is a local Pi extension. It stores delegation policy data, model identifiers, and any configured per-role thinking policy in global defaults and session entries; it does not store the thinking level chosen for an individual run. ContextShunt is off by default. When explicitly enforced, it may keep a known successful text result in a private, session-only temporary file to serve bounded recovery; the file has an opaque ID, quota, cancellation check, and an absolute 30-minute TTL from creation. Cleanup is scheduled while the process is active and runs at shutdown, but crashes or OS suspension can delay deletion. It does not store credentials and makes no network request of its own; when one of its explicit tools asks an external executor to answer a bounded question, that executor performs the call. The reader accepts only the verified `pi-subagents` 0.76.1 launch contract; any other build fails closed before a request is sent.
|
|
6
6
|
|
|
7
7
|
ContextShunt is not a sandbox or a worker bridge. It preserves permissions and backends, does not inspect files before tool authorization, and leaves errors, structured/mixed results, images, binaries, invalid inputs, and unknown contracts unchanged. One-time exceptions are user-authorized, short-lived, bound to one call and immutable input snapshot, and capped by declared lines plus real returned UTF-8 bytes. The policy guides the main agent. It cannot guarantee that another system will follow a configured role or thinking choice. Review local configuration before using it.
|
|
8
8
|
|
|
@@ -20,4 +20,4 @@ Include the affected version or commit, operating system, Pi version, reproducti
|
|
|
20
20
|
|
|
21
21
|
## Supported versions
|
|
22
22
|
|
|
23
|
-
Only the latest published version is supported. Version `0.
|
|
23
|
+
Only the latest published version is supported. Version `0.18.0` requires Pi `0.87.1` or later; version `0.14.1` requires Pi `0.84.3` or later.
|
package/package.json
CHANGED
package/src/agent-launch.ts
CHANGED
|
@@ -5,7 +5,7 @@ export const LAUNCH_PREFLIGHT_TIMEOUT_MS = 5_000;
|
|
|
5
5
|
export const LAUNCH_TERMINAL_TIMEOUT_MS = 120_000;
|
|
6
6
|
|
|
7
7
|
const PACKAGE_NAME = "pi-delegation-policy";
|
|
8
|
-
/** `pi-subagents` 0.
|
|
8
|
+
/** `pi-subagents` 0.76.1 `src/api/preflight.ts` and `src/shared/launch-contract.ts`. */
|
|
9
9
|
const LAUNCH_CONTRACT_VERSION = 3;
|
|
10
10
|
const DEFINITION_PROJECTION_VERSION = 2;
|
|
11
11
|
const SHA256_LOWER_HEX = /^[0-9a-f]{64}$/;
|
|
@@ -48,6 +48,11 @@ export type AgentLaunchPreflight = (input: unknown) => Promise<unknown>;
|
|
|
48
48
|
|
|
49
49
|
export type AgentLaunchModules = Readonly<{
|
|
50
50
|
resolveSubagentLaunchContract: AgentLaunchPreflight;
|
|
51
|
+
/**
|
|
52
|
+
* Runtime extension paths that `pi-subagents` gives a profile with no tools and no extensions.
|
|
53
|
+
* The contract must report exactly these, so a relabeled or added extension fails closed.
|
|
54
|
+
*/
|
|
55
|
+
profileRuntimeExtensions: () => readonly string[];
|
|
51
56
|
requestEvent: string;
|
|
52
57
|
startedEvent: string;
|
|
53
58
|
responseEvent: string;
|
|
@@ -165,16 +170,24 @@ export function createDefaultAgentLaunchLoader(
|
|
|
165
170
|
loadModule: DynamicModuleLoader = (specifier) => import(specifier),
|
|
166
171
|
): () => Promise<AgentLaunchModules | undefined> {
|
|
167
172
|
return () =>
|
|
168
|
-
Promise.all([
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
Promise.all([
|
|
174
|
+
loadModule("pi-subagents/preflight"),
|
|
175
|
+
loadModule("pi-subagents/delegation"),
|
|
176
|
+
loadModule("pi-subagents/child-tool-plan"),
|
|
177
|
+
])
|
|
178
|
+
.then(([preflight, delegation, childToolPlan]) => {
|
|
179
|
+
if (!isRecord(preflight) || !isRecord(delegation) || !isRecord(childToolPlan)) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
171
182
|
const resolveLaunchContract = preflight.resolveSubagentLaunchContract;
|
|
183
|
+
const resolvePiLaunchToolPlan = childToolPlan.resolvePiLaunchToolPlan;
|
|
172
184
|
const requestEvent = delegation.SUBAGENT_DELEGATION_REQUEST_EVENT;
|
|
173
185
|
const startedEvent = delegation.SUBAGENT_DELEGATION_STARTED_EVENT;
|
|
174
186
|
const responseEvent = delegation.SUBAGENT_DELEGATION_RESPONSE_EVENT;
|
|
175
187
|
const cancelEvent = delegation.SUBAGENT_DELEGATION_CANCEL_EVENT;
|
|
176
188
|
if (
|
|
177
189
|
typeof resolveLaunchContract !== "function" ||
|
|
190
|
+
typeof resolvePiLaunchToolPlan !== "function" ||
|
|
178
191
|
requestEvent !== DELEGATION_EVENTS.request ||
|
|
179
192
|
startedEvent !== DELEGATION_EVENTS.started ||
|
|
180
193
|
responseEvent !== DELEGATION_EVENTS.response ||
|
|
@@ -184,8 +197,18 @@ export function createDefaultAgentLaunchLoader(
|
|
|
184
197
|
}
|
|
185
198
|
const resolveSubagentLaunchContract: AgentLaunchPreflight = async (input) =>
|
|
186
199
|
resolveLaunchContract(input);
|
|
200
|
+
// The same public resolver the child launch uses, given the profile's own inputs. Its
|
|
201
|
+
// runtime list depends only on the installed package unless permissions, fast mode or
|
|
202
|
+
// fanout are requested, and the profile requests none of them.
|
|
203
|
+
const profileRuntimeExtensions = (): readonly string[] =>
|
|
204
|
+
resolvePiLaunchToolPlan({
|
|
205
|
+
tools: [],
|
|
206
|
+
extensions: [],
|
|
207
|
+
structuredOutput: true,
|
|
208
|
+
}).runtimeExtensions;
|
|
187
209
|
return {
|
|
188
210
|
resolveSubagentLaunchContract,
|
|
211
|
+
profileRuntimeExtensions,
|
|
189
212
|
requestEvent,
|
|
190
213
|
startedEvent,
|
|
191
214
|
responseEvent,
|
|
@@ -216,6 +239,7 @@ function createPreflightInput<Request extends AgentLaunchRequest, Value>(
|
|
|
216
239
|
...(definition.result.variant === "structured"
|
|
217
240
|
? { outputSchema: definition.result.buildSchema(request) }
|
|
218
241
|
: {}),
|
|
242
|
+
intercomBridge: { mode: "off" },
|
|
219
243
|
skill: false,
|
|
220
244
|
runId: requestId,
|
|
221
245
|
};
|
|
@@ -226,6 +250,7 @@ function validateLaunchContract<Request extends AgentLaunchRequest, Value>(
|
|
|
226
250
|
request: Request,
|
|
227
251
|
active: Pick<ActiveRun<Value>, "requestId" | "host">,
|
|
228
252
|
definition: AgentLaunchDefinition<Request, Value>,
|
|
253
|
+
modules: AgentLaunchModules,
|
|
229
254
|
): value is AgentLaunchContract {
|
|
230
255
|
try {
|
|
231
256
|
if (!isRecord(value) || value.ok !== true || !isRecord(value.contract)) return false;
|
|
@@ -267,8 +292,12 @@ function validateLaunchContract<Request extends AgentLaunchRequest, Value>(
|
|
|
267
292
|
contract.model !== resolvedModel ||
|
|
268
293
|
contract.thinking !== request.model.thinking ||
|
|
269
294
|
contract.systemPromptMode !== "replace" ||
|
|
295
|
+
contract.inheritGlobalContext !== false ||
|
|
270
296
|
contract.inheritProjectContext !== false ||
|
|
271
|
-
contract.inheritSkills !== false
|
|
297
|
+
contract.inheritSkills !== false ||
|
|
298
|
+
!isRecord(contract.intercomBridge) ||
|
|
299
|
+
contract.intercomBridge.active !== false ||
|
|
300
|
+
contract.intercomBridge.mode !== "off"
|
|
272
301
|
)
|
|
273
302
|
return false;
|
|
274
303
|
|
|
@@ -292,6 +321,7 @@ function validateLaunchContract<Request extends AgentLaunchRequest, Value>(
|
|
|
292
321
|
!exactStrings(contract.tools.effectiveMcpTools, []) ||
|
|
293
322
|
!exactStrings(contract.tools.toolExtensionPaths, []) ||
|
|
294
323
|
!exactStrings(contract.tools.configuredExtensions, []) ||
|
|
324
|
+
!exactStrings(contract.tools.requiredExtensionIds, []) ||
|
|
295
325
|
contract.tools.disableAmbientExtensions !== true ||
|
|
296
326
|
contract.tools.fanoutAuthorized !== false ||
|
|
297
327
|
"capabilityCeiling" in contract.tools ||
|
|
@@ -301,7 +331,8 @@ function validateLaunchContract<Request extends AgentLaunchRequest, Value>(
|
|
|
301
331
|
!contract.tools.runtimeExtensions.every(
|
|
302
332
|
(extension) => typeof extension === "string" && extension.length > 0,
|
|
303
333
|
) ||
|
|
304
|
-
!exactStrings(contract.tools.
|
|
334
|
+
!exactStrings(contract.tools.runtimeExtensions, modules.profileRuntimeExtensions()) ||
|
|
335
|
+
!exactStrings(contract.tools.extensionArgs, modules.profileRuntimeExtensions())
|
|
305
336
|
)
|
|
306
337
|
return false;
|
|
307
338
|
|
|
@@ -348,6 +379,7 @@ function requestPayload<Request extends AgentLaunchRequest, Value>(
|
|
|
348
379
|
thinking: request.model.thinking,
|
|
349
380
|
timeoutMs: LAUNCH_TERMINAL_TIMEOUT_MS,
|
|
350
381
|
artifacts: false,
|
|
382
|
+
intercomBridge: { mode: "off" },
|
|
351
383
|
skill: false,
|
|
352
384
|
result:
|
|
353
385
|
definition.result.variant === "structured"
|
|
@@ -492,7 +524,7 @@ export class AgentLaunch<Request extends AgentLaunchRequest, Value> {
|
|
|
492
524
|
resolved = undefined;
|
|
493
525
|
}
|
|
494
526
|
if (!this.isLive(active)) return;
|
|
495
|
-
if (!validateLaunchContract(resolved, request, active, this.definition)) {
|
|
527
|
+
if (!validateLaunchContract(resolved, request, active, this.definition, modules)) {
|
|
496
528
|
active.settle({ kind: "unavailable" });
|
|
497
529
|
return;
|
|
498
530
|
}
|
|
@@ -19,7 +19,7 @@ import type { SourceSnapshot } from "./context-shunt.ts";
|
|
|
19
19
|
import type { ReaderAnswer, ReaderThinking } from "./context-shunt-reader.ts";
|
|
20
20
|
|
|
21
21
|
export const CONTEXT_SHUNT_READER_AGENT_NAME = "pi-delegation-policy.context-shunt-inline-reader";
|
|
22
|
-
export const CONTEXT_SHUNT_READER_PROTOCOL_VERSION = "0.
|
|
22
|
+
export const CONTEXT_SHUNT_READER_PROTOCOL_VERSION = "0.76.1";
|
|
23
23
|
export const READER_PREFLIGHT_TIMEOUT_MS = LAUNCH_PREFLIGHT_TIMEOUT_MS;
|
|
24
24
|
export const READER_TERMINAL_TIMEOUT_MS = LAUNCH_TERMINAL_TIMEOUT_MS;
|
|
25
25
|
|
package/src/prompt.ts
CHANGED
|
@@ -44,6 +44,9 @@ const LEGACY_OWNERSHIP_POLICY =
|
|
|
44
44
|
const ORCHESTRATOR_OWNERSHIP_POLICY =
|
|
45
45
|
"In orchestrator, keep global strategy, objectives, critical decisions, coordination, safety, evidence evaluation, final acceptance, and concise synthesis with the main agent. The main agent MUST delegate transferable detailed review and integration mechanics; final responsibility does not permit personal execution except under the named direct-work exceptions.";
|
|
46
46
|
|
|
47
|
+
const WORKFLOW_DISCLOSURE_POLICY =
|
|
48
|
+
"Orchestration scripts, workflow code, and child briefs are internal working material, not deliverables for the user. Do not paste or send their source code into the chat. Launch a script by the path of its private file, which the host manages, and report only the results, blockers, and decisions the user needs. Keep any control or visibility the host requires. When the user explicitly asks to inspect code, show what was requested.";
|
|
49
|
+
|
|
47
50
|
const VISUAL_DESIGN_POLICY = `Visual Design is an optional specialist role. It is optional to configure. Before selecting an ordinary role for each task or phase, evaluate whether Visual Design is configured and all four conditions hold:
|
|
48
51
|
1. the primary acceptance criterion is a visual or user-experience result;
|
|
49
52
|
2. product behavior and data contracts are already defined and remain unchanged;
|
|
@@ -292,6 +295,9 @@ ${ROLE_SELECTION_POLICY}
|
|
|
292
295
|
Ownership and retention:
|
|
293
296
|
${ownershipPolicy}
|
|
294
297
|
|
|
298
|
+
Workflow disclosure:
|
|
299
|
+
${WORKFLOW_DISCLOSURE_POLICY}
|
|
300
|
+
|
|
295
301
|
Enabled ordinary roles: ${enabled.map(roleName).join(", ")}.${disabled.length ? `\nDisabled ordinary roles: ${disabled.map(roleName).join(", ")}.` : ""}
|
|
296
302
|
|
|
297
303
|
Model preference: ${effective.preference}. ${preferenceGuidance(effective.preference, enabled)}
|