pi-cohort 7.6.2 → 7.6.4

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.6.4] - 2026-10-29
4
+
5
+ ### Fixed
6
+ - Async children on external execution backends no longer falsely need attention while a tool call runs past the idle threshold within an open turn; replay now opens the turn, preserving the silence ceiling and final-answer closure. (#37)
7
+
8
+ ## [7.6.3] - 2026-10-28
9
+
10
+ ### Added
11
+ - Every child process gets `PI_SUBAGENT_PARENT_SESSION_ID`, the pi session id of the session that launched it, so a session roster can link each child to its parent without parsing the session name. A nested child gets its immediate parent's id. The README now lists `PI_SUBAGENT_CHILD`, `PI_SUBAGENT_CHILD_AGENT`, `PI_SUBAGENT_RUN_ID`, and `PI_SUBAGENT_PARENT_SESSION_ID` as stable inputs for other extensions. (#34)
12
+
3
13
  ## [7.6.2] - 2026-10-28
4
14
 
5
15
  ### Added
package/README.md CHANGED
@@ -177,6 +177,15 @@ Each child session is named `<agent> <run id prefix>[/<index>] from <parent>`, s
177
177
 
178
178
  The run id prefix works as the `id` for `subagent` status, interrupt, and resume; the index is the child `index` for resume. A nested child names its parent child: `worker 7b41d0aa from scout 3f9a2c1e from billing reports`.
179
179
 
180
+ Every child process also gets these environment variables, stable inputs for other extensions (for example, a session roster linking each child to its parent):
181
+
182
+ | Variable | Value | Set |
183
+ |---|---|---|
184
+ | `PI_SUBAGENT_CHILD` | `1` | on every child |
185
+ | `PI_SUBAGENT_CHILD_AGENT` | the child's agent name | when the agent is known |
186
+ | `PI_SUBAGENT_RUN_ID` | the full run id; its prefix appears in the session name | when the run id is known |
187
+ | `PI_SUBAGENT_PARENT_SESSION_ID` | the pi session id of the session that launched the child | on every child; a nested child gets its immediate parent's id, never an inherited ancestor's |
188
+
180
189
  Full reference: agent/chain authoring in [doc/agents-and-chains.md](doc/agents-and-chains.md), exact command syntax in [doc/commands.md](doc/commands.md), the raw tool API in [doc/programmatic-api.md](doc/programmatic-api.md).
181
190
 
182
191
  ## Key concepts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cohort",
3
- "version": "7.6.2",
3
+ "version": "7.6.4",
4
4
  "description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
5
5
  "author": "Jacek Juraszek",
6
6
  "license": "MIT",
@@ -59,6 +59,8 @@ interface AsyncExecutionContext {
59
59
  parentThinking?: string;
60
60
  /** Parent session display name, or its id when unnamed, captured at dispatch */
61
61
  parentSessionLabel?: string;
62
+ /** Parent session id, captured at dispatch */
63
+ parentSessionId?: string;
62
64
  executionBackend?: string;
63
65
  }
64
66
 
@@ -635,6 +637,7 @@ export function executeAsyncChain(
635
637
  asyncDir,
636
638
  sessionId: ctx.currentSessionId,
637
639
  parentSessionLabel: ctx.parentSessionLabel,
640
+ parentSessionId: ctx.parentSessionId,
638
641
  runtime: ctx.runtime,
639
642
  forwardedFlags,
640
643
  worktreeSetupHook,
@@ -850,6 +853,7 @@ export function executeAsyncSingle(
850
853
  asyncDir,
851
854
  sessionId: ctx.currentSessionId,
852
855
  parentSessionLabel: ctx.parentSessionLabel,
856
+ parentSessionId: ctx.parentSessionId,
853
857
  runtime: ctx.runtime,
854
858
  forwardedFlags,
855
859
  worktreeSetupHook,
@@ -123,6 +123,7 @@ function synthesizeChildEvents(message: unknown, emit: (event: SynthesizedChildE
123
123
  emit({ type: "tool_execution_end" });
124
124
  emit({ type: "tool_result_end", message });
125
125
  } else if (msg.role === "assistant") {
126
+ emit({ type: "message_start" });
126
127
  // Emit tool_execution_start for each tool call in the assistant content.
127
128
  if (Array.isArray(msg.content)) {
128
129
  for (const part of msg.content) {
@@ -118,6 +118,7 @@ interface SubagentRunConfig {
118
118
  asyncDir: string;
119
119
  sessionId?: string | null;
120
120
  parentSessionLabel?: string;
121
+ parentSessionId?: string;
121
122
  runtime: PiRuntimeIdentity;
122
123
  forwardedFlags?: string[];
123
124
  worktreeSetupHook?: string;
@@ -627,6 +628,7 @@ export interface SingleStepContext {
627
628
  runtime: PiRuntimeIdentity;
628
629
  forwardedFlags?: string[];
629
630
  parentSessionLabel?: string;
631
+ parentSessionId?: string;
630
632
  registerInterrupt?: (interrupt: (() => void) | undefined) => void;
631
633
  nestedRoute?: NestedRouteInfo;
632
634
  onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
@@ -793,6 +795,7 @@ export async function runSingleStep(
793
795
  childAgentName: step.agent,
794
796
  childIndex: ctx.flatIndex,
795
797
  parentSessionLabel: ctx.parentSessionLabel,
798
+ parentSessionId: ctx.parentSessionId,
796
799
  parentEventSink: ctx.nestedRoute?.eventSink,
797
800
  parentControlInbox: ctx.nestedRoute?.controlInbox,
798
801
  parentRootRunId: ctx.nestedRoute?.rootRunId,
@@ -940,6 +943,7 @@ export async function runSingleStep(
940
943
  childAgentName: step.agent,
941
944
  childIndex: ctx.flatIndex,
942
945
  parentSessionLabel: ctx.parentSessionLabel,
946
+ parentSessionId: ctx.parentSessionId,
943
947
  parentEventSink: ctx.nestedRoute?.eventSink,
944
948
  parentControlInbox: ctx.nestedRoute?.controlInbox,
945
949
  parentRootRunId: ctx.nestedRoute?.rootRunId,
@@ -1983,6 +1987,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1983
1987
  controlConfig: config.controlConfig,
1984
1988
  forwardedFlags: config.forwardedFlags,
1985
1989
  parentSessionLabel: config.parentSessionLabel,
1990
+ parentSessionId: config.parentSessionId,
1986
1991
  executionBackendCoordinator,
1987
1992
  executionBackendConfig,
1988
1993
  nestedRoute: config.nestedRoute,
@@ -2274,6 +2279,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2274
2279
  controlConfig: config.controlConfig,
2275
2280
  forwardedFlags: config.forwardedFlags,
2276
2281
  parentSessionLabel: config.parentSessionLabel,
2282
+ parentSessionId: config.parentSessionId,
2277
2283
  executionBackendCoordinator,
2278
2284
  executionBackendConfig,
2279
2285
  nestedRoute: config.nestedRoute,
@@ -2455,6 +2461,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2455
2461
  controlConfig: config.controlConfig,
2456
2462
  forwardedFlags: config.forwardedFlags,
2457
2463
  parentSessionLabel: config.parentSessionLabel,
2464
+ parentSessionId: config.parentSessionId,
2458
2465
  executionBackendCoordinator,
2459
2466
  executionBackendConfig,
2460
2467
  nestedRoute: config.nestedRoute,
@@ -320,6 +320,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
320
320
  parentModel: parentModelFullId(input.ctx.model),
321
321
  parentThinking: input.ctx.thinkingLevel,
322
322
  parentSessionLabel: resolveSessionLabel(input.ctx.sessionManager),
323
+ parentSessionId: input.ctx.sessionManager.getSessionId(),
323
324
  skills: behavior.skills === false ? [] : behavior.skills,
324
325
  structuredOutput: structuredRuntime,
325
326
  acceptance: task.acceptance,
@@ -1164,6 +1165,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1164
1165
  parentModel: parentModelFullId(ctx.model),
1165
1166
  parentThinking: ctx.thinkingLevel,
1166
1167
  parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
1168
+ parentSessionId: ctx.sessionManager.getSessionId(),
1167
1169
  skills: behavior.skills === false ? [] : behavior.skills,
1168
1170
  structuredOutput: structuredRuntime,
1169
1171
  acceptance: seqStep.acceptance,
@@ -159,6 +159,7 @@ async function runSingleAttempt(
159
159
  childAgentName: agent.name,
160
160
  childIndex: options.index ?? 0,
161
161
  parentSessionLabel: options.parentSessionLabel,
162
+ parentSessionId: options.parentSessionId,
162
163
  parentEventSink: options.nestedRoute?.eventSink,
163
164
  parentControlInbox: options.nestedRoute?.controlInbox,
164
165
  parentRootRunId: options.nestedRoute?.rootRunId,
@@ -93,6 +93,7 @@ export async function runExternalSingleAttempt(input: RunExternalSingleAttemptIn
93
93
  childAgentName: agent.name,
94
94
  childIndex: options.index ?? 0,
95
95
  parentSessionLabel: options.parentSessionLabel,
96
+ parentSessionId: options.parentSessionId,
96
97
  parentEventSink: options.nestedRoute?.eventSink,
97
98
  parentControlInbox: options.nestedRoute?.controlInbox,
98
99
  parentRootRunId: options.nestedRoute?.rootRunId,
@@ -226,6 +226,7 @@ function buildAsyncContext(ctx: ExtensionContext, deps: CallExecutorDeps, cwd: s
226
226
  parentModel: parentModelFullId(ctx.model),
227
227
  parentThinking: ctx.thinkingLevel,
228
228
  parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
229
+ parentSessionId: ctx.sessionManager.getSessionId(),
229
230
  executionBackend: deps.config.executionBackend,
230
231
  };
231
232
  }
@@ -1505,6 +1506,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
1505
1506
  parentModel: parentModelFullId(input.ctx.model),
1506
1507
  parentThinking: input.ctx.thinkingLevel,
1507
1508
  parentSessionLabel: resolveSessionLabel(input.ctx.sessionManager),
1509
+ parentSessionId: input.ctx.sessionManager.getSessionId(),
1508
1510
  skills: effectiveSkills === false ? [] : effectiveSkills,
1509
1511
  acceptance: task.acceptance,
1510
1512
  acceptanceContext: { mode: "parallel" },
@@ -2067,6 +2069,7 @@ async function runSinglePath(data: ExecutionContextData, deps: CallExecutorDeps)
2067
2069
  parentModel: parentModelFullId(ctx.model),
2068
2070
  parentThinking: ctx.thinkingLevel,
2069
2071
  parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
2072
+ parentSessionId: ctx.sessionManager.getSessionId(),
2070
2073
  skills: effectiveSkills,
2071
2074
  acceptance: params.acceptance,
2072
2075
  acceptanceContext: { mode: "single" },
@@ -24,6 +24,7 @@ export const SUBAGENT_PARENT_CHILD_INDEX_ENV = "PI_SUBAGENT_PARENT_CHILD_INDEX";
24
24
  export const SUBAGENT_PARENT_DEPTH_ENV = "PI_SUBAGENT_PARENT_DEPTH";
25
25
  export const SUBAGENT_PARENT_PATH_ENV = "PI_SUBAGENT_PARENT_PATH";
26
26
  export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = "PI_SUBAGENT_PARENT_CAPABILITY_TOKEN";
27
+ export const SUBAGENT_PARENT_SESSION_ID_ENV = "PI_SUBAGENT_PARENT_SESSION_ID";
27
28
 
28
29
  interface BuildPiArgsInput {
29
30
  baseArgs: string[];
@@ -47,6 +48,7 @@ interface BuildPiArgsInput {
47
48
  childIndex?: number;
48
49
  /** Parent session display name, or its id when unnamed; names the child session. */
49
50
  parentSessionLabel?: string;
51
+ parentSessionId?: string;
50
52
  parentEventSink?: string;
51
53
  parentControlInbox?: string;
52
54
  parentRootRunId?: string;
@@ -218,6 +220,8 @@ export function buildPiArgs(input: BuildPiArgsInput, fileSystem: BuildPiArgsFile
218
220
  env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
219
221
  ? input.parentCapabilityToken ?? process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] ?? ""
220
222
  : "";
223
+ // Always set, so a grandchild sees its immediate parent rather than an inherited ancestor.
224
+ env[SUBAGENT_PARENT_SESSION_ID_ENV] = input.parentSessionId ?? "";
221
225
  env.PI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext ? "1" : "0";
222
226
  env.PI_SUBAGENT_INHERIT_SKILLS = input.inheritSkills ? "1" : "0";
223
227
  if (input.runId) {
@@ -832,6 +832,8 @@ export interface RunSyncOptions {
832
832
  parentThinking?: string;
833
833
  /** Parent session display name, or its id when unnamed; names the child session */
834
834
  parentSessionLabel?: string;
835
+ /** Parent session id; exported to the child as PI_SUBAGENT_PARENT_SESSION_ID */
836
+ parentSessionId?: string;
835
837
  /** Skills to inject (overrides agent default if provided) */
836
838
  skills?: string[];
837
839
  structuredOutput?: {