oira666_pi-subagent 0.1.15 → 0.2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Pi Subagent
2
2
 
3
- Delegate tasks to specialized subagents with configurable context modes (`spawn` / `fork`).
3
+ Delegate tasks to specialized subagents.
4
4
 
5
5
  ## Install
6
6
 
@@ -39,21 +39,17 @@ Processes are spawned via the operating system and communicate through JSON-line
39
39
  Each subagent runs as an **in-process `AgentSession`** created via the pi SDK — no new process is spawned.
40
40
 
41
41
  - No spawn overhead — sessions start in milliseconds
42
- - No temp files for system prompts or fork snapshots
42
+ - No temp files for system prompts
43
43
  - Concurrency through the Node.js event loop (fine for I/O-bound LLM work)
44
44
  - All sessions share the same memory and event loop
45
45
 
46
- ### Context modes
47
-
48
- **`spawn` (default)** — Child receives only the task string. Best for isolated work, lower cost.
49
- **`fork`** — Child receives a snapshot of the current session context + task. Best for follow-up work.
50
-
51
- The main agent receives only the **final text output** from subagents (no tool calls, no reasoning).
46
+ Each subagent receives only the task string. The main agent in turn receives
47
+ only the **final text output** from subagents (no tool calls, no reasoning).
52
48
 
53
49
  ## Tool Call Shape
54
50
 
55
51
  ```json
56
- { "tasks": [{ "agent": "code-writer", "task": "Implement the API" }], "mode": "spawn" }
52
+ { "tasks": [{ "agent": "code-writer", "task": "Implement the API" }] }
57
53
  ```
58
54
 
59
55
  Multiple tasks run in parallel:
@@ -63,8 +59,7 @@ Multiple tasks run in parallel:
63
59
  "tasks": [
64
60
  { "agent": "code-writer", "task": "Draft the implementation" },
65
61
  { "agent": "code-reviwer", "task": "Review the plan" }
66
- ],
67
- "mode": "fork"
62
+ ]
68
63
  }
