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 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.17.0** requires Pi `0.87.1` or later (`>=0.87.1`); it re-applies its marked policy block in the final provider payload.
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.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 (protocol `0.69.0` is the
167
- verified one). Delegation `off` suspends the layer.
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.17.0` requires Pi `0.87.1` or later; version `0.14.1` requires Pi `0.84.3` or later.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-delegation-policy",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "private": false,
5
5
  "description": "A Pi extension for configurable delegation intensity and exact subagent role model references.",
6
6
  "type": "module",
@@ -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.69.0 `src/api/preflight.ts` and `src/shared/launch-contract.ts`. */
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([loadModule("pi-subagents/preflight"), loadModule("pi-subagents/delegation")])
169
- .then(([preflight, delegation]) => {
170
- if (!isRecord(preflight) || !isRecord(delegation)) return undefined;
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.extensionArgs, contract.tools.runtimeExtensions)
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.69.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)}