pi-cohort 7.6.1 → 7.6.2

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,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.6.2] - 2026-10-28
4
+
5
+ ### Added
6
+ - Each child session is named `<agent> <run id prefix>[/<index>] from <parent>`, where `<parent>` is the parent session's name or, when unnamed, its id. `/resume`, terminal titles, and live-session rosters now tell children apart instead of listing unnamed sessions. (#32)
7
+
3
8
  ## [7.6.1] - 2026-10-26
4
9
 
5
10
  ### Added
package/README.md CHANGED
@@ -167,6 +167,16 @@ Review and delivery workflows live in pi-gauntlet; pi-cohort ships delegation pr
167
167
 
168
168
  `context: "fork"` starts a child from a real branched session instead of a fresh one, when it needs the parent's history. Cost across the whole subtree - main loop plus every foreground/background/nested child - rolls up into one `Σ$` total in the footer; see [doc/observability.md](doc/observability.md).
169
169
 
170
+ Each child session is named `<agent> <run id prefix>[/<index>] from <parent>`, so `/resume`, terminal titles, and live-session rosters can tell children apart:
171
+
172
+ | Child | Session name |
173
+ |---|---|
174
+ | Single `scout` from a session named `billing reports` | `scout 3f9a2c1e from billing reports` |
175
+ | Third task (index 2) of the same parallel run | `scout 3f9a2c1e/2 from billing reports` |
176
+ | `scout` from an unnamed session | `scout 3f9a2c1e from <parent session id>` |
177
+
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
+
170
180
  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).
171
181
 
172
182
  ## Key concepts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cohort",
3
- "version": "7.6.1",
3
+ "version": "7.6.2",
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",
@@ -57,6 +57,8 @@ interface AsyncExecutionContext {
57
57
  parentModel?: string;
58
58
  /** Parent session thinking level, captured at dispatch */
59
59
  parentThinking?: string;
60
+ /** Parent session display name, or its id when unnamed, captured at dispatch */
61
+ parentSessionLabel?: string;
60
62
  executionBackend?: string;
61
63
  }
62
64
 