69
64
  ```
70
65
 
@@ -136,7 +131,6 @@ PI_SUBAGENTS_MODE=subprocess pi
136
131
  | Session isolation | Full OS-level | Shared memory/event loop |
137
132
  | Startup overhead | ~200–500 ms per agent | ~10–50 ms per agent |
138
133
  | Parallelism | True OS parallelism | Event-loop concurrency |
139
- | Fork mode context | Temp JSONL file | Temp JSONL file (same format) |
140
134
  | Depth tracking | Env vars in child process | Closure parameters |
141
135
  | `pi` binary required | Yes | No |
142
136
  | Crash isolation | Yes — subprocess crash is contained | No — exception bubbles up |
@@ -236,7 +230,7 @@ tool_result_end
236
230
  interface SubagentDetails {
237
231
  // Execution metadata
238
232
  mode: "single" | "parallel"; // one task vs multiple parallel tasks
239
- delegationMode: "spawn" | "fork"; // context mode used
233
+ delegationMode: "spawn"; // always "spawn" (kept for backward-compatible serialization)
240
234
  projectAgentsDir: string | null; // path to .pi/agents/ dir if used
241
235
 
242
236
  // Individual agent results (one per task)
@@ -1,8 +1,6 @@
1
1
  ---
2
2
  name: code-architect
3
3
  description: Technical design agent for shaping implementations, APIs, module boundaries, and tradeoffs before coding. Use this agent for plans and architecture decisions.
4
- thinking: high
5
- tools: read,bash,grep,find,ls
6
4
  ---
7
5
 
8
6
  You are a senior software architect focused on practical design.
@@ -1,8 +1,6 @@
1
1
  ---
2
2
  name: code-reviwer
3
3
  description: Code review specialist for finding bugs, regressions, edge cases, and maintainability issues. Use this agent to review code, plans, or patches.
4
- thinking: high
5
- tools: read,bash,grep,find,ls
6
4
  ---
7
5
 
8
6
  You are a skeptical, detail-oriented code reviewer.
@@ -1,8 +1,6 @@
1
1
  ---
2
2
  name: code-writer
3
3
  description: Focused implementation agent for writing and refactoring code with small, reliable diffs. Use this agent when you want code changes made directly.
4
- thinking: medium
5
- tools: read,bash,edit,write
6
4
  ---
7
5
 
8
6
  You are a pragmatic software engineer focused on implementation.
package/index.ts CHANGED
@@ -13,10 +13,6 @@
13
13
  * The tool always accepts a `tasks` array:
14
14
  * - One task: treated as a single-agent delegation.
15
15
  * - Multiple tasks: treated as a parallel delegation.
16
- *
17
- * And two context modes:
18
- * - spawn (default): child gets only the task prompt.
19
- * - fork: child gets a forked snapshot of current session context + task prompt.
20
16
  */
21
17
 
22
18
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
@@ -33,7 +29,6 @@ import {
33
29
  type SubagentDetails,
34
30
  DEFAULT_DELEGATION_MODE,
35
31
  buildSubagentDetails,
36
- emptyUsage,
37
32
  getFinalOutput,
38
33
  isResultError,
39
34
  } from "./types.js";
@@ -65,7 +60,7 @@ const TaskItem = Type.Object({
65
60
  }),
66
61
  task: Type.String({
67
62
  description:
68
- "Task description for this delegated run. In spawn mode include all required context; in fork mode the subagent also sees your current session context.",
63
+ "Task description for this delegated run. Include all required context; the subagent receives only this prompt.",
69
64
  }),
70
65
  cwd: Type.Optional(
71
66
  Type.String({ description: "Working directory for this agent's process" }),
@@ -78,13 +73,6 @@ const SubagentParams = Type.Object({
78
73
  description:
79
74
  "Array of {agent, task} objects. One task behaves like a single-agent delegation; multiple tasks run concurrently.",
80
75
  }),
81
- mode: Type.Optional(
82
- Type.String({
83
- description:
84
- "Context mode for delegated runs. 'spawn' (default) sends only the task prompt (best for isolated, reproducible runs with lower token/cost and less context leakage). 'fork' adds a snapshot of current session context plus task prompt (best for follow-up work, but usually higher token/cost and may include sensitive context).",
85
- default: DEFAULT_DELEGATION_MODE,
86
- }),
87
- ),
88
76
  });
89
77
 
90
78
  // ---------------------------------------------------------------------------
@@ -99,34 +87,6 @@ interface DelegationDepthConfig {
99
87
  preventCycles: boolean;
100
88
  }
101
89
 
102
- interface SessionSnapshotSource {
103
- getHeader: () => unknown;
104
- getBranch: () => unknown[];
105
- }
106
-
107
- function parseDelegationMode(raw: unknown): DelegationMode | null {
108
- if (raw === undefined) return DEFAULT_DELEGATION_MODE;
109
- if (typeof raw !== "string") return null;
110
- const normalized = raw.trim().toLowerCase();
111
- if (normalized === "spawn" || normalized === "fork") {
112
- return normalized;
113
- }
114
- return null;
115
- }
116
-
117
- function buildForkSessionSnapshotJsonl(
118
- sessionManager: SessionSnapshotSource,
119
- ): string | null {
120
- const header = sessionManager.getHeader();
121
- if (!header || typeof header !== "object") return null;
122
-
123
- const branchEntries = sessionManager.getBranch();
124
- const lines = [JSON.stringify(header)];
125
- for (const entry of branchEntries) lines.push(JSON.stringify(entry));
126
- return `${lines.join("\n")}\n`;
127
- }
128
-
129
-
130
90
  function parseBoolean(raw: unknown): boolean | null {
131
91
  if (typeof raw === "boolean") return raw;
132
92
  if (typeof raw !== "string") return null;
@@ -496,22 +456,18 @@ ${agentList}
496
456
 
497
457
  Each subagent runs in an **isolated process**.
498
458
 
499
- Context behavior is controlled by optional 'mode':
500
- - 'spawn' (default): child receives only the provided task prompt. Best for isolated, reproducible tasks with lower token/cost and less context leakage.
501
- - 'fork': child receives a forked snapshot of current session context plus the task prompt. Best for follow-up tasks that rely on prior context; usually higher token/cost and may include sensitive context.
502
-
503
459
  The tool always accepts a \`tasks\` array:
504
460
  - one item = single-agent delegation
505
461
  - multiple items = parallel delegation
506
462
 
507
463
  **Single-task delegation**:
508
464
  \`\`\`json
509
- { "tasks": [{ "agent": "agent-name", "task": "Detailed task..." }], "mode": "spawn" }
465
+ { "tasks": [{ "agent": "agent-name", "task": "Detailed task..." }] }
510
466
  \`\`\`
511
467
 
512
468
  **Multi-task delegation**:
513
469
  \`\`\`json
514
- { "tasks": [{ "agent": "agent-name", "task": "..." }, { "agent": "other-agent", "task": "..." }], "mode": "fork" }
470
+ { "tasks": [{ "agent": "agent-name", "task": "..." }, { "agent": "other-agent", "task": "..." }] }
515
471
  \`\`\`
516
472
 
517
473
  ### Runtime delegation guards
@@ -541,14 +497,8 @@ The tool always accepts a \`tasks\` array:
541
497
  " - one task: single-agent delegation",
542
498
  " - multiple tasks: parallel delegation",
543
499
  "",
544
- "Optional context mode switch:",
545
- " mode: \"spawn\" (default) -> child gets only your task prompt.",
546
- " Best for isolated/reproducible work; lower token/cost and less context leakage.",
547
- " mode: \"fork\" -> child gets current session context + your task prompt.",
548
- " Best for follow-up work that depends on prior context; higher token/cost and may include sensitive context.",
549
- "",
550
- 'Example single: { tasks: [{ agent: "writer", task: "Rewrite README.md" }], mode: "spawn" }',
551
- 'Example parallel: { tasks: [{ agent: "writer", task: "..." }, { agent: "tester", task: "..." }], mode: "fork" }',
500
+ 'Example single: { tasks: [{ agent: "writer", task: "Rewrite README.md" }] }',
501
+ 'Example parallel: { tasks: [{ agent: "writer", task: "..." }, { agent: "tester", task: "..." }] }',
552
502
  ].join("\n"),
553
503
  parameters: SubagentParams,
554
504
 
@@ -557,48 +507,11 @@ The tool always accepts a \`tasks\` array:
557
507
  const discovery = discoverAgents(ctx.cwd, "both");
558
508
  const { agents } = discovery;
559
509
 
560
- const delegationMode = parseDelegationMode(params.mode);
561
- if (!delegationMode) {
562
- const fallbackDetails = makeDetailsFactory(
563
- discovery.projectAgentsDir,
564
- DEFAULT_DELEGATION_MODE,
565
- );
566
- return {
567
- content: [
568
- {
569
- type: "text",
570
- text: `Invalid mode \"${String(params.mode)}\". Expected \"spawn\" or \"fork\".\nAvailable agents: ${formatAgentNames(agents)}`,
571
- },
572
- ],
573
- details: fallbackDetails("single")([]),
574
- isError: true,
575
- };
576
- }
577
-
578
510
  const makeDetails = makeDetailsFactory(
579
511
  discovery.projectAgentsDir,
580
- delegationMode,
512
+ DEFAULT_DELEGATION_MODE,
581
513
  );
