pi-subagents 0.20.0 → 0.21.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 +26 -0
- package/README.md +21 -4
- package/agent-management.ts +19 -9
- package/agent-manager-chain-detail.ts +1 -1
- package/agent-manager-detail.ts +2 -0
- package/agent-manager-edit.ts +31 -6
- package/agent-manager-parallel.ts +2 -2
- package/agent-manager.ts +4 -2
- package/agent-serializer.ts +2 -0
- package/agents/context-builder.md +13 -6
- package/agents/delegate.md +2 -0
- package/agents/oracle.md +4 -1
- package/agents/planner.md +5 -1
- package/agents/researcher.md +4 -1
- package/agents/reviewer.md +78 -20
- package/agents/scout.md +5 -2
- package/agents/worker.md +7 -4
- package/agents.ts +29 -7
- package/async-execution.ts +64 -35
- package/async-job-tracker.ts +52 -15
- package/async-status.ts +107 -14
- package/chain-clarify.ts +1 -1
- package/chain-execution.ts +10 -2
- package/completion-dedupe.ts +1 -1
- package/completion-guard.ts +125 -0
- package/doctor.ts +1 -1
- package/execution.ts +158 -26
- package/fork-context.ts +3 -3
- package/index.ts +17 -6
- package/intercom-bridge.ts +2 -1
- package/jsonl-writer.ts +2 -2
- package/long-running-guard.ts +175 -0
- package/model-fallback.ts +1 -1
- package/package.json +1 -1
- package/pi-args.ts +4 -2
- package/pi-spawn.ts +1 -1
- package/prompt-template-bridge.ts +9 -9
- package/prompts/parallel-cleanup.md +39 -8
- package/render.ts +239 -49
- package/result-intercom.ts +5 -5
- package/result-watcher.ts +21 -12
- package/run-status.ts +1 -1
- package/schemas.ts +24 -13
- package/session-tokens.ts +2 -6
- package/settings.ts +2 -2
- package/single-output.ts +1 -1
- package/skills/pi-subagents/SKILL.md +93 -20
- package/skills.ts +8 -2
- package/slash-bridge.ts +3 -3
- package/subagent-control.ts +103 -21
- package/subagent-executor.ts +82 -25
- package/subagent-prompt-runtime.ts +80 -3
- package/subagent-runner.ts +339 -93
- package/subagents-status.ts +9 -7
- package/text-editor.ts +22 -6
- package/top-level-async.ts +1 -1
- package/types.ts +63 -8
- package/utils.ts +3 -3
- package/worktree.ts +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.21.0] - 2026-04-29
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Document the recommended parent-agent workflow as `clarify → planner → worker → fresh reviewers → worker` in the docs and bundled skill.
|
|
9
|
+
- Packaged `planner`, `worker`, and `oracle` now default to forked session context when the launch omits `context`; explicit `context: "fresh"` still overrides the agent default.
|
|
10
|
+
- Expanded builtin subagent guidance so agents with a safe pi-intercom target can hand results back with blocking `intercom ask`, documented the self-orchestrated clarify → plan → implement → review workflow, and added GPT-5.5-oriented subagent prompt guidance to the bundled skill and `context-builder`.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Prevent child subagents from receiving parent orchestration tooling/history, and inject boundary instructions that forbid sub-delegation and pseudo tool calls.
|
|
14
|
+
- Added active-long-running and repeated mutating-tool failure notices so supervised/forked workers cannot burn turns silently while still appearing healthy.
|
|
15
|
+
- Fixed task editor wrapping so wide characters cannot push text past the right border.
|
|
16
|
+
- Mark implementation subagents as failed when they complete without any file mutation attempt.
|
|
17
|
+
- Applied the same no-mutation completion guard to async/background runner paths.
|
|
18
|
+
- Split terminal no-mutation guard notices from live idle notices so completed failures do not suggest status or interrupt commands.
|
|
19
|
+
- Clarified worker/intercom bridge instructions so blocked decisions use `intercom ask` and stay alive for the reply instead of completing with a question.
|
|
20
|
+
- Labeled the Agents widget as async/background work so running detached agents are easier to identify.
|
|
21
|
+
- Reworked parallel progress wording so parallel runs show running/done agent counts (and chain parallel groups show `step X/Y · parallel group` with agent fractions) instead of serial `step X/Y` counters.
|
|
22
|
+
- Expanded `/parallel-cleanup` guidance to flag redundant wrapper tests when one focused regression is enough.
|
|
23
|
+
- Fixed flexible schema validation for `reads` and `skill` overrides so `reads: false`, `skill: "review"`, and `skill: false` no longer trigger `element.reads.every is not a function` (issue #124).
|
|
24
|
+
- Hardened slash-result and async-widget animation timers so stale extension contexts after `/new` or reload stop their timers instead of crashing on `ctx.ui` access (issue #122).
|
|
25
|
+
|
|
26
|
+
## [0.20.1] - 2026-04-27
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Made the packaged `/parallel-cleanup` prompt self-contained instead of referencing local-only cleanup skills.
|
|
30
|
+
|
|
5
31
|
## [0.20.0] - 2026-04-27
|
|
6
32
|
|
|
7
33
|
### Added
|
package/README.md
CHANGED
|
@@ -174,6 +174,20 @@ or ask:
|
|
|
174
174
|
Check whether subagents and intercom are set up correctly.
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
+
## Recommended orchestration pattern (scaffolding)
|
|
178
|
+
|
|
179
|
+
Use orchestration as parent-agent guidance, not as a runtime workflow mode. For implementation work, the recommended loop is:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
clarify → planner → worker → fresh reviewers → worker
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Use the optional prompt shortcuts below when you want the pattern to be repeatable.
|
|
186
|
+
|
|
187
|
+
Packaged `planner`, `worker`, and `oracle` default to forked context when a launch omits `context`; pass `context: "fresh"` when you intentionally want a fresh child run.
|
|
188
|
+
|
|
189
|
+
Child-safety boundaries are enforced at runtime. Spawned child sessions do not register the `subagent` tool, do not receive the bundled `pi-subagents` skill, and receive explicit boundary instructions that they are not the parent orchestrator and must not propose or run subagents. Forked child context filtering also removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
|
|
190
|
+
|
|
177
191
|
## Optional shortcuts
|
|
178
192
|
|
|
179
193
|
The package includes reusable prompt templates for common workflows. You do not need them, but they are handy when you want the same shape every time:
|
|
@@ -183,6 +197,7 @@ The package includes reusable prompt templates for common workflows. You do not
|
|
|
183
197
|
| `/parallel-review` | Launch fresh-context reviewers with distinct angles, then synthesize what to fix. |
|
|
184
198
|
| `/parallel-research` | Combine `researcher` and `scout` for external evidence, local code context, and practical tradeoffs. |
|
|
185
199
|
| `/gather-context-and-clarify` | Scout/research first, then ask the user the clarification questions that matter. |
|
|
200
|
+
| `/parallel-cleanup` | Run review-only cleanup passes after implementation. |
|
|
186
201
|
|
|
187
202
|
## Optional pi-intercom companion
|
|
188
203
|
|
|
@@ -237,7 +252,7 @@ Skip this section until you want exact syntax.
|
|
|
237
252
|
| `/subagents-status` | Open the active/recent run overlay |
|
|
238
253
|
| `/subagents-doctor` | Show read-only setup diagnostics |
|
|
239
254
|
|
|
240
|
-
Commands validate agent names locally, support tab completion, and
|
|
255
|
+
Commands validate agent names locally, support tab completion, and send results back into the conversation.
|
|
241
256
|
|
|
242
257
|
### Per-step tasks
|
|
243
258
|
|
|
@@ -413,7 +428,7 @@ Example:
|
|
|
413
428
|
}
|
|
414
429
|
```
|
|
415
430
|
|
|
416
|
-
Supported override fields are `model`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `disabled`, `skills`, `tools`, and `systemPrompt`. Project overrides beat user overrides.
|
|
431
|
+
Supported override fields are `model`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`, `disabled`, `skills`, `tools`, and `systemPrompt`. Use `defaultContext: false` in builtin overrides to clear an inherited context default. Project overrides beat user overrides.
|
|
417
432
|
|
|
418
433
|
You can also manage builtin overrides from `/agents`. On a builtin detail screen, press `e`, choose user or project scope if needed, and save the fields you want to override.
|
|
419
434
|
|
|
@@ -430,6 +445,7 @@ Use these fields when an agent should see more:
|
|
|
430
445
|
| `systemPromptMode: append` | Append the agent prompt to Pi’s normal base prompt. |
|
|
431
446
|
| `inheritProjectContext: true` | Keep inherited project instructions from files like `AGENTS.md` and `CLAUDE.md`. |
|
|
432
447
|
| `inheritSkills: true` | Let the child see Pi’s discovered skills catalog. |
|
|
448
|
+
| `defaultContext: fork` | Use forked session context when a launch omits `context`; explicit `context: "fresh"` still wins. |
|
|
433
449
|
|
|
434
450
|
Builtin agents opt into project instruction inheritance by default so they follow repo-specific rules out of the box. `delegate` also uses append mode because its job is orchestration inside the parent workflow.
|
|
435
451
|
|
|
@@ -472,6 +488,7 @@ Important fields:
|
|
|
472
488
|
| `systemPromptMode` | `replace` by default; `append` keeps Pi’s base prompt. |
|
|
473
489
|
| `inheritProjectContext` | Keeps or strips inherited project instruction blocks. |
|
|
474
490
|
| `inheritSkills` | Keeps or strips Pi’s discovered skills catalog. |
|
|
491
|
+
| `defaultContext` | Optional `fresh` or `fork` launch context default for this agent. |
|
|
475
492
|
| `skills` | Injects specific skills directly, regardless of `inheritSkills`. |
|
|
476
493
|
| `output` | Default single-agent output file. |
|
|
477
494
|
| `defaultReads` | Files to read before running in chain/parallel behavior. |
|
|
@@ -712,7 +729,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
712
729
|
| `concurrency` | number | config or `4` | Top-level parallel concurrency. |
|
|
713
730
|
| `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
|
|
714
731
|
| `chain` | array | - | Sequential and parallel chain steps. |
|
|
715
|
-
| `context` | `fresh \| fork` | `fresh` | `fork` creates real branched sessions from the parent leaf. |
|
|
732
|
+
| `context` | `fresh \| fork` | agent default or `fresh` | `fork` creates real branched sessions from the parent leaf. Packaged `planner`, `worker`, and `oracle` default to `fork`. |
|
|
716
733
|
| `chainDir` | string | temp chain dir | Persistent directory for chain artifacts. |
|
|
717
734
|
| `clarify` | boolean | true for chains | Show TUI preview/edit flow. |
|
|
718
735
|
| `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
|
|
@@ -724,7 +741,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
724
741
|
| `share` | boolean | false | Upload session export to GitHub Gist. |
|
|
725
742
|
| `sessionDir` | string | derived | Override session log directory. |
|
|
726
743
|
|
|
727
|
-
`context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. It never silently downgrades to `fresh`.
|
|
744
|
+
`context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. It never silently downgrades to `fresh`. In multi-agent runs, if any requested agent has `defaultContext: fork` and the launch omits `context`, the whole invocation uses forked context; pass `context: "fresh"` when you intentionally want a fresh run.
|
|
728
745
|
|
|
729
746
|
Sequential and parallel chain tasks accept `agent`, `task`, `cwd`, `output`, `reads`, `progress`, `skill`, and `model`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`.
|
|
730
747
|
|
package/agent-management.ts
CHANGED
|
@@ -67,7 +67,7 @@ function normalizeListScope(scope: unknown): AgentScope | undefined {
|
|
|
67
67
|
return undefined;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
function sanitizeName(name: string): string {
|
|
71
71
|
return name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -81,7 +81,7 @@ function availableNames(cwd: string, kind: "agent" | "chain"): string[] {
|
|
|
81
81
|
return [...new Set(items.map((x) => x.name))].sort((a, b) => a.localeCompare(b));
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
function findAgents(name: string, cwd: string, scope: AgentScope = "both"): AgentConfig[] {
|
|
85
85
|
const d = discoverAgentsAll(cwd);
|
|
86
86
|
const raw = name.trim();
|
|
87
87
|
const sanitized = sanitizeName(raw);
|
|
@@ -90,7 +90,7 @@ export function findAgents(name: string, cwd: string, scope: AgentScope = "both"
|
|
|
90
90
|
.sort((a, b) => a.source.localeCompare(b.source));
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
function findChains(name: string, cwd: string, scope: AgentScope = "both"): ChainConfig[] {
|
|
94
94
|
const raw = name.trim();
|
|
95
95
|
const sanitized = sanitizeName(raw);
|
|
96
96
|
return discoverAgentsAll(cwd).chains
|
|
@@ -259,6 +259,11 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
|
|
|
259
259
|
if (typeof cfg.inheritSkills !== "boolean") return "config.inheritSkills must be a boolean when provided.";
|
|
260
260
|
target.inheritSkills = cfg.inheritSkills;
|
|
261
261
|
}
|
|
262
|
+
if (hasKey(cfg, "defaultContext")) {
|
|
263
|
+
if (cfg.defaultContext === false || cfg.defaultContext === "") target.defaultContext = undefined;
|
|
264
|
+
else if (cfg.defaultContext === "fresh" || cfg.defaultContext === "fork") target.defaultContext = cfg.defaultContext;
|
|
265
|
+
else return "config.defaultContext must be 'fresh', 'fork', or false when provided.";
|
|
266
|
+
}
|
|
262
267
|
if (hasKey(cfg, "output")) {
|
|
263
268
|
if (cfg.output === false || cfg.output === "") target.output = undefined;
|
|
264
269
|
else if (typeof cfg.output === "string") target.output = cfg.output;
|
|
@@ -328,7 +333,7 @@ function renamePath(
|
|
|
328
333
|
return { filePath };
|
|
329
334
|
}
|
|
330
335
|
|
|
331
|
-
|
|
336
|
+
function formatAgentDetail(agent: AgentConfig): string {
|
|
332
337
|
const tools = [...(agent.tools ?? []), ...(agent.mcpDirectTools ?? []).map((t) => `mcp:${t}`)];
|
|
333
338
|
const lines: string[] = [`Agent: ${agent.name} (${agent.source})`, `Path: ${agent.filePath}`, `Description: ${agent.description}`];
|
|
334
339
|
if (agent.model) lines.push(`Model: ${agent.model}`);
|
|
@@ -338,6 +343,7 @@ export function formatAgentDetail(agent: AgentConfig): string {
|
|
|
338
343
|
lines.push(`System prompt mode: ${agent.systemPromptMode}`);
|
|
339
344
|
lines.push(`Inherit project context: ${agent.inheritProjectContext ? "true" : "false"}`);
|
|
340
345
|
lines.push(`Inherit skills: ${agent.inheritSkills ? "true" : "false"}`);
|
|
346
|
+
if (agent.defaultContext) lines.push(`Default context: ${agent.defaultContext}`);
|
|
341
347
|
if (agent.source === "builtin") lines.push(`Disabled: ${agent.disabled ? "true" : "false"}`);
|
|
342
348
|
if (agent.extensions !== undefined) lines.push(`Extensions: ${agent.extensions.length ? agent.extensions.join(", ") : "(none)"}`);
|
|
343
349
|
if (agent.thinking) lines.push(`Thinking: ${agent.thinking}`);
|
|
@@ -349,7 +355,7 @@ export function formatAgentDetail(agent: AgentConfig): string {
|
|
|
349
355
|
return lines.join("\n");
|
|
350
356
|
}
|
|
351
357
|
|
|
352
|
-
|
|
358
|
+
function formatChainDetail(chain: ChainConfig): string {
|
|
353
359
|
const lines: string[] = [`Chain: ${chain.name} (${chain.source})`, `Path: ${chain.filePath}`, `Description: ${chain.description}`, "", "Steps:"];
|
|
354
360
|
for (let i = 0; i < chain.steps.length; i++) {
|
|
355
361
|
const s = chain.steps[i]!;
|
|
@@ -376,8 +382,12 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
376
382
|
const chains = d.chains.filter((c) => scope === "both" || c.source === scope).sort((a, b) => a.name.localeCompare(b.name));
|
|
377
383
|
const lines = [
|
|
378
384
|
"Executable agents:",
|
|
379
|
-
...(agents.length
|
|
380
|
-
|
|
385
|
+
...(agents.length
|
|
386
|
+
? agents.map((a) => `- ${a.name} (${a.source}${a.defaultContext ? `, context: ${a.defaultContext}` : ""}): ${a.description}`)
|
|
387
|
+
: ["- (none)"]),
|
|
388
|
+
...(disabledBuiltins.length
|
|
389
|
+
? ["", "Disabled builtins:", ...disabledBuiltins.map((a) => `- ${a.name} (${a.source}${a.defaultContext ? `, context: ${a.defaultContext}` : ""}, disabled): ${a.description}`)]
|
|
390
|
+
: []),
|
|
381
391
|
"",
|
|
382
392
|
"Chains:",
|
|
383
393
|
...(chains.length ? chains.map((c) => `- ${c.name} (${c.source}): ${c.description}`) : ["- (none)"]),
|
|
@@ -385,7 +395,7 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
385
395
|
return result(lines.join("\n"));
|
|
386
396
|
}
|
|
387
397
|
|
|
388
|
-
|
|
398
|
+
function handleGet(params: ManagementParams, ctx: ManagementContext): AgentToolResult<Details> {
|
|
389
399
|
if (!params.agent && !params.chainName) return result("Specify 'agent' or 'chainName' for get.", true);
|
|
390
400
|
const hasBoth = Boolean(params.agent && params.chainName);
|
|
391
401
|
const blocks: string[] = [];
|
|
@@ -560,7 +570,7 @@ export function handleUpdate(params: ManagementParams, ctx: ManagementContext):
|
|
|
560
570
|
return result([headline, ...warnings].join("\n"));
|
|
561
571
|
}
|
|
562
572
|
|
|
563
|
-
|
|
573
|
+
function handleDelete(params: ManagementParams, ctx: ManagementContext): AgentToolResult<Details> {
|
|
564
574
|
if (!params.agent && !params.chainName) return result("Specify 'agent' or 'chainName' for delete.", true);
|
|
565
575
|
if (params.agent && params.chainName) return result("Specify either 'agent' or 'chainName', not both.", true);
|
|
566
576
|
const scopeHint = asDisambiguationScope(params.agentScope);
|
|
@@ -17,7 +17,7 @@ const CHAIN_DETAIL_VIEWPORT_HEIGHT = 12;
|
|
|
17
17
|
|
|
18
18
|
type DetailChainStep = ChainStepConfig | ChainStep;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
function buildDependencyMap(steps: DetailChainStep[]): Map<number, number[]> {
|
|
21
21
|
const outputMap = new Map<string, number>();
|
|
22
22
|
const deps = new Map<number, number[]>();
|
|
23
23
|
for (let i = 0; i < steps.length; i++) {
|
package/agent-manager-detail.ts
CHANGED
|
@@ -58,12 +58,14 @@ function buildDetailLines(
|
|
|
58
58
|
const output = agent.output ?? "(none)";
|
|
59
59
|
const reads = agent.defaultReads && agent.defaultReads.length > 0 ? agent.defaultReads.join(", ") : "(none)";
|
|
60
60
|
const progress = agent.defaultProgress ? "on" : "off";
|
|
61
|
+
const defaultContext = agent.defaultContext ?? "auto";
|
|
61
62
|
const maxSubagentDepth = agent.maxSubagentDepth !== undefined ? String(agent.maxSubagentDepth) : "(default)";
|
|
62
63
|
|
|
63
64
|
lines.push(renderFieldLine("Model:", agent.model ?? "default", contentWidth, theme));
|
|
64
65
|
lines.push(renderFieldLine("Prompt mode:", agent.systemPromptMode, contentWidth, theme));
|
|
65
66
|
lines.push(renderFieldLine("Project ctx:", agent.inheritProjectContext ? "on" : "off", contentWidth, theme));
|
|
66
67
|
lines.push(renderFieldLine("Skills ctx:", agent.inheritSkills ? "on" : "off", contentWidth, theme));
|
|
68
|
+
lines.push(renderFieldLine("Run context:", defaultContext, contentWidth, theme));
|
|
67
69
|
if (agent.source === "builtin") {
|
|
68
70
|
lines.push(renderFieldLine("Disabled:", agent.disabled ? "on" : "off", contentWidth, theme));
|
|
69
71
|
}
|
package/agent-manager-edit.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
|
|
3
|
-
import { defaultSystemPromptMode, type AgentConfig, type BuiltinAgentOverrideBase } from "./agents.ts";
|
|
3
|
+
import { defaultSystemPromptMode, type AgentConfig, type AgentDefaultContext, type BuiltinAgentOverrideBase } from "./agents.ts";
|
|
4
4
|
import { createEditorState, ensureCursorVisible, getCursorDisplayPos, handleEditorInput, renderEditor, wrapText } from "./text-editor.ts";
|
|
5
5
|
import type { TextEditorState } from "./text-editor.ts";
|
|
6
6
|
import { pad, row, renderHeader, renderFooter, formatScrollInfo } from "./render-helpers.ts";
|
|
@@ -18,15 +18,15 @@ export interface EditState {
|
|
|
18
18
|
title?: string;
|
|
19
19
|
overrideBase?: BuiltinAgentOverrideBase;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
interface EditInputResult { action?: "save" | "discard" | "delete"; nextScreen?: EditScreen; }
|
|
22
|
+
interface CreateEditStateOptions {
|
|
23
23
|
fields?: EditField[];
|
|
24
24
|
title?: string;
|
|
25
25
|
overrideBase?: BuiltinAgentOverrideBase;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
29
|
-
const FIELD_ORDER = ["name", "description", "model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "tools", "extensions", "skills", "output", "reads", "progress", "interactive", "prompt"] as const;
|
|
29
|
+
const FIELD_ORDER = ["name", "description", "model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "defaultContext", "tools", "extensions", "skills", "output", "reads", "progress", "interactive", "prompt"] as const;
|
|
30
30
|
type ThinkingLevel = typeof THINKING_LEVELS[number];
|
|
31
31
|
const PROMPT_VIEWPORT_HEIGHT = 16;
|
|
32
32
|
const MODEL_SELECTOR_HEIGHT = 10;
|
|
@@ -38,6 +38,12 @@ function parseTools(value: string): { tools?: string[]; mcp?: string[] } { const
|
|
|
38
38
|
function parseCommaList(value: string): string[] | undefined { const items = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0); return items.length > 0 ? items : undefined; }
|
|
39
39
|
function arraysEqual(a: string[] | undefined, b: string[] | undefined): boolean { if (!a && !b) return true; if (!a || !b || a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false; return true; }
|
|
40
40
|
|
|
41
|
+
function nextDefaultContext(value: AgentDefaultContext | undefined): AgentDefaultContext | undefined {
|
|
42
|
+
if (value === undefined) return "fork";
|
|
43
|
+
if (value === "fork") return "fresh";
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
function fieldValueMatchesBase(field: EditField, state: EditState): boolean {
|
|
42
48
|
const base = state.overrideBase;
|
|
43
49
|
if (!base) return false;
|
|
@@ -48,6 +54,7 @@ function fieldValueMatchesBase(field: EditField, state: EditState): boolean {
|
|
|
48
54
|
case "systemPromptMode": return state.draft.systemPromptMode === base.systemPromptMode;
|
|
49
55
|
case "inheritProjectContext": return state.draft.inheritProjectContext === base.inheritProjectContext;
|
|
50
56
|
case "inheritSkills": return state.draft.inheritSkills === base.inheritSkills;
|
|
57
|
+
case "defaultContext": return state.draft.defaultContext === base.defaultContext;
|
|
51
58
|
case "disabled": return state.draft.disabled === base.disabled;
|
|
52
59
|
case "tools": return arraysEqual(toolList(state.draft), toolList(base));
|
|
53
60
|
case "skills": return arraysEqual(state.draft.skills, base.skills);
|
|
@@ -66,6 +73,7 @@ function resetFieldToBase(field: EditField, state: EditState): void {
|
|
|
66
73
|
case "systemPromptMode": state.draft.systemPromptMode = base.systemPromptMode; break;
|
|
67
74
|
case "inheritProjectContext": state.draft.inheritProjectContext = base.inheritProjectContext; break;
|
|
68
75
|
case "inheritSkills": state.draft.inheritSkills = base.inheritSkills; break;
|
|
76
|
+
case "defaultContext": state.draft.defaultContext = base.defaultContext; break;
|
|
69
77
|
case "disabled": state.draft.disabled = base.disabled; break;
|
|
70
78
|
case "tools": state.draft.tools = base.tools ? [...base.tools] : undefined; state.draft.mcpDirectTools = base.mcpDirectTools ? [...base.mcpDirectTools] : undefined; break;
|
|
71
79
|
case "skills": state.draft.skills = base.skills ? [...base.skills] : undefined; break;
|
|
@@ -94,6 +102,7 @@ function renderFieldValue(field: EditField, state: EditState): string {
|
|
|
94
102
|
case "systemPromptMode": return draft.systemPromptMode ?? defaultSystemPromptMode(draft.name);
|
|
95
103
|
case "inheritProjectContext": return draft.inheritProjectContext ? "on" : "off";
|
|
96
104
|
case "inheritSkills": return draft.inheritSkills ? "on" : "off";
|
|
105
|
+
case "defaultContext": return draft.defaultContext ?? "auto";
|
|
97
106
|
case "disabled": return draft.disabled ? "on" : "off";
|
|
98
107
|
case "tools": return formatTools(draft);
|
|
99
108
|
case "extensions": return draft.extensions !== undefined ? (draft.extensions.length > 0 ? draft.extensions.join(", ") : "") : "(all)";
|
|
@@ -129,6 +138,15 @@ function applyFieldValue(field: EditField, state: EditState, value: string): voi
|
|
|
129
138
|
case "skills": draft.skills = parseCommaList(value); break;
|
|
130
139
|
case "output": { const trimmed = value.trim(); draft.output = trimmed.length > 0 ? trimmed : undefined; break; }
|
|
131
140
|
case "reads": draft.defaultReads = parseCommaList(value); break;
|
|
141
|
+
case "defaultContext": {
|
|
142
|
+
const trimmed = value.trim();
|
|
143
|
+
if (trimmed === "" || trimmed === "auto") {
|
|
144
|
+
draft.defaultContext = undefined;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
if (trimmed === "fresh" || trimmed === "fork") draft.defaultContext = trimmed;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
132
150
|
case "inheritProjectContext":
|
|
133
151
|
case "inheritSkills":
|
|
134
152
|
case "disabled":
|
|
@@ -260,9 +278,10 @@ export function handleEditInput(screen: EditScreen, state: EditState, data: stri
|
|
|
260
278
|
if (data === "m") { openModelPicker(state, models); return { nextScreen: "edit-field" }; }
|
|
261
279
|
if (data === "t") { openThinkingPicker(state); return { nextScreen: "edit-field" }; }
|
|
262
280
|
if (data === "s") { openSkillPicker(state, skills); return { nextScreen: "edit-field" }; }
|
|
263
|
-
if (data === " " && (field === "inheritProjectContext" || field === "inheritSkills" || field === "disabled" || field === "progress" || field === "interactive")) {
|
|
281
|
+
if (data === " " && (field === "inheritProjectContext" || field === "inheritSkills" || field === "defaultContext" || field === "disabled" || field === "progress" || field === "interactive")) {
|
|
264
282
|
if (field === "inheritProjectContext") state.draft.inheritProjectContext = !state.draft.inheritProjectContext;
|
|
265
283
|
if (field === "inheritSkills") state.draft.inheritSkills = !state.draft.inheritSkills;
|
|
284
|
+
if (field === "defaultContext") state.draft.defaultContext = nextDefaultContext(state.draft.defaultContext);
|
|
266
285
|
if (field === "disabled") state.draft.disabled = !state.draft.disabled;
|
|
267
286
|
if (field === "progress") state.draft.defaultProgress = !state.draft.defaultProgress;
|
|
268
287
|
if (field === "interactive") state.draft.interactive = !state.draft.interactive;
|
|
@@ -273,6 +292,10 @@ export function handleEditInput(screen: EditScreen, state: EditState, data: stri
|
|
|
273
292
|
if (field === "thinking") { openThinkingPicker(state); return { nextScreen: "edit-field" }; }
|
|
274
293
|
if (field === "skills") { openSkillPicker(state, skills); return { nextScreen: "edit-field" }; }
|
|
275
294
|
if (field === "prompt") { state.promptEditor = createEditorState(state.draft.systemPrompt ?? ""); return { nextScreen: "edit-prompt" }; }
|
|
295
|
+
if (field === "defaultContext") {
|
|
296
|
+
state.draft.defaultContext = nextDefaultContext(state.draft.defaultContext);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
276
299
|
if (field === "inheritProjectContext" || field === "inheritSkills" || field === "disabled" || field === "progress" || field === "interactive") return;
|
|
277
300
|
state.fieldMode = "text"; state.fieldEditor = createEditorState(renderFieldValue(field, state)); return { nextScreen: "edit-field" };
|
|
278
301
|
}
|
|
@@ -346,7 +369,9 @@ export function renderEdit(screen: EditScreen, state: EditState, width: number,
|
|
|
346
369
|
? "Project Ctx"
|
|
347
370
|
: field === "inheritSkills"
|
|
348
371
|
? "Skills Ctx"
|
|
349
|
-
: field === "
|
|
372
|
+
: field === "defaultContext"
|
|
373
|
+
? "Default Ctx"
|
|
374
|
+
: field === "disabled"
|
|
350
375
|
? "Disabled"
|
|
351
376
|
: `${field[0]!.toUpperCase()}${field.slice(1)}`;
|
|
352
377
|
const rawLabel = pad(`${fieldLabel}:`, labelWidth);
|
|
@@ -4,7 +4,7 @@ import type { TextEditorState } from "./text-editor.ts";
|
|
|
4
4
|
import { createEditorState, handleEditorInput, renderEditor, wrapText, getCursorDisplayPos, ensureCursorVisible } from "./text-editor.ts";
|
|
5
5
|
import { pad, row, renderHeader, renderFooter, fuzzyFilter } from "./render-helpers.ts";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
interface ParallelSlot {
|
|
8
8
|
agentName: string;
|
|
9
9
|
customTask: string;
|
|
10
10
|
}
|
|
@@ -20,7 +20,7 @@ export interface ParallelState {
|
|
|
20
20
|
editEditor: TextEditorState | null;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
type ParallelAction =
|
|
24
24
|
| { type: "proceed" }
|
|
25
25
|
| { type: "back" };
|
|
26
26
|
|
package/agent-manager.ts
CHANGED
|
@@ -44,7 +44,7 @@ interface NameInputState { mode: "new-agent" | "clone-agent" | "clone-chain" | "
|
|
|
44
44
|
interface StatusMessage { text: string; type: "error" | "info"; }
|
|
45
45
|
interface OverrideScopeState { selectedScope: "user" | "project"; allowProject: boolean; }
|
|
46
46
|
|
|
47
|
-
const BUILTIN_OVERRIDE_FIELDS: EditField[] = ["model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "disabled", "tools", "skills", "prompt"];
|
|
47
|
+
const BUILTIN_OVERRIDE_FIELDS: EditField[] = ["model", "fallbackModels", "thinking", "systemPromptMode", "inheritProjectContext", "inheritSkills", "defaultContext", "disabled", "tools", "skills", "prompt"];
|
|
48
48
|
|
|
49
49
|
function cloneConfig(config: AgentConfig): AgentConfig {
|
|
50
50
|
return {
|
|
@@ -61,6 +61,7 @@ function cloneConfig(config: AgentConfig): AgentConfig {
|
|
|
61
61
|
base: {
|
|
62
62
|
...config.override.base,
|
|
63
63
|
disabled: config.override.base.disabled,
|
|
64
|
+
defaultContext: config.override.base.defaultContext,
|
|
64
65
|
fallbackModels: config.override.base.fallbackModels ? [...config.override.base.fallbackModels] : undefined,
|
|
65
66
|
skills: config.override.base.skills ? [...config.override.base.skills] : undefined,
|
|
66
67
|
tools: config.override.base.tools ? [...config.override.base.tools] : undefined,
|
|
@@ -162,6 +163,7 @@ export class AgentManagerComponent implements Component {
|
|
|
162
163
|
systemPromptMode: entry.config.systemPromptMode,
|
|
163
164
|
inheritProjectContext: entry.config.inheritProjectContext,
|
|
164
165
|
inheritSkills: entry.config.inheritSkills,
|
|
166
|
+
defaultContext: entry.config.defaultContext,
|
|
165
167
|
disabled: entry.config.disabled,
|
|
166
168
|
systemPrompt: entry.config.systemPrompt,
|
|
167
169
|
skills: entry.config.skills ? [...entry.config.skills] : undefined,
|
|
@@ -667,7 +669,7 @@ export class AgentManagerComponent implements Component {
|
|
|
667
669
|
}
|
|
668
670
|
|
|
669
671
|
render(width: number): string[] {
|
|
670
|
-
this.overlayWidth =
|
|
672
|
+
this.overlayWidth = width; const w = this.overlayWidth;
|
|
671
673
|
switch (this.screen) {
|
|
672
674
|
case "list": return renderList(this.listState, this.listAgents(), w, this.theme, this.statusMessage);
|
|
673
675
|
case "template-select": return this.renderTemplateSelect(w);
|
package/agent-serializer.ts
CHANGED
|
@@ -11,6 +11,7 @@ export const KNOWN_FIELDS = new Set([
|
|
|
11
11
|
"systemPromptMode",
|
|
12
12
|
"inheritProjectContext",
|
|
13
13
|
"inheritSkills",
|
|
14
|
+
"defaultContext",
|
|
14
15
|
"skill",
|
|
15
16
|
"skills",
|
|
16
17
|
"extensions",
|
|
@@ -46,6 +47,7 @@ export function serializeAgent(config: AgentConfig): string {
|
|
|
46
47
|
lines.push(`systemPromptMode: ${config.systemPromptMode}`);
|
|
47
48
|
lines.push(`inheritProjectContext: ${config.inheritProjectContext ? "true" : "false"}`);
|
|
48
49
|
lines.push(`inheritSkills: ${config.inheritSkills ? "true" : "false"}`);
|
|
50
|
+
if (config.defaultContext) lines.push(`defaultContext: ${config.defaultContext}`);
|
|
49
51
|
|
|
50
52
|
const skillsValue = joinComma(config.skills);
|
|
51
53
|
if (skillsValue) lines.push(`skills: ${skillsValue}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-builder
|
|
3
3
|
description: Analyzes requirements and codebase, generates context and meta-prompt
|
|
4
|
-
tools: read, grep, find, ls, bash, write, web_search
|
|
4
|
+
tools: read, grep, find, ls, bash, write, web_search, intercom
|
|
5
5
|
model: openai-codex/gpt-5.5
|
|
6
6
|
thinking: medium
|
|
7
7
|
systemPromptMode: replace
|
|
@@ -12,7 +12,7 @@ output: context.md
|
|
|
12
12
|
|
|
13
13
|
You are a requirements-to-context subagent.
|
|
14
14
|
|
|
15
|
-
Analyze the user request against the codebase, gather the minimum high-value context, and produce structured handoff material for planning.
|
|
15
|
+
Analyze the user request against the codebase, gather the minimum high-value context, and produce structured handoff material for planning and GPT-5.5 subagent prompts.
|
|
16
16
|
|
|
17
17
|
Working rules:
|
|
18
18
|
- Read the request carefully before touching the codebase.
|
|
@@ -29,9 +29,16 @@ When running in a chain, expect to generate two files in the chain directory:
|
|
|
29
29
|
- dependencies, constraints, and implementation risks
|
|
30
30
|
|
|
31
31
|
`meta-prompt.md`
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
32
|
+
- goal: the concrete outcome the next agent should produce
|
|
33
|
+
- context/evidence: relevant files, diffs, decisions, constraints, and source-backed facts
|
|
34
|
+
- success criteria: what must be true before the next agent can finish
|
|
35
|
+
- hard constraints: true invariants only, such as no edits for review-only work or escalation for unapproved decisions
|
|
36
|
+
- suggested approach: concise direction without over-specifying every step
|
|
37
|
+
- validation: targeted checks to run, or the next-best check if validation is unavailable
|
|
38
|
+
- stop/escalation rules: when to ask via `intercom`, when enough evidence is enough, and when to stop
|
|
35
39
|
- resolved questions and assumptions
|
|
36
40
|
|
|
37
|
-
The goal is to hand the planner exactly enough code and requirement context to
|
|
41
|
+
The goal is to hand the planner or another GPT-5.5 subagent exactly enough code and requirement context to act without rediscovering the same ground. Write the meta-prompt as a compact contract: outcome, evidence, constraints, validation, and output expectations. Avoid long procedural scripts unless each step is a real requirement.
|
|
42
|
+
|
|
43
|
+
## Pi-intercom handoff
|
|
44
|
+
If `intercom` is available and runtime bridge instructions or the task name a safe orchestrator target, send your completed context summary back with a blocking `intercom({ action: "ask", ... })` before finishing. Keep the message concise, include the output path, and ask whether the orchestrator wants clarification or deeper context. If no safe target is available, do not guess; return normally.
|
package/agents/delegate.md
CHANGED
|
@@ -7,3 +7,5 @@ inheritSkills: false
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are a delegated agent. Execute the assigned task using the provided tools. Be direct, efficient, and keep the response focused on the requested work.
|
|
10
|
+
|
|
11
|
+
If `intercom` is available and runtime bridge instructions or the task name a safe orchestrator target, send your completed result back with a blocking `intercom({ action: "ask", ... })` before finishing. Stay alive for the reply so you can clarify or do a small follow-up if asked. If no safe target is available, do not guess; return normally.
|
package/agents/oracle.md
CHANGED
|
@@ -7,6 +7,7 @@ thinking: high
|
|
|
7
7
|
systemPromptMode: replace
|
|
8
8
|
inheritProjectContext: true
|
|
9
9
|
inheritSkills: false
|
|
10
|
+
defaultContext: fork
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
You are the oracle: a high-context decision-consistency subagent.
|
|
@@ -17,7 +18,9 @@ Before you do anything else, reconstruct the key inherited decisions, constraint
|
|
|
17
18
|
|
|
18
19
|
If you need clarification from the main agent, use `intercom`. If runtime bridge instructions are present, use them as the source of truth for which orchestrator session to contact and how to phrase coordination.
|
|
19
20
|
|
|
20
|
-
Use `intercom({ action: "ask", ... })` when you need a real decision or clarification. Use `intercom({ action: "send", ... })` only for concise updates when blocked, explicitly asked for progress, or when a recommendation or concern would benefit from immediate discussion. Keep intercom traffic tight and purposeful. Do not narrate your whole review through intercom
|
|
21
|
+
Use `intercom({ action: "ask", ... })` when you need a real decision or clarification. Use `intercom({ action: "send", ... })` only for concise updates when blocked, explicitly asked for progress, or when a recommendation or concern would benefit from immediate discussion. Keep intercom traffic tight and purposeful. Do not narrate your whole review through intercom.
|
|
22
|
+
|
|
23
|
+
If runtime bridge instructions or the task name a safe orchestrator target, send your final oracle recommendation back with a blocking `intercom({ action: "ask", ... })` before finishing. Stay alive for the reply so you can clarify, revise the recommendation, or produce a worker prompt if asked. If no safe target is available, do not guess; return normally.
|
|
21
24
|
|
|
22
25
|
Core responsibilities:
|
|
23
26
|
- reconstruct inherited decisions, constraints, and open questions from the context
|
package/agents/planner.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: planner
|
|
3
3
|
description: Creates implementation plans from context and requirements
|
|
4
|
-
tools: read, grep, find, ls, write
|
|
4
|
+
tools: read, grep, find, ls, write, intercom
|
|
5
5
|
model: openai-codex/gpt-5.5
|
|
6
6
|
thinking: high
|
|
7
7
|
systemPromptMode: replace
|
|
@@ -9,6 +9,7 @@ inheritProjectContext: true
|
|
|
9
9
|
inheritSkills: false
|
|
10
10
|
output: plan.md
|
|
11
11
|
defaultReads: context.md
|
|
12
|
+
defaultContext: fork
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
You are a planning subagent.
|
|
@@ -50,3 +51,6 @@ Which tasks depend on others.
|
|
|
50
51
|
Anything likely to go wrong, need clarification, or need careful verification.
|
|
51
52
|
|
|
52
53
|
Keep the plan concrete. Another agent should be able to execute it without guessing what you meant.
|
|
54
|
+
|
|
55
|
+
## Pi-intercom handoff
|
|
56
|
+
If `intercom` is available and runtime bridge instructions or the task name a safe orchestrator target, send the completed plan back with a blocking `intercom({ action: "ask", ... })` before finishing. Include the plan path or concise plan summary and ask whether the orchestrator wants clarification, revisions, or approval to proceed. If no safe target is available, do not guess; return normally.
|
package/agents/researcher.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: researcher
|
|
3
3
|
description: Autonomous web researcher — searches, evaluates, and synthesizes a focused research brief
|
|
4
|
-
tools: read, write, web_search, fetch_content, get_search_content
|
|
4
|
+
tools: read, write, web_search, fetch_content, get_search_content, intercom
|
|
5
5
|
model: openai-codex/gpt-5.5
|
|
6
6
|
thinking: medium
|
|
7
7
|
systemPromptMode: replace
|
|
@@ -48,3 +48,6 @@ Numbered findings with inline source citations.
|
|
|
48
48
|
|
|
49
49
|
## Gaps
|
|
50
50
|
What could not be answered confidently. Suggested next steps.
|
|
51
|
+
|
|
52
|
+
## Pi-intercom handoff
|
|
53
|
+
If `intercom` is available and runtime bridge instructions or the task name a safe orchestrator target, send your completed research brief back with a blocking `intercom({ action: "ask", ... })` before finishing. Keep the message concise, include the output path or top findings, and ask whether the orchestrator wants follow-up research. If no safe target is available, do not guess; return normally.
|