@@ -632,6 +634,7 @@ export function executeAsyncChain(
632
634
  sessionDir: path.join(sessionRoot ?? path.join(RUN_STATE_ROOT_DIR, "sessions"), `async-${id}`),
633
635
  asyncDir,
634
636
  sessionId: ctx.currentSessionId,
637
+ parentSessionLabel: ctx.parentSessionLabel,
635
638
  runtime: ctx.runtime,
636
639
  forwardedFlags,
637
640
  worktreeSetupHook,
@@ -846,6 +849,7 @@ export function executeAsyncSingle(
846
849
  sessionDir: path.join(sessionRoot ?? path.join(RUN_STATE_ROOT_DIR, "sessions"), `async-${id}`),
847
850
  asyncDir,
848
851
  sessionId: ctx.currentSessionId,
852
+ parentSessionLabel: ctx.parentSessionLabel,
849
853
  runtime: ctx.runtime,
850
854
  forwardedFlags,
851
855
  worktreeSetupHook,
@@ -117,6 +117,7 @@ interface SubagentRunConfig {
117
117
  sessionDir?: string;
118
118
  asyncDir: string;
119
119
  sessionId?: string | null;
120
+ parentSessionLabel?: string;
120
121
  runtime: PiRuntimeIdentity;
121
122
  forwardedFlags?: string[];
122
123
  worktreeSetupHook?: string;
@@ -625,6 +626,7 @@ export interface SingleStepContext {
625
626
  outputFile: string;
626
627
  runtime: PiRuntimeIdentity;
627
628
  forwardedFlags?: string[];
629
+ parentSessionLabel?: string;
628
630
  registerInterrupt?: (interrupt: (() => void) | undefined) => void;
629
631
  nestedRoute?: NestedRouteInfo;
630
632
  onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
@@ -790,6 +792,7 @@ export async function runSingleStep(
790
792
  runId: ctx.id,
791
793
  childAgentName: step.agent,
792
794
  childIndex: ctx.flatIndex,
795
+ parentSessionLabel: ctx.parentSessionLabel,
793
796
  parentEventSink: ctx.nestedRoute?.eventSink,
794
797
  parentControlInbox: ctx.nestedRoute?.controlInbox,
795
798
  parentRootRunId: ctx.nestedRoute?.rootRunId,
@@ -936,6 +939,7 @@ export async function runSingleStep(
936
939
  runId: ctx.id,
937
940
  childAgentName: step.agent,
938
941
  childIndex: ctx.flatIndex,
942
+ parentSessionLabel: ctx.parentSessionLabel,
939
943
  parentEventSink: ctx.nestedRoute?.eventSink,
940
944
  parentControlInbox: ctx.nestedRoute?.controlInbox,
941
945
  parentRootRunId: ctx.nestedRoute?.rootRunId,
@@ -1978,6 +1982,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1978
1982
  runtime: config.runtime,
1979
1983
  controlConfig: config.controlConfig,
1980
1984
  forwardedFlags: config.forwardedFlags,
1985
+ parentSessionLabel: config.parentSessionLabel,
1981
1986
  executionBackendCoordinator,
1982
1987
  executionBackendConfig,
1983
1988
  nestedRoute: config.nestedRoute,
@@ -2268,6 +2273,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2268
2273
  runtime: config.runtime,
2269
2274
  controlConfig: config.controlConfig,
2270
2275
  forwardedFlags: config.forwardedFlags,
2276
+ parentSessionLabel: config.parentSessionLabel,
2271
2277
  executionBackendCoordinator,
2272
2278
  executionBackendConfig,
2273
2279
  nestedRoute: config.nestedRoute,
@@ -2448,6 +2454,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2448
2454
  runtime: config.runtime,
2449
2455
  controlConfig: config.controlConfig,
2450
2456
  forwardedFlags: config.forwardedFlags,
2457
+ parentSessionLabel: config.parentSessionLabel,
2451
2458
  executionBackendCoordinator,
2452
2459
  executionBackendConfig,
2453
2460
  nestedRoute: config.nestedRoute,
@@ -9,6 +9,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
9
9
  import type { AgentConfig } from "../../agents/agents.ts";
10
10
  import { ChainClarifyComponent, type ChainClarifyResult, type BehaviorOverride } from "./chain-clarify.ts";
11
11
  import { parentModelFullId, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
12
+ import { resolveSessionLabel } from "../../shared/session-identity.ts";
12
13
  import {
13
14
  resolveChainTemplates,
14
15
  createChainDir,
@@ -318,6 +319,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
318
319
  preferredModelProvider: input.ctx.model?.provider,
319
320
  parentModel: parentModelFullId(input.ctx.model),
320
321
  parentThinking: input.ctx.thinkingLevel,
322
+ parentSessionLabel: resolveSessionLabel(input.ctx.sessionManager),
321
323
  skills: behavior.skills === false ? [] : behavior.skills,
322
324
  structuredOutput: structuredRuntime,
323
325
  acceptance: task.acceptance,
@@ -1161,6 +1163,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1161
1163
  preferredModelProvider: ctx.model?.provider,
1162
1164
  parentModel: parentModelFullId(ctx.model),
1163
1165
  parentThinking: ctx.thinkingLevel,
1166
+ parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
1164
1167
  skills: behavior.skills === false ? [] : behavior.skills,
1165
1168
  structuredOutput: structuredRuntime,
1166
1169
  acceptance: seqStep.acceptance,
@@ -158,6 +158,7 @@ async function runSingleAttempt(
158
158
  runId: options.runId,
159
159
  childAgentName: agent.name,
160
160
  childIndex: options.index ?? 0,
161
+ parentSessionLabel: options.parentSessionLabel,
161
162
  parentEventSink: options.nestedRoute?.eventSink,
162
163
  parentControlInbox: options.nestedRoute?.controlInbox,
163
164
  parentRootRunId: options.nestedRoute?.rootRunId,
@@ -92,6 +92,7 @@ export async function runExternalSingleAttempt(input: RunExternalSingleAttemptIn
92
92
  runId: options.runId,
93
93
  childAgentName: agent.name,
94
94
  childIndex: options.index ?? 0,
95
+ parentSessionLabel: options.parentSessionLabel,
95
96
  parentEventSink: options.nestedRoute?.eventSink,
96
97
  parentControlInbox: options.nestedRoute?.controlInbox,
97
98
  parentRootRunId: options.nestedRoute?.rootRunId,
@@ -37,7 +37,7 @@ import {
37
37
  import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
38
38
  import { executeAsyncChain, executeAsyncSingle, formatAsyncStartedMessage, isAsyncAvailable } from "../background/async-execution.ts";
39
39
  import { createForkContextResolver } from "../../shared/fork-context.ts";
40
- import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
40
+ import { resolveCurrentSessionId, resolveSessionLabel } from "../../shared/session-identity.ts";
41
41
  import { formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "../shared/subagent-control.ts";
42
42
  import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeTopLevelOutput, resolveParallelTaskOutputPath, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
43
43
  import { blockedLine } from "../shared/completion-guard.ts";
@@ -225,6 +225,7 @@ function buildAsyncContext(ctx: ExtensionContext, deps: CallExecutorDeps, cwd: s
225
225
  currentModelProvider: ctx.model?.provider,
226
226
  parentModel: parentModelFullId(ctx.model),
227
227
  parentThinking: ctx.thinkingLevel,
228
+ parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
228
229
  executionBackend: deps.config.executionBackend,
229
230
  };
230
231
  }
@@ -1503,6 +1504,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
1503
1504
  preferredModelProvider: input.ctx.model?.provider,
1504
1505
  parentModel: parentModelFullId(input.ctx.model),
1505
1506
  parentThinking: input.ctx.thinkingLevel,
1507
+ parentSessionLabel: resolveSessionLabel(input.ctx.sessionManager),
1506
1508
  skills: effectiveSkills === false ? [] : effectiveSkills,
1507
1509
  acceptance: task.acceptance,
1508
1510
  acceptanceContext: { mode: "parallel" },
@@ -2064,6 +2066,7 @@ async function runSinglePath(data: ExecutionContextData, deps: CallExecutorDeps)
2064
2066
  preferredModelProvider: currentProvider,
2065
2067
  parentModel: parentModelFullId(ctx.model),
2066
2068
  parentThinking: ctx.thinkingLevel,
2069
+ parentSessionLabel: resolveSessionLabel(ctx.sessionManager),
2067
2070
  skills: effectiveSkills,
2068
2071
  acceptance: params.acceptance,
2069
2072
  acceptanceContext: { mode: "single" },
@@ -45,6 +45,8 @@ interface BuildPiArgsInput {
45
45
  runId?: string;
46
46
  childAgentName?: string;
47
47
  childIndex?: number;
48
+ /** Parent session display name, or its id when unnamed; names the child session. */
49
+ parentSessionLabel?: string;
48
50
  parentEventSink?: string;
49
51
  parentControlInbox?: string;
50
52
  parentRootRunId?: string;
@@ -79,6 +81,13 @@ export function applyThinkingSuffix(model: string | undefined, thinking: string
79
81
  return `${model}:${thinking}`;
80
82
  }
81
83
 
84
+ function childSessionName(input: BuildPiArgsInput): string | undefined {
85
+ if (!input.childAgentName || !input.runId) return undefined;
86
+ const index = input.childIndex ? `/${input.childIndex}` : "";
87
+ const parent = input.parentSessionLabel ? ` from ${input.parentSessionLabel}` : "";
88
+ return `${input.childAgentName} ${input.runId.slice(0, 8)}${index}${parent}`;
89
+ }
90
+
82
91
  export function buildPiArgs(input: BuildPiArgsInput, fileSystem: BuildPiArgsFileSystem = fs): BuildPiArgsResult {
83
92
  const args = [...input.baseArgs];
84
93
  // Forwarded flags are already name-deduped by deriveForwardedFlags; append only
@@ -100,6 +109,11 @@ export function buildPiArgs(input: BuildPiArgsInput, fileSystem: BuildPiArgsFile
100
109
  }
101
110
  }
102
111
 
112
+ const sessionName = childSessionName(input);
113
+ if (sessionName) {
114
+ args.push("--name", sessionName);
115
+ }
116
+
103
117
  const modelArg = applyThinkingSuffix(input.model, input.thinking);
104
118
  if (modelArg) {
105
119
  args.push("--model", modelArg);
@@ -3,8 +3,18 @@ interface SessionIdentityManager {
3
3
  getSessionId(): string | null | undefined;
4
4
  }
5
5
 
6
+ interface SessionLabelManager {
7
+ getSessionName(): string | undefined;
8
+ getSessionId(): string;
9
+ }
10
+
6
11
  export function resolveCurrentSessionId(sessionManager: SessionIdentityManager): string {
7
12
  const sessionId = sessionManager.getSessionFile() ?? sessionManager.getSessionId();
8
13
  if (!sessionId) throw new Error("Current session identity is unavailable.");
9
14
  return sessionId;
10
15
  }
16
+
17
+ /** The session's display name, or its id when unnamed. */
18
+ export function resolveSessionLabel(sessionManager: SessionLabelManager): string {
19
+ return sessionManager.getSessionName() || sessionManager.getSessionId();
20
+ }
@@ -830,6 +830,8 @@ export interface RunSyncOptions {
830
830
  parentModel?: string;
831
831
  /** Parent session thinking level; used when the agent sets no `thinking` */
832
832
  parentThinking?: string;
833
+ /** Parent session display name, or its id when unnamed; names the child session */
834
+ parentSessionLabel?: string;
833
835
  /** Skills to inject (overrides agent default if provided) */
834
836
  skills?: string[];
835
837
  structuredOutput?: {