582
514
 
583
- let forkSessionSnapshotJsonl: string | undefined;
584
- if (delegationMode === "fork") {
585
- forkSessionSnapshotJsonl = buildForkSessionSnapshotJsonl(
586
- ctx.sessionManager,
587
- );
588
- if (!forkSessionSnapshotJsonl) {
589
- return {
590
- content: [
591
- {
592
- type: "text",
593
- text: "Cannot use mode=\"fork\": failed to snapshot current session context.",
594
- },
595
- ],
596
- details: makeDetails("single")([]),
597
- isError: true,
598
- };
599
- }
600
- }
601
-
602
515
  const tasks = params.tasks ?? [];
603
516
  if (tasks.length === 0) {
604
517
  return {
@@ -700,8 +613,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
700
613
  task.agent,
701
614
  task.task,
702
615
  task.cwd,
703
- delegationMode,
704
- forkSessionSnapshotJsonl,
705
616
  agents,
706
617
  ctx.cwd,
707
618
  signal,
@@ -714,8 +625,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
714
625
 
715
626
  return await executeParallel(
716
627
  tasks,
717
- delegationMode,
718
- forkSessionSnapshotJsonl,
719
628
  agents,
720
629
  ctx.cwd,
721
630
  signal,
@@ -750,8 +659,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
750
659
  agentName: string,
751
660
  task: string,
752
661
  cwd: string | undefined,
753
- delegationMode: DelegationMode,
754
- forkSessionSnapshotJsonl: string | undefined,
755
662
  agents: AgentConfig[],
756
663
  defaultCwd: string,
757
664
  signal: AbortSignal | undefined,
@@ -768,8 +675,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
768
675
  agentName,
769
676
  task,
770
677
  taskCwd: cwd,
771
- delegationMode,
772
- forkSessionSnapshotJsonl,
773
678
  parentDepth: currentDepth,
774
679
  parentAgentStack: ancestorAgentStack,
775
680
  maxDepth,
@@ -786,8 +691,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
786
691
  agentName,
787
692
  task,
788
693
  taskCwd: cwd,
789
- delegationMode,
790
- forkSessionSnapshotJsonl,
791
694
  parentDepth: currentDepth,
792
695
  parentAgentStack: ancestorAgentStack,
793
696
  maxDepth,
@@ -827,8 +730,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
827
730
 
828
731
  async function executeParallel(
829
732
  tasks: Array<{ agent: string; task: string; cwd?: string }>,
830
- delegationMode: DelegationMode,
831
- forkSessionSnapshotJsonl: string | undefined,
832
733
  agents: AgentConfig[],
833
734
  defaultCwd: string,
834
735
  signal: AbortSignal | undefined,
@@ -840,8 +741,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
840
741
  if (subagentMode === "sdk") {
841
742
  return executeParallelSameProcess(
842
743
  tasks,
843
- delegationMode,
844
- forkSessionSnapshotJsonl,
845
744
  agents,
846
745
  defaultCwd,
847
746
  currentDepth,
@@ -857,8 +756,6 @@ This guard prevents self-recursion and cyclic handoffs (for example A -> B -> A)
857
756
  }
858
757
  return executeParallelSubprocess(
859
758
  tasks,
860
- delegationMode,
861
- forkSessionSnapshotJsonl,
862
759
  agents,
863
760
  defaultCwd,
864
761
  currentDepth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oira666_pi-subagent",
3
- "version": "0.1.15",
3
+ "version": "0.2.0",
4
4
  "description": "Subagent extension for Pi coding agent. Delegate tasks to specialized agents.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
package/render.ts CHANGED
@@ -5,13 +5,11 @@
5
5
  import * as os from "node:os";
6
6
  import { Container, Spacer, Text } from "@mariozechner/pi-tui";
7
7
  import {
8
- type DelegationMode,
9
8
  type LiveLogEntry,
10
9
  type NestedSubagentResult,
11
10
  type SingleResult,
12
11
  type SubagentDetails,
13
12
  type UsageStats,
14
- DEFAULT_DELEGATION_MODE,
15
13
  aggregateUsage,
16
14
  getDisplayItems,
17
15
  getFinalOutput,
@@ -35,6 +33,7 @@ interface TreeNode {
35
33
  children: TreeNode[];
36
34
  }
37
35
 
36
+
38
37
  interface TreeCounts {
39
38
  total: number;
40
39
  running: number;
@@ -45,7 +44,6 @@ interface TreeCounts {
45
44
 
46
45
  interface PendingSubagentCall {
47
46
  toolCallId: string;
48
- mode: DelegationMode;
49
47
  tasks: Array<{ agent: string; task?: string }>;
50
48
  }
51
49
 
@@ -83,10 +81,6 @@ function truncate(text: string, maxLen: number): string {
83
81
  return text.length > maxLen ? `${text.slice(0, maxLen)}...` : text;
84
82
  }
85
83
 
86
- function normalizeDelegationMode(raw: unknown): DelegationMode {
87
- return raw === "fork" ? "fork" : DEFAULT_DELEGATION_MODE;
88
- }
89
-
90
84
  function splitOutputLines(text: string): string[] {
91
85
  const lines = text.replace(/\r\n?/g, "\n").split("\n");
92
86
  if (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
@@ -166,7 +160,6 @@ function extractPendingSubagentCalls(messages: SingleResult["messages"]): Pendin
166
160
  : typeof part.id === "string"
167
161
  ? part.id
168
162
  : `${messageIndex}:${partIndex}`,
169
- mode: normalizeDelegationMode((args as any).mode),
170
163
  tasks,
171
164
  });
172
165
  }
@@ -178,14 +171,13 @@ function buildPendingNodes(call: PendingSubagentCall): TreeNode[] {
178
171
  return call.tasks.map((task) => ({
179
172
  label: task.agent,
180
173
  status: "running",
181
- meta: call.mode === "fork" ? "fork" : "spawn",
182
174
  task: task.task,
183
175
  children: [],
184
176
  }));
185
177
  }
186
178
 
187
179
  function buildNodesFromNestedResult(nested: NestedSubagentResult): TreeNode[] {
188
- return nested.details.results.map((result) => buildResultNode(result, nested.details.delegationMode));
180
+ return nested.details.results.map((result) => buildResultNode(result));
189
181
  }
190
182
 
191
183
  function buildNestedChildren(result: SingleResult): TreeNode[] {
@@ -292,10 +284,10 @@ function buildLeafPreview(result: SingleResult): string[] | undefined {
292
284
  return unique.length > 0 ? unique.slice(-OUTPUT_PREVIEW_LINE_COUNT) : undefined;
293
285
  }
294
286
 
295
- function buildResultNode(result: SingleResult, delegationMode: DelegationMode): TreeNode {
287
+ function buildResultNode(result: SingleResult): TreeNode {
296
288
  const status = statusFromResult(result);
297
289
  const usage = formatUsage(result.usage, result.model);
298
- const metaParts: string[] = [result.agentSource, delegationMode];
290
+ const metaParts: string[] = [result.agentSource];
299
291
  if (usage) metaParts.push(usage);
300
292
  if (status === "error") {
301
293
  const errorText = result.errorMessage || result.stderr || result.stopReason;
@@ -316,7 +308,7 @@ function buildResultNode(result: SingleResult, delegationMode: DelegationMode):
316
308
  }
317
309
 
318
310
  function buildTopLevelNodes(details: SubagentDetails): TreeNode[] {
319
- return details.results.map((result) => buildResultNode(result, details.delegationMode));
311
+ return details.results.map((result) => buildResultNode(result));
320
312
  }
321
313
 
322
314
  function renderTreeLines(
@@ -374,10 +366,9 @@ function topLevelSummary(details: SubagentDetails, counts: TreeCounts): string {
374
366
  // ---------------------------------------------------------------------------
375
367
 
376
368
  export function renderCall(args: Record<string, any>, theme: { fg: ThemeFg; bold: (s: string) => string }): Text {
377
- const delegationMode = normalizeDelegationMode(args.mode);
378
369
  const tasks = Array.isArray(args.tasks) ? args.tasks : [];
379
370
  const count = tasks.length;
380
- let text = `${theme.fg("toolTitle", theme.bold("subagent "))}${theme.fg("muted", `[${delegationMode}]`)} ${theme.fg("accent", `${count} task${count === 1 ? "" : "s"}`)}`;
371
+ let text = `${theme.fg("toolTitle", theme.bold("subagent "))}${theme.fg("accent", `${count} task${count === 1 ? "" : "s"}`)}`;
381
372
  for (const task of tasks.slice(0, 6)) {
382
373
  const agent = typeof task?.agent === "string" ? task.agent : "...";
383
374
  const preview = typeof task?.task === "string" ? ` ${truncate(task.task, 56)}` : "";
@@ -414,7 +405,7 @@ export function renderResult(
414
405
  const container = new Container();
415
406
  container.addChild(
416
407
  new Text(
417
- `${icon} ${theme.fg("toolTitle", theme.bold("subagent tree "))}${theme.fg("muted", `[${details.delegationMode}]`)} ${theme.fg("dim", topLevelSummary(details, counts))}`,
408
+ `${icon} ${theme.fg("toolTitle", theme.bold("subagent tree "))}${theme.fg("dim", topLevelSummary(details, counts))}`,
418
409
  0,
419
410
  0,
420
411
  ),
package/runner-sdk.ts CHANGED
@@ -8,8 +8,6 @@
8
8
  * read at the root level exactly as before — they're just propagated to nested
9
9
  * sessions via closure parameters rather than via subprocess env inheritance.
10
10
  *
11
- * Fork mode still writes a JSONL snapshot to a temp file; the child session
12
- * opens it with SessionManager.open() instead of receiving it via --session.
13
11
  */
14
12
 
15
13
  import {
@@ -26,12 +24,8 @@ import {
26
24
  createLsTool,
27
25
  type ToolDefinition,
28
26
  } from "@mariozechner/pi-coding-agent";
29
- import * as fs from "node:fs";
30
- import * as os from "node:os";
31
- import * as path from "node:path";
32
27
  import type { AgentConfig } from "./agents.js";
33
28
  import {
34
- type DelegationMode,
35
29
  type LiveLogEntry,
36
30
  type SingleResult,
37
31
  type SubagentDetails,
@@ -60,26 +54,6 @@ import {
60
54
  // ---------------------------------------------------------------------------
61
55
 
62
56
 
63
- function writeForkSessionToTempFile(
64
- agentName: string,
65
- sessionJsonl: string,
66
- ): { dir: string; filePath: string } {
67
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
68
- const safeName = agentName.replace(/[^\w.-]+/g, "_");
69
- const filePath = path.join(tmpDir, `fork-${safeName}.jsonl`);
70
- fs.writeFileSync(filePath, sessionJsonl, { encoding: "utf-8", mode: 0o600 });
71
- return { dir: tmpDir, filePath };
72
- }
73
-
74
- function cleanupTempDir(dir: string | null): void {
75
- if (!dir) return;
76
- try {
77
- fs.rmSync(dir, { recursive: true, force: true });
78
- } catch {
79
- /* ignore */
80
- }
81
- }
82
-
83
57
  /**
84
58
  * Build the tool list for a child agent.
85
59
  * When the agent config restricts tools, only those are included.
@@ -127,9 +101,6 @@ export interface RunAgentSameProcessOptions {
127
101
  agentName: string;
128
102
  task: string;
129
103
  taskCwd?: string;
130
- delegationMode: DelegationMode;
131
- /** JSONL session snapshot for fork mode — same format as subprocess runner */
132
- forkSessionSnapshotJsonl?: string;
133
104
  parentDepth: number;
134
105
  parentAgentStack: string[];
135
106
  maxDepth: number;
@@ -163,8 +134,6 @@ export async function runAgentSameProcess(
163
134
  agentName,
164
135
  task,
165
136
  taskCwd,
166
- delegationMode,
167
- forkSessionSnapshotJsonl,
168
137
  parentDepth,
169
138
  parentAgentStack,
170
139
  maxDepth,
@@ -194,28 +163,6 @@ export async function runAgentSameProcess(
194
163
  };
195
164
  }
196
165
 
197
- if (
198
- delegationMode === "fork" &&
199
- (!forkSessionSnapshotJsonl || !forkSessionSnapshotJsonl.trim())
200
- ) {
201
- return {
202
- agent: agentName,
203
- agentSource: agent.source,
204
- task,
205
- exitCode: 1,
206
- messages: [],
207
- stderr: "Cannot run in fork mode: missing parent session snapshot context.",
208
- usage: emptyUsage(),
209
- toolCalls: {},
210
- model: agent.model,
211
- stopReason: "error",
212
- errorMessage: "Cannot run in fork mode: missing parent session snapshot context.",
213
- completedTurns: 0,
214
- turnInProgress: false,
215
- liveLog: [],
216
- };
217
- }
218
-
219
166
  const childDepth = Math.max(0, Math.floor(parentDepth)) + 1;
220
167
  const childStack = [...parentAgentStack, agentName];
221
168
  const effectiveCwd = taskCwd ?? cwd;
@@ -243,16 +190,6 @@ export async function runAgentSameProcess(
243
190
 
244
191
  emitUpdate();
245
192
 
246
- // Fork mode: write JSONL to a temp file; opened via SessionManager.open()
247
- // (same serialisation format as the subprocess runner — backward-compatible)
248
- let forkTmpDir: string | null = null;
249
- let forkTmpPath: string | null = null;
250
- if (delegationMode === "fork" && forkSessionSnapshotJsonl) {
251
- const tmp = writeForkSessionToTempFile(agentName, forkSessionSnapshotJsonl);
252
- forkTmpDir = tmp.dir;
253
- forkTmpPath = tmp.filePath;
254
- }
255
-
256
193
  const childCtx: SubagentSessionContext = {
257
194
  depth: childDepth,
258
195
  maxDepth,
@@ -284,9 +221,7 @@ export async function runAgentSameProcess(
284
221
  // Thinking level from agent config (same string values as --thinking flag)
285
222
  const thinkingLevel = agent.thinking as any | undefined;
286
223
 
287
- const sessionManager = forkTmpPath
288
- ? SessionManager.open(forkTmpPath)
289
- : SessionManager.inMemory();
224
+ const sessionManager = SessionManager.inMemory();
290
225
 
291
226
  const { session } = await subagentContext.run(childCtx, () =>
292
227
  createAgentSession({
@@ -407,8 +342,6 @@ export async function runAgentSameProcess(
407
342
  result.errorMessage = result.errorMessage ?? msg;
408
343
  if (!result.stderr.trim()) result.stderr = msg;
409
344
  return result;
410
- } finally {
411
- cleanupTempDir(forkTmpDir);
412
345
  }
413
346
  }
414
347
 
@@ -418,8 +351,6 @@ export async function runAgentSameProcess(
418
351
 
419
352
  export async function executeParallelSameProcess(
420
353
  tasks: Array<{ agent: string; task: string; cwd?: string }>,
421
- delegationMode: DelegationMode,
422
- forkSessionSnapshotJsonl: string | undefined,
423
354
  agents: AgentConfig[],
424
355
  defaultCwd: string,
425
356
  depth: number,
@@ -509,8 +440,6 @@ export async function executeParallelSameProcess(
509
440
  agentName: t.agent,
510
441
  task: t.task,
511
442
  taskCwd: t.cwd,
512
- delegationMode,
513
- forkSessionSnapshotJsonl,
514
443
  parentDepth: depth,
515
444
  parentAgentStack: stack,
516
445
  maxDepth,
package/runner.ts CHANGED
@@ -12,12 +12,10 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core";
12
12
  import type { Message } from "@mariozechner/pi-ai";
13
13
  import type { AgentConfig } from "./agents.js";
14
14
  import {
15
- type DelegationMode,
16
15
  type LiveLogEntry,
17
16
  type SingleResult,
18
17
  type SubagentDetails,
19
18
  MAX_LIVE_LOG_ENTRIES,
20
- buildSubagentDetails,
21
19
  emptyUsage,
22
20
  extractToolCalls,
23
21
  getFinalOutput,
@@ -74,17 +72,6 @@ function writePromptToTempFile(
74
72
  return { dir: tmpDir, filePath };
75
73
  }
76
74
 
77
- function writeForkSessionToTempFile(
78
- agentName: string,
79
- sessionJsonl: string,
80
- ): { dir: string; filePath: string } {
81
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
82
- const safeName = agentName.replace(/[^\w.-]+/g, "_");
83
- const filePath = path.join(tmpDir, `fork-${safeName}.jsonl`);
84
- fs.writeFileSync(filePath, sessionJsonl, { encoding: "utf-8", mode: 0o600 });
85
- return { dir: tmpDir, filePath };
86
- }
87
-
88
75
  function cleanupTempDir(dir: string | null): void {
89
76
  if (!dir) return;
90
77
  try {
@@ -363,8 +350,6 @@ function buildPiArgs(
363
350
  agent: AgentConfig,
364
351
  systemPromptPath: string | null,
365
352
  task: string,
366
- delegationMode: DelegationMode,
367
- forkSessionPath: string | null,
368
353
  ): string[] {
369
354
  const args: string[] = [
370
355
  "--mode",
@@ -372,14 +357,9 @@ function buildPiArgs(
372
357
  ..._inheritedCliArgs.extensionArgs,
373
358
  ..._inheritedCliArgs.alwaysProxy,
374
359
  "-p",
360
+ "--no-session",
375
361
  ];
376
362
 
377
- if (delegationMode === "spawn") {
378
- args.push("--no-session");
379
- } else if (forkSessionPath) {
380
- args.push("--session", forkSessionPath);
381
- }
382
-
383
363
  // Agent config takes priority; fall back to parent CLI value
384
364
  const model = agent.model ?? _inheritedCliArgs.fallbackModel;
385
365
  if (model) args.push("--model", model);
@@ -425,10 +405,6 @@ export interface RunAgentOptions {
425
405
  task: string;
426
406
  /** Optional override working directory. */
427
407
  taskCwd?: string;
428
- /** Context mode: spawn (fresh) or fork (session snapshot + task). */
429
- delegationMode: DelegationMode;
430
- /** Serialized parent session snapshot used when delegationMode is "fork". */
431
- forkSessionSnapshotJsonl?: string;
432
408
  /** Current delegation depth of the caller process. */
433
409
  parentDepth: number;
434
410
  /** Delegation stack from the caller process (ancestor agent names). */
@@ -457,8 +433,6 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
457
433
  agentName,
458
434
  task,
459
435
  taskCwd,
460
- delegationMode,
461
- forkSessionSnapshotJsonl,
462
436
  parentDepth,
463
437
  parentAgentStack,
464
438
  maxDepth,
@@ -486,30 +460,6 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
486
460
  };
487
461
  }
488
462
 
489
- if (
490
- delegationMode === "fork" &&
491
- (!forkSessionSnapshotJsonl || !forkSessionSnapshotJsonl.trim())
492
- ) {
493
- return {
494
- agent: agentName,
495
- agentSource: agent.source,
496
- task,
497
- exitCode: 1,
498
- messages: [],
499
- stderr:
500
- "Cannot run in fork mode: missing parent session snapshot context.",
501
- usage: emptyUsage(),
502
- toolCalls: {},
503
- model: agent.model,
504
- stopReason: "error",
505
- errorMessage:
506
- "Cannot run in fork mode: missing parent session snapshot context.",
507
- completedTurns: 0,
508
- turnInProgress: false,
509
- liveLog: [],
510
- };
511
- }
512
-
513
463
  const result: SingleResult = {
514
464
  agent: agentName,
515
465
  agentSource: agent.source,
@@ -548,22 +498,11 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
548
498
  promptTmpPath = tmp.filePath;
549
499
  }
550
500
 
551
- // Write forked session snapshot if needed
552
- let forkSessionTmpDir: string | null = null;
553
- let forkSessionTmpPath: string | null = null;
554
- if (delegationMode === "fork" && forkSessionSnapshotJsonl) {
555
- const tmp = writeForkSessionToTempFile(agent.name, forkSessionSnapshotJsonl);
556
- forkSessionTmpDir = tmp.dir;
557
- forkSessionTmpPath = tmp.filePath;
558
- }
559
-
560
501
  try {
561
502
  const piArgs = buildPiArgs(
562
503
  agent,
563
504
  promptTmpPath,
564
505
  task,
565
- delegationMode,
566
- forkSessionTmpPath,
567
506
  );
568
507
  let wasAborted = false;
569
508
 
@@ -761,7 +700,6 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
761
700
  return result;
762
701
  } finally {
763
702
  cleanupTempDir(promptTmpDir);
764
- cleanupTempDir(forkSessionTmpDir);
765
703
  }
766
704
  }
767
705
 
@@ -774,8 +712,6 @@ export async function runAgentSubprocess(opts: RunAgentOptions): Promise<SingleR
774
712
 
775
713
  export async function executeParallelSubprocess(
776
714
  tasks: Array<{ agent: string; task: string; cwd?: string }>,
777
- delegationMode: DelegationMode,
778
- forkSessionSnapshotJsonl: string | undefined,
779
715
  agents: AgentConfig[],
780
716
  defaultCwd: string,
781
717
  parentDepth: number,
@@ -865,8 +801,6 @@ export async function executeParallelSubprocess(
865
801
  agentName: t.agent,
866
802
  task: t.task,
867
803
  taskCwd: t.cwd,
868
- delegationMode,
869
- forkSessionSnapshotJsonl,
870
804
  parentDepth,
871
805
  parentAgentStack,
872
806
  maxDepth,
package/types.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import type { Message } from "@mariozechner/pi-ai";
6
6
 
7
7
  /** Context mode for delegated runs. */
8
- export type DelegationMode = "spawn" | "fork";
8
+ export type DelegationMode = "spawn";
9
9
 
10
10
  /** Default context mode for delegated runs. */
11
11
  export const DEFAULT_DELEGATION_MODE: DelegationMode = "spawn";
@@ -224,7 +224,7 @@ export function isSubagentDetails(value: unknown): value is SubagentDetails {
224
224
  if (!value || typeof value !== "object") return false;
225
225
  const maybe = value as Partial<SubagentDetails>;
226
226
  return (maybe.mode === "single" || maybe.mode === "parallel") &&
227
- (maybe.delegationMode === "spawn" || maybe.delegationMode === "fork") &&
227
+ maybe.delegationMode === "spawn" &&
228
228
  Array.isArray(maybe.results);
229
229
  }
230
230