pi-subagents 0.24.3 → 0.25.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 -5
- package/README.md +19 -11
- package/package.json +4 -8
- package/prompts/review-loop.md +1 -1
- package/skills/pi-subagents/SKILL.md +46 -10
- package/src/agents/agent-management.ts +5 -0
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +30 -6
- package/src/agents/skills.ts +25 -23
- package/src/extension/config.ts +16 -0
- package/src/extension/fanout-child.ts +170 -0
- package/src/extension/index.ts +13 -25
- package/src/intercom/intercom-bridge.ts +2 -1
- package/src/intercom/result-intercom.ts +108 -0
- package/src/runs/background/async-execution.ts +107 -7
- package/src/runs/background/async-job-tracker.ts +57 -14
- package/src/runs/background/async-resume.ts +28 -15
- package/src/runs/background/async-status.ts +60 -30
- package/src/runs/background/result-watcher.ts +111 -54
- package/src/runs/background/run-id-resolver.ts +83 -0
- package/src/runs/background/run-status.ts +79 -3
- package/src/runs/background/stale-run-reconciler.ts +46 -1
- package/src/runs/background/subagent-runner.ts +66 -18
- package/src/runs/foreground/chain-execution.ts +6 -0
- package/src/runs/foreground/execution.ts +21 -5
- package/src/runs/foreground/subagent-executor.ts +314 -18
- package/src/runs/shared/completion-guard.ts +23 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +365 -0
- package/src/runs/shared/nested-events.ts +819 -0
- package/src/runs/shared/nested-path.ts +52 -0
- package/src/runs/shared/nested-render.ts +115 -0
- package/src/runs/shared/parallel-utils.ts +1 -0
- package/src/runs/shared/pi-args.ts +67 -5
- package/src/runs/shared/run-history.ts +12 -7
- package/src/runs/shared/single-output.ts +12 -2
- package/src/runs/shared/subagent-prompt-runtime.ts +25 -5
- package/src/shared/artifacts.ts +2 -2
- package/src/shared/types.ts +95 -0
- package/src/shared/utils.ts +11 -1
- package/src/tui/render.ts +254 -153
package/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.25.0] - 2026-05-21
|
|
4
6
|
|
|
5
7
|
### Added
|
|
6
|
-
-
|
|
7
|
-
- Added a packaged `/review-loop` prompt for parent-controlled worker, fresh-reviewer, and fix-worker cycles that can run as an initial async chain or as follow-up subagent runs after async worker completions, stopping when reviewers find no fixes worth doing now or the review-round cap is reached.
|
|
8
|
+
- Allow child agents whose resolved builtin tools explicitly include `subagent` to run child-safe nested fanout, with parent-visible nested status trees and nested `status`/`interrupt`/`resume` by id.
|
|
8
9
|
|
|
9
10
|
### Fixed
|
|
10
|
-
-
|
|
11
|
+
- Preserve compact nested child summaries in grouped result/intercom payloads and async completion metadata before ordinary result files are processed and deleted.
|
|
12
|
+
- Keep async result files retryable when nested registry enrichment temporarily fails, instead of marking them seen before a successful delivery pass.
|
|
13
|
+
- Require an explicit id for child-safe nested `status` when no local foreground run is active, preventing fanout children from listing unrelated top-level async runs.
|
|
14
|
+
- Keep fanout child control inbox polling alive across transient filesystem errors, and retain control requests for retry when control-result writes fail.
|
|
15
|
+
- Share nested path/env sanitization between child launch arguments and nested event projection.
|
|
11
16
|
|
|
12
|
-
## [
|
|
17
|
+
## [0.24.4] - 2026-05-20
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- Treat provider-coerced single-run `output: "false"` the same as boolean `false`, preventing literal `false` output files in foreground and async runs.
|
|
21
|
+
- Include selected direct MCP tool names in explicit child `--tools` allowlists when metadata cache/config resolution is available.
|
|
22
|
+
- Honor `PI_CODING_AGENT_DIR` for runtime config, agent/chain/settings discovery, skills, run history, artifact cleanup, and intercom defaults.
|
|
23
|
+
- Hide nested child Pi process windows on Windows for both foreground and background subagent runs.
|
|
24
|
+
- Avoid completion-guard false positives for declared read-only agents, and add `completionGuard: false` for bash-enabled non-implementation agents that should not be required to edit files.
|
|
25
|
+
- Skip empty or whitespace-only assistant text parts when selecting subagent final output, so later meaningful text in the same or earlier assistant message is not masked.
|
|
26
|
+
- Declare `@earendil-works/pi-tui` as a runtime dependency so packaged installs can load the extension without relying on dev dependencies or optional peers.
|
|
27
|
+
- Treat recovered intermediate child tool/provider errors as successful when a later clean final assistant response is emitted, preventing false failed subagent results.
|
|
28
|
+
- Use progress-driven spinner frames in subagent result rows and async widgets, avoiding timer-driven off-screen redraw flicker in small terminals.
|
|
29
|
+
|
|
30
|
+
## [0.24.3] - 2026-05-14
|
|
13
31
|
|
|
14
32
|
### Added
|
|
33
|
+
- Show provider-free model and thinking labels in async subagent widgets and status views.
|
|
34
|
+
- Added a packaged `/review-loop` prompt for parent-controlled worker, fresh-reviewer, and fix-worker cycles that can run as an initial async chain or as follow-up subagent runs after async worker completions, stopping when reviewers find no fixes worth doing now or the review-round cap is reached.
|
|
15
35
|
|
|
16
36
|
### Fixed
|
|
37
|
+
- Let `async: true` chain tool calls run in the background when `clarify` is omitted, and avoid showing the async badge for explicit foreground clarify runs.
|
|
17
38
|
|
|
18
39
|
## [0.24.2] - 2026-05-10
|
|
19
40
|
|
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ Foreground runs stream progress in the conversation while they run.
|
|
|
149
149
|
|
|
150
150
|
Background runs keep working after control returns to you. Inspect active runs with `subagent({ action: "status" })`, or a specific run with `subagent({ action: "status", id: "..." })`.
|
|
151
151
|
|
|
152
|
-
They also show a compact async widget and send completion notifications. Parallel background runs show per-agent progress instead of fake chain steps. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones.
|
|
152
|
+
They also show a compact async widget and send completion notifications. Parallel background runs show per-agent progress instead of fake chain steps. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones. When a child is explicitly allowed to fan out with `tools: subagent`, its nested runs appear under that parent child in the main status tree instead of being hidden inside the child process.
|
|
153
153
|
|
|
154
154
|
You can also ask naturally:
|
|
155
155
|
|
|
@@ -181,7 +181,7 @@ Use the optional prompt shortcuts below when you want the pattern to be repeatab
|
|
|
181
181
|
|
|
182
182
|
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.
|
|
183
183
|
|
|
184
|
-
Child-safety boundaries are enforced at runtime. Spawned child sessions do not
|
|
184
|
+
Child-safety boundaries are enforced at runtime. Spawned child sessions do not receive the bundled `pi-subagents` skill, and forked child context filtering 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. By default, children do not register the `subagent` tool and receive boundary instructions that they are not the parent orchestrator and must not propose or run subagents. The explicit exception is an agent whose resolved builtin `tools` includes `subagent`; that child gets a child-safe `subagent` tool for the fanout work the parent assigned, still bounded by `maxSubagentDepth`.
|
|
185
185
|
|
|
186
186
|
## Optional shortcuts
|
|
187
187
|
|
|
@@ -223,7 +223,7 @@ The child can use one dedicated coordination tool:
|
|
|
223
223
|
|
|
224
224
|
- `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
|
|
225
225
|
|
|
226
|
-
Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets and
|
|
226
|
+
Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets, full child summaries, and compact nested child summaries under the parent child that launched them.
|
|
227
227
|
|
|
228
228
|
If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
|
|
229
229
|
|
|
@@ -433,6 +433,7 @@ skills: safe-bash, chrome-devtools
|
|
|
433
433
|
output: context.md
|
|
434
434
|
defaultReads: context.md
|
|
435
435
|
defaultProgress: true
|
|
436
|
+
completionGuard: false
|
|
436
437
|
interactive: true
|
|
437
438
|
maxSubagentDepth: 1
|
|
438
439
|
---
|
|
@@ -458,20 +459,22 @@ Important fields:
|
|
|
458
459
|
| `output` | Default single-agent output file. |
|
|
459
460
|
| `defaultReads` | Files to read before running in chain/parallel behavior. |
|
|
460
461
|
| `defaultProgress` | Maintain `progress.md`. |
|
|
462
|
+
| `completionGuard` | Set `false` only for non-implementation agents that may mention implementation words while using mutation-capable tools such as `bash`. |
|
|
461
463
|
| `interactive` | Parsed for compatibility but not enforced in v1. |
|
|
462
464
|
| `maxSubagentDepth` | Tightens nested delegation for this agent’s children. |
|
|
463
465
|
|
|
464
466
|
### Tool and extension selection
|
|
465
467
|
|
|
466
|
-
If `tools` is omitted, `pi-subagents` does not pass `--tools`, so the child gets Pi’s normal builtin tools. If `tools` is present, regular tool names become an explicit allowlist. `mcp:` entries are split out and forwarded as direct MCP selections. Path-like `tools` entries, such as extension paths or `.ts`/`.js` files, are treated as tool-extension paths rather than builtin tool names.
|
|
468
|
+
If `tools` is omitted, `pi-subagents` does not pass `--tools`, so the child gets Pi’s normal builtin tools. If `tools` is present, regular tool names become an explicit allowlist. `mcp:` entries are split out and forwarded as direct MCP selections. Path-like `tools` entries, such as extension paths or `.ts`/`.js` files, are treated as tool-extension paths rather than builtin tool names. Agents that declare only known read-only builtin tools skip the implementation completion guard, but `bash`, unknown tools, and MCP tools stay mutation-capable. Use `completionGuard: false` for bash-enabled validators or advisors that should never be judged as implementation agents.
|
|
467
469
|
|
|
468
470
|
Examples:
|
|
469
471
|
|
|
470
472
|
- `tools` omitted and `extensions` omitted: normal builtins and normal extensions.
|
|
471
473
|
- `tools: mcp:chrome-devtools`: normal builtins plus direct Chrome DevTools MCP tools.
|
|
472
474
|
- `tools: read, bash, mcp:chrome-devtools`: only `read` and `bash` as builtins, plus direct Chrome DevTools MCP tools.
|
|
475
|
+
- `tools: subagent, read`: a child-safe `subagent` tool is available inside that child so it can run explicitly assigned nested fanout.
|
|
473
476
|
|
|
474
|
-
Direct MCP tools require [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter). Subagents only receive direct MCP tools when `mcp:` entries are listed in their frontmatter; global `directTools: true` in `mcp.json` is not enough by itself. The generic `mcp` proxy tool can still be used for discovery when available. The adapter caches tool metadata at startup, so after connecting a new MCP server for the first time, restart Pi before relying on direct tools.
|
|
477
|
+
Direct MCP tools require [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter). Subagents only receive direct MCP tools when `mcp:` entries are listed in their frontmatter; global `directTools: true` in `mcp.json` is not enough by itself. The generic `mcp` proxy tool can still be used for discovery when available. The adapter caches tool metadata at startup, so after connecting a new MCP server for the first time, restart Pi before relying on direct tools. An `mcp:` entry named `subagent` does not authorize nested fanout; only the builtin `subagent` tool name does.
|
|
475
478
|
|
|
476
479
|
`extensions` controls child extension loading:
|
|
477
480
|
|
|
@@ -591,7 +594,7 @@ What the bundled skill covers:
|
|
|
591
594
|
- **Delegation patterns**: when to launch which agent, whether to use single, parallel, chain, or async mode, and whether to use fresh or forked context
|
|
592
595
|
- **Prompt workflow recipes**: how to apply the packaged techniques directly with `subagent(...)` when the user describes the workflow in natural language instead of invoking a slash command. This includes parallel review, review-loop, parallel research, parallel context-build, parallel handoff-plan, gather-context-and-clarify, and parallel cleanup
|
|
593
596
|
- **Role-agent prompting guidance**: compact contract prompts instead of long scripts, what to include in role-specific meta prompts, and retrieval budgets for researchers
|
|
594
|
-
- **Safety boundaries**: child agents must not run subagents
|
|
597
|
+
- **Safety boundaries**: child agents must not run subagents unless their resolved builtin tools explicitly include `subagent`, must not invent intercom targets, and must escalate unapproved decisions
|
|
595
598
|
- **Intercom conventions**: when to ask vs send, and how parent-side result delivery works with `pi-intercom`
|
|
596
599
|
- **Control and diagnostics**: attention signals, soft interrupts, status, and the `doctor` action
|
|
597
600
|
|
|
@@ -735,13 +738,18 @@ Status and control actions:
|
|
|
735
738
|
```ts
|
|
736
739
|
subagent({ action: "status" })
|
|
737
740
|
subagent({ action: "status", id: "<run-id>" })
|
|
741
|
+
subagent({ action: "status", id: "<nested-run-id>" })
|
|
738
742
|
subagent({ action: "interrupt", id: "<run-id>" })
|
|
743
|
+
subagent({ action: "interrupt", id: "<nested-run-id>" })
|
|
739
744
|
subagent({ action: "resume", id: "<run-id>", message: "follow-up question" })
|
|
740
745
|
subagent({ action: "resume", id: "<run-id>", index: 1, message: "follow-up for child 2" })
|
|
746
|
+
subagent({ action: "resume", id: "<nested-run-id>", message: "follow-up for a nested child" })
|
|
741
747
|
subagent({ action: "doctor" })
|
|
742
748
|
```
|
|
743
749
|
|
|
744
|
-
`
|
|
750
|
+
`status` resolves exact foreground ids, top-level async ids, and nested run ids before falling back to prefix matching. Nested status shows the root/parent path, nested children, session/artifact paths when known, and nested control commands. Inside child-safe fanout mode, bare `status` requires an id when no local foreground run is active, so children cannot enumerate unrelated top-level async runs. Bare `interrupt` still targets only the visible top-level run; interrupting a nested run requires its explicit nested id.
|
|
751
|
+
|
|
752
|
+
`resume` sends the follow-up directly when an async child is still reachable over intercom. After completion, it revives the child by starting a new async child from the stored child session file. Multi-child async runs and remembered foreground single, parallel, or chain runs can be revived by passing `index` to choose the child. Nested runs can be resumed by nested id when their live route or persisted session metadata is available. Revive starts a new child process from the old session context; it does not restart the same OS process, and it requires the chosen child to have a persisted `.jsonl` session file.
|
|
745
753
|
|
|
746
754
|
## Worktree isolation
|
|
747
755
|
|
|
@@ -820,7 +828,7 @@ Session directory precedence is: `params.sessionDir`, then `config.defaultSessio
|
|
|
820
828
|
{ "maxSubagentDepth": 1 }
|
|
821
829
|
```
|
|
822
830
|
|
|
823
|
-
Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent’s child runs, but cannot relax an inherited stricter limit.
|
|
831
|
+
Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent’s child runs, but cannot relax an inherited stricter limit. This applies even to children that explicitly declare `tools: subagent`; at the cap, execution fanout is blocked instead of silently hiding nested work.
|
|
824
832
|
|
|
825
833
|
### `intercomBridge`
|
|
826
834
|
|
|
@@ -896,7 +904,7 @@ Async runs write:
|
|
|
896
904
|
subagent-log-<id>.md
|
|
897
905
|
```
|
|
898
906
|
|
|
899
|
-
`status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
|
|
907
|
+
`status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. Nested fanout status is stored as compact sidecar event/registry metadata and merged into parent status views and result/intercom payloads; full recursive status snapshots are not embedded in parent result files. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
|
|
900
908
|
|
|
901
909
|
## Live progress
|
|
902
910
|
|
|
@@ -918,9 +926,9 @@ This is disabled by default. Session data may contain source code, paths, enviro
|
|
|
918
926
|
|
|
919
927
|
## Recursion guard
|
|
920
928
|
|
|
921
|
-
Subagents can call `subagent
|
|
929
|
+
Subagents can call `subagent` only when their resolved builtin tools explicitly include `subagent`. That is meant for delegated fanout agents, not ordinary worker/reviewer children. A depth guard prevents unbounded nesting.
|
|
922
930
|
|
|
923
|
-
By default, nesting is limited to two levels: main session → subagent → sub-subagent. Deeper calls are blocked with guidance to complete the current task directly.
|
|
931
|
+
By default, nesting is limited to two levels: main session → subagent → sub-subagent. Deeper calls are blocked with guidance to complete the current task directly. Nested runs appear in the parent status widget and `status` output as a tree, and `status`, `interrupt`, and `resume` can target a nested run by its id.
|
|
924
932
|
|
|
925
933
|
Configure the limit with:
|
|
926
934
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Pi extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification",
|
|
5
5
|
"author": "Nico Bailon",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,8 +54,7 @@
|
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@earendil-works/pi-agent-core": "*",
|
|
56
56
|
"@earendil-works/pi-ai": "*",
|
|
57
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
58
|
-
"@earendil-works/pi-tui": "*"
|
|
57
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
59
58
|
},
|
|
60
59
|
"peerDependenciesMeta": {
|
|
61
60
|
"@earendil-works/pi-agent-core": {
|
|
@@ -66,19 +65,16 @@
|
|
|
66
65
|
},
|
|
67
66
|
"@earendil-works/pi-coding-agent": {
|
|
68
67
|
"optional": true
|
|
69
|
-
},
|
|
70
|
-
"@earendil-works/pi-tui": {
|
|
71
|
-
"optional": true
|
|
72
68
|
}
|
|
73
69
|
},
|
|
74
70
|
"dependencies": {
|
|
71
|
+
"@earendil-works/pi-tui": "^0.74.0",
|
|
75
72
|
"jiti": "^2.7.0",
|
|
76
73
|
"typebox": "^1.1.24"
|
|
77
74
|
},
|
|
78
75
|
"devDependencies": {
|
|
79
76
|
"@earendil-works/pi-agent-core": "^0.74.0",
|
|
80
77
|
"@earendil-works/pi-ai": "^0.74.0",
|
|
81
|
-
"@earendil-works/pi-coding-agent": "^0.74.0"
|
|
82
|
-
"@earendil-works/pi-tui": "^0.74.0"
|
|
78
|
+
"@earendil-works/pi-coding-agent": "^0.74.0"
|
|
83
79
|
}
|
|
84
80
|
}
|
package/prompts/review-loop.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Review/fix loop until clean
|
|
|
4
4
|
|
|
5
5
|
Run a parent-orchestrated review loop for the requested work.
|
|
6
6
|
|
|
7
|
-
Use the `subagent` tool. Keep the parent session as the loop controller and final decision-maker. Child subagents must receive concrete role-specific tasks; they must not run subagents or manage the loop themselves.
|
|
7
|
+
Use the `subagent` tool. Keep the parent session as the loop controller and final decision-maker. Child subagents must receive concrete role-specific tasks; they must not run subagents or manage the loop themselves unless the parent intentionally selected an explicit fanout agent whose builtin `tools` includes `subagent` for that assigned fanout.
|
|
8
8
|
|
|
9
9
|
Default to a maximum of 3 review rounds unless I specify a different cap. Count a review round each time fresh-context reviewers inspect the current diff after a worker pass. Stop early when reviewers find no blockers or fixes worth doing now.
|
|
10
10
|
|
|
@@ -10,7 +10,7 @@ description: |
|
|
|
10
10
|
|
|
11
11
|
# Pi Subagents
|
|
12
12
|
|
|
13
|
-
This skill is for the main parent orchestrator only. Do not inject or follow it inside spawned child subagents. The parent session owns delegation, orchestration, review fanout, and final fix-worker launches; child subagents should receive concrete role-specific tasks
|
|
13
|
+
This skill is for the main parent orchestrator only. Do not inject or follow it inside spawned child subagents. The parent session owns delegation, orchestration, review fanout, and final fix-worker launches; child subagents should receive concrete role-specific tasks. Ordinary children should not run their own subagent workflows; the explicit exception is a delegated fanout child whose resolved builtin `tools` includes `subagent`, and that child may use `subagent` only for the fanout work the parent assigned.
|
|
14
14
|
|
|
15
15
|
Use this skill when the parent orchestrator needs to launch a specialized subagent, compose multiple agents into a workflow, or create/edit agents and chains on demand.
|
|
16
16
|
|
|
@@ -108,7 +108,38 @@ Use this at the start of non-trivial work. Launch `scout` for local context and
|
|
|
108
108
|
|
|
109
109
|
### Parallel cleanup technique
|
|
110
110
|
|
|
111
|
-
Use this after implementation when the user wants cleanup review or when a final pass would reduce AI-slop. Launch two fresh-context `reviewer` tasks with `output: false` and `progress: false`: one deslop pass and one verbosity pass. If the `deslop` or `verbosity-cleaner` skills are available, pass the relevant skill to that reviewer; otherwise inline the criteria. Both reviewers are review-only and should flag concrete issues with severity, file/line references, and smallest safe fixes.
|
|
111
|
+
Use this after implementation when the user wants cleanup review or when a final pass would reduce AI-slop. Launch two fresh-context `reviewer` tasks with `output: false` and `progress: false`: one deslop pass and one verbosity pass. If the `deslop` or `verbosity-cleaner` skills are available, pass the relevant skill to that reviewer; otherwise inline the criteria. Both reviewers are review-only and should flag concrete issues with severity, file/line references, and smallest safe fixes. Phrase the constraint as “Do not modify project/source files; returning findings through the configured output artifact is allowed” when you use `output` or `outputMode: "file-only"`. The parent decides what to apply and asks before making changes unless cleanup was already authorized.
|
|
112
|
+
|
|
113
|
+
### Staged fix orchestration technique
|
|
114
|
+
|
|
115
|
+
Use this when a broad diff has known reviewer findings across several items and the user wants the parent to “orchestrate subagents like a boss.” Keep the active worktree safe with a three-stage chain:
|
|
116
|
+
|
|
117
|
+
1. A parallel read-only planning fanout, one planner/reviewer per issue cluster. Each child inspects the real diff and returns exact files, line refs, proposed fixes, and focused validation. They must not edit.
|
|
118
|
+
2. One writer worker. It receives the planner summaries through `{previous}`, the parent’s accepted scope, stop rules, and verification contract. It is the only child allowed to edit the active worktree.
|
|
119
|
+
3. A parallel read-only validation fanout. Validators inspect the worker diff from fresh context with distinct angles, report pass/fail, remaining blockers, and missing verification.
|
|
120
|
+
|
|
121
|
+
Prefer `async: true`, `context: "fresh"` for planners/validators, `outputMode: "file-only"` for large summaries, and per-stage output names that will not collide. Use this pattern instead of launching several writer workers into a dirty worktree. Include non-blocking suggestions in the writer prompt only when they are small, safe, and do not expand product scope; otherwise record them as deferred.
|
|
122
|
+
|
|
123
|
+
Example shape:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
subagent({
|
|
127
|
+
async: true,
|
|
128
|
+
context: "fresh",
|
|
129
|
+
chain: [
|
|
130
|
+
{ parallel: [
|
|
131
|
+
{ agent: "reviewer", task: "Plan fixes for deploy docs/workflow. Inspect the current diff. Do not modify project/source files; returning findings via the configured output artifact is allowed.", output: "plans/deploy.md", outputMode: "file-only" },
|
|
132
|
+
{ agent: "reviewer", task: "Plan fixes for scheduler contract. Inspect the current diff. Do not modify project/source files; returning findings via the configured output artifact is allowed.", output: "plans/scheduler.md", outputMode: "file-only" },
|
|
133
|
+
{ agent: "reviewer", task: "Plan fixes for sandbox/security. Inspect the current diff. Do not modify project/source files; returning findings via the configured output artifact is allowed.", output: "plans/sandbox.md", outputMode: "file-only" }
|
|
134
|
+
], concurrency: 3 },
|
|
135
|
+
{ agent: "worker", task: "Apply only the accepted fixes from these planning summaries. You are the sole writer for the active worktree. Run focused validation and report changed files, commands, failures, and remaining issues.\n\nPlanning summaries:\n{previous}", output: "worker/fixes.md", outputMode: "file-only", progress: true },
|
|
136
|
+
{ parallel: [
|
|
137
|
+
{ agent: "reviewer", task: "Validate the post-worker diff for deploy and scheduler fixes. Do not modify project/source files; returning findings via the configured output artifact is allowed.", output: "validation/deploy-scheduler.md", outputMode: "file-only" },
|
|
138
|
+
{ agent: "reviewer", task: "Validate the post-worker diff for sandbox/security fixes. Do not modify project/source files; returning findings via the configured output artifact is allowed.", output: "validation/sandbox.md", outputMode: "file-only" }
|
|
139
|
+
], concurrency: 2 }
|
|
140
|
+
]
|
|
141
|
+
})
|
|
142
|
+
```
|
|
112
143
|
|
|
113
144
|
## Builtin Agents
|
|
114
145
|
|
|
@@ -144,7 +175,7 @@ A strong subagent prompt usually includes:
|
|
|
144
175
|
- **Goal**: the concrete outcome the child should produce.
|
|
145
176
|
- **Context/evidence**: relevant plan paths, files, diffs, decisions, or user constraints already approved.
|
|
146
177
|
- **Success criteria**: what must be true before the child can finish.
|
|
147
|
-
- **Hard constraints**: true invariants only, such as no edits for review-only tasks, one writer thread, child must not run subagents, or escalation for unapproved decisions.
|
|
178
|
+
- **Hard constraints**: true invariants only, such as no edits for review-only tasks, one writer thread, child must not run subagents unless it is an explicitly assigned `tools: subagent` fanout child, or escalation for unapproved decisions.
|
|
148
179
|
- **Validation**: targeted checks to run, or the next-best check when validation is impossible.
|
|
149
180
|
- **Output**: the expected summary shape, artifact path, or finding format.
|
|
150
181
|
- **Stop rules**: when to ask via `intercom`, when to stop after enough evidence, and when not to keep searching.
|
|
@@ -245,7 +276,7 @@ subagent({
|
|
|
245
276
|
})
|
|
246
277
|
```
|
|
247
278
|
|
|
248
|
-
Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. Failed runs and save errors still return inline details for debugging.
|
|
279
|
+
Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. When a task is review-only, say “do not modify project/source files” rather than “do not write files” if you also configured `output`; otherwise the child may treat the output artifact as forbidden. Failed runs and save errors still return inline details for debugging.
|
|
249
280
|
|
|
250
281
|
### Chain execution
|
|
251
282
|
|
|
@@ -293,13 +324,14 @@ const run = subagent({
|
|
|
293
324
|
// Continue local inspection, then later call status with the returned id.
|
|
294
325
|
```
|
|
295
326
|
|
|
296
|
-
Inspect async runs with `subagent({ action: "status", id: "..." })` or `subagent({ action: "status" })` for active runs.
|
|
327
|
+
Inspect async runs with `subagent({ action: "status", id: "..." })` or `subagent({ action: "status" })` for active runs. If a delegated fanout child launches nested runs, the parent status view shows them as a tree and you can target a nested run directly with its nested id.
|
|
297
328
|
|
|
298
329
|
Use `resume` for follow-up work after a delegated run:
|
|
299
330
|
|
|
300
331
|
```typescript
|
|
301
332
|
subagent({ action: "resume", id: "run-id", message: "Follow up on this point." })
|
|
302
333
|
subagent({ action: "resume", id: "run-id", index: 1, message: "Continue reviewer 2." })
|
|
334
|
+
subagent({ action: "resume", id: "nested-run-id", message: "Continue this nested reviewer." })
|
|
303
335
|
```
|
|
304
336
|
|
|
305
337
|
Resume behavior:
|
|
@@ -307,6 +339,7 @@ Resume behavior:
|
|
|
307
339
|
- If an async child has completed, `resume` revives it by starting a new async child from the persisted child session file.
|
|
308
340
|
- Multi-child async runs require `index` unless only one running child is selectable.
|
|
309
341
|
- Completed foreground single, parallel, and chain runs can also be revived by `index` while their run metadata remains in extension state.
|
|
342
|
+
- Nested runs can be resumed by nested id when a live route or persisted nested session metadata is available.
|
|
310
343
|
- Revive starts a new child process from the old session context; it does not restart the same OS process.
|
|
311
344
|
- If the chosen child has no persisted `.jsonl` session file, resume fails and reports that directly.
|
|
312
345
|
|
|
@@ -330,13 +363,14 @@ Use soft interrupt when a child is clearly blocked or drifting and the parent ne
|
|
|
330
363
|
subagent({ action: "interrupt" })
|
|
331
364
|
```
|
|
332
365
|
|
|
333
|
-
Pass `id` when targeting a specific controllable run:
|
|
366
|
+
Pass `id` when targeting a specific controllable run, including a nested run shown in the parent status tree:
|
|
334
367
|
|
|
335
368
|
```typescript
|
|
336
369
|
subagent({ action: "interrupt", id: "abc123" })
|
|
370
|
+
subagent({ action: "interrupt", id: "nested-run-id" })
|
|
337
371
|
```
|
|
338
372
|
|
|
339
|
-
A soft interrupt cancels the current child turn and leaves the run paused. It does not mean the delegated task succeeded or failed. After an interrupt, decide the next explicit action: resume with clearer instructions, replace the task, ask the user, or stop the workflow.
|
|
373
|
+
A soft interrupt cancels the current child turn and leaves the run paused. It does not mean the delegated task succeeded or failed. Bare `interrupt` does not target hidden nested descendants; use the explicit nested id. After an interrupt, decide the next explicit action: resume with clearer instructions, replace the task, ask the user, or stop the workflow.
|
|
340
374
|
|
|
341
375
|
Per-run control thresholds can be overridden when a task legitimately runs without observable output for longer than usual:
|
|
342
376
|
|
|
@@ -430,7 +464,7 @@ Use `contact_supervisor` with `reason: "need_decision"` when:
|
|
|
430
464
|
- a child needs clarification instead of guessing
|
|
431
465
|
- an approval, product, API, or scope choice is required before continuing safely
|
|
432
466
|
|
|
433
|
-
Do not use `contact_supervisor` just to resolve review-only/no-edit versus progress-writing or artifact
|
|
467
|
+
Do not use `contact_supervisor` just to resolve review-only/no-project-edit versus progress-writing or output-artifact instructions. The child must not modify project/source files, but returning findings through its normal response or configured output artifact is allowed unless the parent explicitly set `output: false`.
|
|
434
468
|
|
|
435
469
|
Use `contact_supervisor` with `reason: "progress_update"` when:
|
|
436
470
|
- a child is explicitly asked for progress
|
|
@@ -440,7 +474,7 @@ Use `contact_supervisor` with `reason: "progress_update"` when:
|
|
|
440
474
|
Message conventions:
|
|
441
475
|
- `reason: "need_decision"` waits for the parent reply and returns it to the child.
|
|
442
476
|
- `reason: "progress_update"` is non-blocking and should stay concise.
|
|
443
|
-
- Child-side routine completion handoffs are not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets and
|
|
477
|
+
- Child-side routine completion handoffs are not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets, full child summaries, and compact nested summaries under the parent child that launched them.
|
|
444
478
|
|
|
445
479
|
If bridge instructions provide the child-facing tool, a child can ask:
|
|
446
480
|
|
|
@@ -656,9 +690,11 @@ The first `worker` implements the approved plan. The parent continues with indep
|
|
|
656
690
|
|
|
657
691
|
For complex work, risky changes, broad refactors, or many changed lines, increase review and validation fanout rather than trusting one reviewer. Use distinct angles such as correctness/regressions, tests/validation, simplicity/maintainability, security/privacy, performance, docs/API contracts, and user-flow behavior. When reviewers find non-trivial issues or the fix worker touches many lines, run another focused review round before final validation.
|
|
658
692
|
|
|
693
|
+
When review has already produced concrete findings across several independent areas, use staged fix orchestration: parallel read-only planners for each issue cluster, one sole writer worker for the active worktree, then parallel fresh-context validators. This is the safest way to handle a dirty worktree with many prior changes because it parallelizes judgment without parallelizing writes. Non-blocking suggestions may go into the writer prompt only if they are small, safe, and inside the approved scope; otherwise defer them explicitly.
|
|
694
|
+
|
|
659
695
|
For very large work, split into serial milestones instead of launching a swarm of writers. Each milestone gets one writer, a validation contract, fresh-context review/validation, a fix pass, and parent acceptance before the next milestone starts. Use parallel subagents inside a milestone for read-only context, research, review, and validation only.
|
|
660
696
|
|
|
661
|
-
Keep orchestration authority in the parent session. Child subagents should not launch more subagents, read this skill, or run their own orchestration loops
|
|
697
|
+
Keep orchestration authority in the parent session. Child subagents should not launch more subagents, read this skill, or run their own orchestration loops unless the parent intentionally selected a fanout agent whose builtin `tools` includes `subagent`. Spawned subagents do not receive the `pi-subagents` skill, parent-only status/control/slash messages, or prior parent `subagent` tool-call/tool-result artifacts. Ordinary children also do not receive the `subagent` extension tool. Child context filtering strips old hidden orchestration-instruction messages when they appear in inherited history. Every child receives a boundary instruction: ordinary children are told the parent owns orchestration and they must not propose or run subagents; explicit fanout children are told to use `subagent` only for the assigned fanout work, with `maxSubagentDepth` still enforced. Implementation children must call real edit/write tools instead of printing pseudo tool calls. Pass children concrete role-specific work instead.
|
|
662
698
|
|
|
663
699
|
1. Clarify first. This is mandatory. Gather code context with `scout` or `context-builder`, add `researcher` only when external evidence matters, then ask the user clarifying questions with `interview` until scope, acceptance criteria, constraints, and non-goals are clear.
|
|
664
700
|
2. Define the validation contract. State what done means before implementation: expected behavior, checks to run, user flows to exercise, and evidence required in the worker handoff. For UI, CLI, integration, or workflow changes, include at least one validator angle that uses the product the way a user would rather than only reading code.
|
|
@@ -297,6 +297,10 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
|
|
|
297
297
|
target.maxSubagentDepth = cfg.maxSubagentDepth;
|
|
298
298
|
} else return "config.maxSubagentDepth must be an integer >= 0 or false when provided.";
|
|
299
299
|
}
|
|
300
|
+
if (hasKey(cfg, "completionGuard")) {
|
|
301
|
+
if (typeof cfg.completionGuard !== "boolean") return "config.completionGuard must be a boolean when provided.";
|
|
302
|
+
target.completionGuard = cfg.completionGuard;
|
|
303
|
+
}
|
|
300
304
|
return undefined;
|
|
301
305
|
}
|
|
302
306
|
|
|
@@ -366,6 +370,7 @@ function formatAgentDetail(agent: AgentConfig): string {
|
|
|
366
370
|
if (agent.defaultReads?.length) lines.push(`Reads: ${agent.defaultReads.join(", ")}`);
|
|
367
371
|
if (agent.defaultProgress) lines.push("Progress: true");
|
|
368
372
|
if (agent.maxSubagentDepth !== undefined) lines.push(`Max subagent depth: ${agent.maxSubagentDepth}`);
|
|
373
|
+
if (agent.completionGuard === false) lines.push("Completion guard: false");
|
|
369
374
|
if (agent.systemPrompt.trim()) lines.push("", "System Prompt:", agent.systemPrompt);
|
|
370
375
|
return lines.join("\n");
|
|
371
376
|
}
|
|
@@ -21,6 +21,7 @@ export const KNOWN_FIELDS = new Set([
|
|
|
21
21
|
"defaultProgress",
|
|
22
22
|
"interactive",
|
|
23
23
|
"maxSubagentDepth",
|
|
24
|
+
"completionGuard",
|
|
24
25
|
]);
|
|
25
26
|
|
|
26
27
|
function joinComma(values: string[] | undefined): string | undefined {
|
|
@@ -69,6 +70,7 @@ export function serializeAgent(config: AgentConfig): string {
|
|
|
69
70
|
if (Number.isInteger(config.maxSubagentDepth) && config.maxSubagentDepth >= 0) {
|
|
70
71
|
lines.push(`maxSubagentDepth: ${config.maxSubagentDepth}`);
|
|
71
72
|
}
|
|
73
|
+
if (config.completionGuard === false) lines.push("completionGuard: false");
|
|
72
74
|
|
|
73
75
|
if (config.extraFields) {
|
|
74
76
|
for (const [key, value] of Object.entries(config.extraFields)) {
|
package/src/agents/agents.ts
CHANGED
|
@@ -7,6 +7,7 @@ import * as os from "node:os";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import type { OutputMode } from "../shared/types.ts";
|
|
10
|
+
import { getAgentDir } from "../shared/utils.ts";
|
|
10
11
|
import { KNOWN_FIELDS } from "./agent-serializer.ts";
|
|
11
12
|
import { parseChain } from "./chain-serializer.ts";
|
|
12
13
|
import { mergeAgentsForScope } from "./agent-selection.ts";
|
|
@@ -45,6 +46,7 @@ export interface BuiltinAgentOverrideBase {
|
|
|
45
46
|
skills?: string[];
|
|
46
47
|
tools?: string[];
|
|
47
48
|
mcpDirectTools?: string[];
|
|
49
|
+
completionGuard?: boolean;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
interface BuiltinAgentOverrideConfig {
|
|
@@ -59,6 +61,7 @@ interface BuiltinAgentOverrideConfig {
|
|
|
59
61
|
systemPrompt?: string;
|
|
60
62
|
skills?: string[] | false;
|
|
61
63
|
tools?: string[] | false;
|
|
64
|
+
completionGuard?: boolean;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
interface BuiltinAgentOverrideInfo {
|
|
@@ -91,6 +94,7 @@ export interface AgentConfig {
|
|
|
91
94
|
defaultProgress?: boolean;
|
|
92
95
|
interactive?: boolean;
|
|
93
96
|
maxSubagentDepth?: number;
|
|
97
|
+
completionGuard?: boolean;
|
|
94
98
|
disabled?: boolean;
|
|
95
99
|
extraFields?: Record<string, string>;
|
|
96
100
|
override?: BuiltinAgentOverrideInfo;
|
|
@@ -131,7 +135,7 @@ interface AgentDiscoveryResult {
|
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
function getUserChainDir(): string {
|
|
134
|
-
return path.join(
|
|
138
|
+
return path.join(getAgentDir(), "chains");
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {
|
|
@@ -182,6 +186,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
182
186
|
skills: agent.skills ? [...agent.skills] : undefined,
|
|
183
187
|
tools: agent.tools ? [...agent.tools] : undefined,
|
|
184
188
|
mcpDirectTools: agent.mcpDirectTools ? [...agent.mcpDirectTools] : undefined,
|
|
189
|
+
completionGuard: agent.completionGuard,
|
|
185
190
|
};
|
|
186
191
|
}
|
|
187
192
|
|
|
@@ -200,6 +205,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
200
205
|
...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
|
|
201
206
|
...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
|
|
202
207
|
...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),
|
|
208
|
+
...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
|
|
203
209
|
};
|
|
204
210
|
}
|
|
205
211
|
|
|
@@ -217,7 +223,7 @@ function findNearestProjectRoot(cwd: string): string | null {
|
|
|
217
223
|
}
|
|
218
224
|
|
|
219
225
|
function getUserAgentSettingsPath(): string {
|
|
220
|
-
return path.join(
|
|
226
|
+
return path.join(getAgentDir(), "settings.json");
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
function getProjectAgentSettingsPath(cwd: string): string | null {
|
|
@@ -336,6 +342,14 @@ function parseBuiltinOverrideEntry(
|
|
|
336
342
|
}
|
|
337
343
|
}
|
|
338
344
|
|
|
345
|
+
if ("completionGuard" in input) {
|
|
346
|
+
if (typeof input.completionGuard === "boolean") {
|
|
347
|
+
override.completionGuard = input.completionGuard;
|
|
348
|
+
} else {
|
|
349
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'completionGuard'; expected a boolean.`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
339
353
|
if ("systemPrompt" in input) {
|
|
340
354
|
if (typeof input.systemPrompt === "string") override.systemPrompt = input.systemPrompt;
|
|
341
355
|
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);
|
|
@@ -408,6 +422,7 @@ function applyBuiltinOverride(
|
|
|
408
422
|
next.tools = tools;
|
|
409
423
|
next.mcpDirectTools = mcpDirectTools;
|
|
410
424
|
}
|
|
425
|
+
if (override.completionGuard !== undefined) next.completionGuard = override.completionGuard;
|
|
411
426
|
|
|
412
427
|
return next;
|
|
413
428
|
}
|
|
@@ -447,7 +462,7 @@ function applyBuiltinOverrides(
|
|
|
447
462
|
|
|
448
463
|
export function buildBuiltinOverrideConfig(
|
|
449
464
|
base: BuiltinAgentOverrideBase,
|
|
450
|
-
draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools">,
|
|
465
|
+
draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "completionGuard">,
|
|
451
466
|
): BuiltinAgentOverrideConfig | undefined {
|
|
452
467
|
const override: BuiltinAgentOverrideConfig = {};
|
|
453
468
|
|
|
@@ -465,6 +480,9 @@ export function buildBuiltinOverrideConfig(
|
|
|
465
480
|
const baseTools = joinToolList(base);
|
|
466
481
|
const draftTools = joinToolList(draft);
|
|
467
482
|
if (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;
|
|
483
|
+
if ((draft.completionGuard !== false) !== (base.completionGuard !== false)) {
|
|
484
|
+
override.completionGuard = draft.completionGuard !== false;
|
|
485
|
+
}
|
|
468
486
|
|
|
469
487
|
return Object.keys(override).length > 0 ? override : undefined;
|
|
470
488
|
}
|
|
@@ -630,6 +648,11 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
630
648
|
}
|
|
631
649
|
|
|
632
650
|
const parsedMaxSubagentDepth = Number(frontmatter.maxSubagentDepth);
|
|
651
|
+
const completionGuard = frontmatter.completionGuard === "false"
|
|
652
|
+
? false
|
|
653
|
+
: frontmatter.completionGuard === "true"
|
|
654
|
+
? true
|
|
655
|
+
: undefined;
|
|
633
656
|
|
|
634
657
|
agents.push({
|
|
635
658
|
name: runtimeName,
|
|
@@ -658,6 +681,7 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
658
681
|
Number.isInteger(parsedMaxSubagentDepth) && parsedMaxSubagentDepth >= 0
|
|
659
682
|
? parsedMaxSubagentDepth
|
|
660
683
|
: undefined,
|
|
684
|
+
completionGuard,
|
|
661
685
|
extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,
|
|
662
686
|
});
|
|
663
687
|
}
|
|
@@ -723,7 +747,7 @@ function resolveNearestProjectChainDirs(cwd: string): { readDirs: string[]; pref
|
|
|
723
747
|
const BUILTIN_AGENTS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "agents");
|
|
724
748
|
|
|
725
749
|
export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {
|
|
726
|
-
const userDirOld = path.join(
|
|
750
|
+
const userDirOld = path.join(getAgentDir(), "agents");
|
|
727
751
|
const userDirNew = path.join(os.homedir(), ".agents");
|
|
728
752
|
const { readDirs: projectAgentDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(cwd);
|
|
729
753
|
const userSettingsPath = getUserAgentSettingsPath();
|
|
@@ -762,7 +786,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
762
786
|
userSettingsPath: string;
|
|
763
787
|
projectSettingsPath: string | null;
|
|
764
788
|
} {
|
|
765
|
-
const userDirOld = path.join(
|
|
789
|
+
const userDirOld = path.join(getAgentDir(), "agents");
|
|
766
790
|
const userDirNew = path.join(os.homedir(), ".agents");
|
|
767
791
|
const userChainDir = getUserChainDir();
|
|
768
792
|
const { readDirs: projectDirs, preferredDir: projectDir } = resolveNearestProjectAgentDirs(cwd);
|
|
@@ -802,7 +826,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
802
826
|
...Array.from(chainMap.values()),
|
|
803
827
|
];
|
|
804
828
|
|
|
805
|
-
const userDir = fs.existsSync(userDirNew) ? userDirNew : userDirOld;
|
|
829
|
+
const userDir = process.env.PI_CODING_AGENT_DIR ? userDirOld : fs.existsSync(userDirNew) ? userDirNew : userDirOld;
|
|
806
830
|
|
|
807
831
|
return { builtin, user, project, chains, userDir, projectDir, userChainDir, projectChainDir, userSettingsPath, projectSettingsPath };
|
|
808
832
|
}
|