pi-subagents 0.19.3 → 0.20.1
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 +21 -0
- package/README.md +13 -10
- package/agents/context-builder.md +1 -0
- package/agents/oracle.md +4 -5
- package/agents/researcher.md +1 -0
- package/agents/scout.md +2 -1
- package/agents/worker.md +33 -25
- package/async-execution.ts +3 -0
- package/package.json +1 -1
- package/prompts/parallel-cleanup.md +42 -0
- package/render-helpers.ts +4 -2
- package/result-intercom.ts +235 -0
- package/result-watcher.ts +71 -5
- package/skills/pi-subagents/SKILL.md +8 -12
- package/subagent-executor.ts +135 -40
- package/subagent-runner.ts +9 -0
- package/types.ts +33 -0
- package/agents/oracle-executor.md +0 -49
- package/prompts/oracle-executor.md +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.20.1] - 2026-04-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Made the packaged `/parallel-cleanup` prompt self-contained instead of referencing local-only cleanup skills.
|
|
9
|
+
|
|
10
|
+
## [0.20.0] - 2026-04-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Added a packaged `/parallel-cleanup` prompt for focused cleanup review passes.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Consolidated the `oracle-executor` role into `worker`: `worker` now uses `openai-codex/gpt-5.3-codex` with high thinking and stricter approved-direction guardrails, while `researcher` and `context-builder` now use medium thinking.
|
|
17
|
+
- Updated the bundled `scout` agent model/thinking defaults.
|
|
18
|
+
- Hard-cut over grouped intercom bridge result delivery: with the bridge active, parent-side `pi-subagents` emits one grouped `subagent:result-intercom` message per foreground parent run (single, top-level parallel, or chain) and one per completed async result file. Acknowledged foreground delivery returns a compact receipt instead of duplicating full output in the normal tool result; unacknowledged delivery preserves the normal full output. Grouped messages include child intercom targets and full child summaries.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- Fixed status and manager row rendering so multiline or tabbed content cannot overflow table rows.
|
|
22
|
+
|
|
23
|
+
### Removed
|
|
24
|
+
- Removed the bundled `oracle-executor` agent and `/oracle-executor` prompt template in favor of using `worker` for approved oracle handoffs.
|
|
25
|
+
|
|
5
26
|
## [0.19.3] - 2026-04-27
|
|
6
27
|
|
|
7
28
|
### Changed
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Run parallel reviewers on this diff. I want one focused on correctness, one on t
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
```text
|
|
70
|
-
|
|
70
|
+
Have worker implement this approved plan. Afterward, run parallel reviewers, summarize their feedback, and apply the fixes that make sense.
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
```text
|
|
@@ -85,7 +85,7 @@ Those are ordinary Pi requests. Pi decides whether to call `subagent`, which age
|
|
|
85
85
|
| Review a diff | “Use reviewer to review this diff.” |
|
|
86
86
|
| Run parallel reviewers | “Run reviewers for correctness, tests, and cleanup.” |
|
|
87
87
|
| Implement then review | “Implement this, then review it.” |
|
|
88
|
-
| Execute a plan carefully | “
|
|
88
|
+
| Execute a plan carefully | “Have worker implement this approved plan, then run reviewers and apply the feedback.” |
|
|
89
89
|
| Scout before planning | “Use scout to inspect the auth flow before planning.” |
|
|
90
90
|
| Run in the background | “Run this in the background.” |
|
|
91
91
|
| Browse agents | “Show me the available subagents.” |
|
|
@@ -102,11 +102,10 @@ The extension ships with builtin agents you can use immediately.
|
|
|
102
102
|
| `scout` | Fast local codebase recon: relevant files, entry points, data flow, risks, and where another agent should start. |
|
|
103
103
|
| `researcher` | Web/docs research with sources: official docs, specs, benchmarks, recent changes, and a concise research brief. |
|
|
104
104
|
| `planner` | A concrete implementation plan from existing context. It should read and plan, not edit code. |
|
|
105
|
-
| `worker` |
|
|
105
|
+
| `worker` | Implementation work, including approved oracle handoffs. It edits files, validates, and escalates unapproved decisions instead of guessing. |
|
|
106
106
|
| `reviewer` | Code review and small fixes. It checks the implementation against the task/plan, tests, edge cases, and simplicity. |
|
|
107
107
|
| `context-builder` | A stronger setup pass before planning: gathers code context and writes handoff material such as `context.md` and `meta-prompt.md`. |
|
|
108
108
|
| `oracle` | A second opinion before acting. It challenges assumptions, catches drift, and recommends the safest next move without editing. |
|
|
109
|
-
| `oracle-executor` | Careful implementation after a direction has been approved. It is the “go do the approved thing” agent. |
|
|
110
109
|
| `delegate` | A lightweight general delegate when you want a child agent that behaves close to the parent session. |
|
|
111
110
|
|
|
112
111
|
A simple rule of thumb: use `scout` before you understand the code, `researcher` before you trust external facts, `planner` before a bigger change, `worker` to implement, `reviewer` to check, and `oracle` when the decision itself feels risky.
|
|
@@ -184,7 +183,6 @@ The package includes reusable prompt templates for common workflows. You do not
|
|
|
184
183
|
| `/parallel-review` | Launch fresh-context reviewers with distinct angles, then synthesize what to fix. |
|
|
185
184
|
| `/parallel-research` | Combine `researcher` and `scout` for external evidence, local code context, and practical tradeoffs. |
|
|
186
185
|
| `/gather-context-and-clarify` | Scout/research first, then ask the user the clarification questions that matter. |
|
|
187
|
-
| `/oracle-executor` | Send an explicitly approved implementation task to `oracle-executor` with inherited context. |
|
|
188
186
|
|
|
189
187
|
## Optional pi-intercom companion
|
|
190
188
|
|
|
@@ -206,12 +204,12 @@ Run this implementation in the background. If the worker gets blocked or needs a
|
|
|
206
204
|
Ask oracle to review this plan. If it sees a decision I need to make, have it ask me instead of assuming.
|
|
207
205
|
```
|
|
208
206
|
|
|
209
|
-
The child can use two kinds of messages:
|
|
207
|
+
The child can use two kinds of coordination messages:
|
|
210
208
|
|
|
211
209
|
- `ask`: the child needs a decision or clarification from the parent session
|
|
212
210
|
- `send`: the child sends a short update when blocked or explicitly asked for progress
|
|
213
211
|
|
|
214
|
-
|
|
212
|
+
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 full child summaries.
|
|
215
213
|
|
|
216
214
|
If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `/subagents-status`, interrupting the run, or nudging the child.
|
|
217
215
|
|
|
@@ -315,7 +313,7 @@ You can combine them in either order:
|
|
|
315
313
|
/run reviewer "review this diff" --bg --fork
|
|
316
314
|
```
|
|
317
315
|
|
|
318
|
-
The `oracle` and `
|
|
316
|
+
The `oracle` and `worker` builtins are designed for an explicit decision loop. A typical pattern is to ask `oracle` for diagnosis and a recommended execution prompt, then only run `worker` after the main agent approves that direction.
|
|
319
317
|
|
|
320
318
|
## Clarify and launch UI
|
|
321
319
|
|
|
@@ -386,7 +384,7 @@ Agent locations, lowest to highest priority:
|
|
|
386
384
|
|
|
387
385
|
Project discovery also reads legacy `.agents/{name}.md` files. If both `.agents/` and `.pi/agents/` define the same project agent, `.pi/agents/` wins. Use `agentScope: "user" | "project" | "both"` to control discovery; `both` is the default and project definitions win name collisions.
|
|
388
386
|
|
|
389
|
-
Builtin agents load at the lowest priority, so a user or project agent with the same name overrides them. `oracle` is an advisory reviewer that critiques direction and proposes an execution prompt without editing files. `
|
|
387
|
+
Builtin agents load at the lowest priority, so a user or project agent with the same name overrides them. `oracle` is an advisory reviewer that critiques direction and proposes an execution prompt without editing files. `worker` is the implementation agent for normal tasks and approved oracle handoffs.
|
|
390
388
|
|
|
391
389
|
The `researcher` builtin uses `web_search`, `fetch_content`, and `get_search_content`; those require [pi-web-access](https://github.com/nicobailon/pi-web-access):
|
|
392
390
|
|
|
@@ -939,7 +937,12 @@ Async events:
|
|
|
939
937
|
- `subagent:async-started`
|
|
940
938
|
- `subagent:async-complete`
|
|
941
939
|
|
|
942
|
-
|
|
940
|
+
Intercom delivery events:
|
|
941
|
+
|
|
942
|
+
- `subagent:control-intercom`
|
|
943
|
+
- `subagent:result-intercom`
|
|
944
|
+
|
|
945
|
+
The result watcher emits `subagent:async-complete`; `index.ts` registers the notification handler that consumes it. Control/attention events are surfaced as visible parent notices and persisted for async runs. With `pi-intercom`, needs-attention notices and grouped parent-side subagent result deliveries can reach the orchestrator over intercom.
|
|
943
946
|
|
|
944
947
|
## Prompt-template integration
|
|
945
948
|
|
|
@@ -3,6 +3,7 @@ name: context-builder
|
|
|
3
3
|
description: Analyzes requirements and codebase, generates context and meta-prompt
|
|
4
4
|
tools: read, grep, find, ls, bash, write, web_search
|
|
5
5
|
model: openai-codex/gpt-5.5
|
|
6
|
+
thinking: medium
|
|
6
7
|
systemPromptMode: replace
|
|
7
8
|
inheritProjectContext: true
|
|
8
9
|
inheritSkills: false
|
package/agents/oracle.md
CHANGED
|
@@ -17,7 +17,7 @@ Before you do anything else, reconstruct the key inherited decisions, constraint
|
|
|
17
17
|
|
|
18
18
|
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
19
|
|
|
20
|
-
Use `intercom({ action: "ask", ... })` when you need a real decision or clarification. Use `intercom({ action: "send", ... })` for concise
|
|
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, and do not send routine completion handoffs.
|
|
21
21
|
|
|
22
22
|
Core responsibilities:
|
|
23
23
|
- reconstruct inherited decisions, constraints, and open questions from the context
|
|
@@ -32,7 +32,7 @@ Core responsibilities:
|
|
|
32
32
|
What you do not do by default:
|
|
33
33
|
- do not edit files or write code
|
|
34
34
|
- do not propose additional parallel decision-makers or new subagent trees unless explicitly asked
|
|
35
|
-
- do not assume
|
|
35
|
+
- do not assume a `worker` implementation handoff is the default outcome
|
|
36
36
|
- do not propose broad pivots unless the context clearly supports them
|
|
37
37
|
- do not continue the user conversation directly
|
|
38
38
|
|
|
@@ -40,8 +40,7 @@ Working rules:
|
|
|
40
40
|
- Use `bash` only for inspection, verification, or read-only analysis.
|
|
41
41
|
- If information is missing and it matters, ask the main agent via `intercom` instead of guessing.
|
|
42
42
|
- If the answer depends on a decision the main agent has not made yet, stop and ask via `intercom` before continuing.
|
|
43
|
-
- When bridge instructions are present, send concise intercom messages when a recommendation, concern, or question would benefit from immediate discussion instead of waiting silently until the final return.
|
|
44
|
-
- Before returning your full structured result, send a short intercom handoff summarizing the recommended next move when bridge instructions are present.
|
|
43
|
+
- When bridge instructions are present, send concise intercom messages only when a recommendation, concern, or question would benefit from immediate discussion instead of waiting silently until the final return.
|
|
45
44
|
- Prefer narrow, specific corrections to the current path over rewriting the whole plan.
|
|
46
45
|
|
|
47
46
|
Your output should follow this shape. If no executor handoff is warranted, say so plainly.
|
|
@@ -70,5 +69,5 @@ Need from main agent:
|
|
|
70
69
|
- specific question or decision required before continuing, if any
|
|
71
70
|
|
|
72
71
|
Suggested execution prompt:
|
|
73
|
-
- a concrete prompt for `
|
|
72
|
+
- a concrete prompt for `worker`, only if an implementation handoff is actually warranted
|
|
74
73
|
- if no handoff is warranted, say so explicitly
|
package/agents/researcher.md
CHANGED
|
@@ -3,6 +3,7 @@ name: researcher
|
|
|
3
3
|
description: Autonomous web researcher — searches, evaluates, and synthesizes a focused research brief
|
|
4
4
|
tools: read, write, web_search, fetch_content, get_search_content
|
|
5
5
|
model: openai-codex/gpt-5.5
|
|
6
|
+
thinking: medium
|
|
6
7
|
systemPromptMode: replace
|
|
7
8
|
inheritProjectContext: true
|
|
8
9
|
inheritSkills: false
|
package/agents/scout.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
name: scout
|
|
3
3
|
description: Fast codebase recon that returns compressed context for handoff
|
|
4
4
|
tools: read, grep, find, ls, bash, write
|
|
5
|
-
model: openai-codex/gpt-5.
|
|
5
|
+
model: openai-codex/gpt-5.5
|
|
6
|
+
thinking: medium
|
|
6
7
|
systemPromptMode: replace
|
|
7
8
|
inheritProjectContext: true
|
|
8
9
|
inheritSkills: false
|
package/agents/worker.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
|
-
description:
|
|
4
|
-
model: openai-codex/gpt-5.
|
|
3
|
+
description: Implementation agent for normal tasks and approved oracle handoffs
|
|
4
|
+
model: openai-codex/gpt-5.3-codex
|
|
5
|
+
thinking: high
|
|
5
6
|
systemPromptMode: replace
|
|
6
7
|
inheritProjectContext: true
|
|
7
8
|
inheritSkills: false
|
|
@@ -9,36 +10,43 @@ defaultReads: context.md, plan.md
|
|
|
9
10
|
defaultProgress: true
|
|
10
11
|
---
|
|
11
12
|
|
|
12
|
-
You are
|
|
13
|
+
You are `worker`: the implementation subagent.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
You are the single writer thread. Your job is to execute the assigned task or approved direction with narrow, coherent edits. The main agent and user remain the decision authority.
|
|
16
|
+
|
|
17
|
+
Use the provided tools directly. First understand the inherited context, supplied files, plan, and explicit task. Then implement carefully and minimally.
|
|
18
|
+
|
|
19
|
+
If the task is framed as an approved direction, oracle handoff, or execution plan, treat that direction as the contract. Validate it against the actual code, but do not silently make new product, architecture, or scope decisions.
|
|
20
|
+
|
|
21
|
+
If the implementation reveals a decision that was not approved and is required to continue safely, pause and escalate. If runtime bridge instructions are present, use them as the source of truth for which parent session to contact and how to coordinate. Use `intercom({ action: "ask", ... })` when a new decision is needed. Use `intercom({ action: "send", ... })` only for concise blocked/progress updates when that extra coordination is helpful or explicitly requested.
|
|
22
|
+
|
|
23
|
+
Default responsibilities:
|
|
24
|
+
- validate the task or approved direction against the actual code
|
|
25
|
+
- implement the smallest correct change
|
|
26
|
+
- follow existing patterns in the codebase
|
|
27
|
+
- verify the result with appropriate checks when possible
|
|
28
|
+
- keep `progress.md` accurate when asked to maintain it
|
|
29
|
+
- report back clearly with changes, validation, risks, and next steps
|
|
15
30
|
|
|
16
31
|
Working rules:
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
- Do not leave
|
|
20
|
-
-
|
|
21
|
-
- If
|
|
22
|
-
-
|
|
32
|
+
- Prefer narrow, correct changes over broad rewrites.
|
|
33
|
+
- Do not add speculative scaffolding or future-proofing unless explicitly required.
|
|
34
|
+
- Do not leave placeholder code, TODOs, or silent scope changes.
|
|
35
|
+
- Use `bash` for inspection, validation, and relevant tests.
|
|
36
|
+
- If there is supplied context or a plan, read it first.
|
|
37
|
+
- If implementation reveals a gap in the approved direction, pause and escalate instead of silently patching around it with an implicit decision.
|
|
38
|
+
- If implementation reveals an unapproved product or architecture choice, pause and ask instead of deciding it yourself.
|
|
39
|
+
- If you send a blocked/progress update through intercom, keep it short and still return the full structured task result normally.
|
|
23
40
|
|
|
24
41
|
When running in a chain, expect instructions about:
|
|
25
42
|
- which files to read first
|
|
26
43
|
- where to maintain progress tracking
|
|
27
44
|
- where to write output if a file target is provided
|
|
28
45
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# Progress
|
|
32
|
-
|
|
33
|
-
## Status
|
|
34
|
-
[In Progress | Completed | Blocked]
|
|
35
|
-
|
|
36
|
-
## Tasks
|
|
37
|
-
- [x] Completed task
|
|
38
|
-
- [ ] Current task
|
|
39
|
-
|
|
40
|
-
## Files Changed
|
|
41
|
-
- `path/to/file.ts` - what changed
|
|
46
|
+
Your final response should follow this shape:
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
Implemented X.
|
|
49
|
+
Changed files: Y.
|
|
50
|
+
Validation: Z.
|
|
51
|
+
Open risks/questions: R.
|
|
52
|
+
Recommended next step: N.
|
package/async-execution.ts
CHANGED
|
@@ -64,6 +64,7 @@ export interface AsyncExecutionContext {
|
|
|
64
64
|
|
|
65
65
|
export interface AsyncChainParams {
|
|
66
66
|
chain: ChainStep[];
|
|
67
|
+
resultMode?: "parallel" | "chain";
|
|
67
68
|
agents: AgentConfig[];
|
|
68
69
|
ctx: AsyncExecutionContext;
|
|
69
70
|
availableModels?: AvailableModelInfo[];
|
|
@@ -345,6 +346,7 @@ export function executeAsyncChain(
|
|
|
345
346
|
controlConfig,
|
|
346
347
|
controlIntercomTarget,
|
|
347
348
|
childIntercomTargets,
|
|
349
|
+
resultMode: params.resultMode ?? "chain",
|
|
348
350
|
},
|
|
349
351
|
id,
|
|
350
352
|
runnerCwd,
|
|
@@ -484,6 +486,7 @@ export function executeAsyncSingle(
|
|
|
484
486
|
controlConfig,
|
|
485
487
|
controlIntercomTarget,
|
|
486
488
|
childIntercomTargets: childIntercomTarget ? [childIntercomTarget(agent, 0)] : undefined,
|
|
489
|
+
resultMode: "single",
|
|
487
490
|
},
|
|
488
491
|
id,
|
|
489
492
|
runnerCwd,
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Parallel cleanup review
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Launch two fresh-context reviewer subagents for an adversarial cleanup review of the current work. Reviewers must inspect the repository, relevant instructions, and current diff directly from files and commands. Do not rely on this prompt as a substitute for reading the code.
|
|
6
|
+
|
|
7
|
+
Reviewer 1: deslop pass.
|
|
8
|
+
|
|
9
|
+
Ask this reviewer to look for AI-slop patterns in the changed scope:
|
|
10
|
+
- comments that restate code, placeholder text, stale rationale, or debug leftovers;
|
|
11
|
+
- defensive checks that hide useful errors, return vague defaults, or validate trusted internal data after a real boundary was already crossed;
|
|
12
|
+
- type escapes, broad casts, duplicated type definitions, or object-bag typing where a local source-of-truth type exists;
|
|
13
|
+
- style drift from nearby non-slop code and project instructions;
|
|
14
|
+
- generated-sounding docs, changelog text, UI copy, status text, or test names;
|
|
15
|
+
- pass-through wrappers, dead helpers, duplicate helper signatures, duplicated test harness setup, or abstractions that do not enforce an invariant;
|
|
16
|
+
- UI or CLI copy that is noisy, vague, brittle, or makes the user do extra interpretation.
|
|
17
|
+
|
|
18
|
+
Tell this reviewer to treat tool output and slop-scan-style findings as leads, not verdicts. It should flag only concrete issues in the requested scope with evidence, severity, file/line references, and the smallest safe fix.
|
|
19
|
+
|
|
20
|
+
Reviewer 2: verbosity pass.
|
|
21
|
+
|
|
22
|
+
Ask this reviewer to look for needless verbosity in code, tests, docs, status text, grouped messages, receipts, and changelog wording:
|
|
23
|
+
- single-use helpers that merely paraphrase an expression;
|
|
24
|
+
- temporary variables that only name obvious expressions;
|
|
25
|
+
- nested returns or branches that can become direct returns without hiding intent;
|
|
26
|
+
- multi-line cleanup scaffolding that can use a local direct pattern while preserving cleanup semantics;
|
|
27
|
+
- repeated boilerplate that can use an existing local fixture or a small local helper;
|
|
28
|
+
- tests that restate formatter details already covered at a cheaper layer;
|
|
29
|
+
- prose that says the same thing twice, sounds generic, or buries the important rule.
|
|
30
|
+
|
|
31
|
+
Tell this reviewer that shorter is only better when it is clearer and preserves behavior, error signals, cleanup semantics, useful invariants, and local style.
|
|
32
|
+
|
|
33
|
+
Both reviewers are review-only. They must not edit files unless I explicitly ask for a writer pass. Their response should be review feedback, not a context summary. Ask them to return concise, evidence-backed findings with file/line references and suggested fixes.
|
|
34
|
+
|
|
35
|
+
While reviewers run, do your own narrow inspection if useful. After they return, synthesize the feedback into:
|
|
36
|
+
- fixes worth doing now;
|
|
37
|
+
- optional improvements;
|
|
38
|
+
- feedback to ignore or defer, with a short reason.
|
|
39
|
+
|
|
40
|
+
Do not blindly apply every reviewer suggestion. Ask before applying fixes unless I already told you to address review feedback.
|
|
41
|
+
|
|
42
|
+
$@
|
package/render-helpers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { visibleWidth } from "@mariozechner/pi-tui";
|
|
2
|
+
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
3
3
|
|
|
4
4
|
function fuzzyScore(query: string, text: string): number {
|
|
5
5
|
const lq = query.toLowerCase();
|
|
@@ -37,7 +37,9 @@ export function pad(s: string, len: number): string {
|
|
|
37
37
|
|
|
38
38
|
export function row(content: string, width: number, theme: Theme): string {
|
|
39
39
|
const innerW = width - 2;
|
|
40
|
-
|
|
40
|
+
const singleLine = content.replace(/[\r\n]+/g, " ").replace(/\t/g, " ");
|
|
41
|
+
const clipped = truncateToWidth(singleLine, innerW);
|
|
42
|
+
return theme.fg("border", "│") + pad(clipped, innerW) + theme.fg("border", "│");
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export function renderHeader(text: string, width: number, theme: Theme): string {
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
type Details,
|
|
4
|
+
type IntercomEventBus,
|
|
5
|
+
type SingleResult,
|
|
6
|
+
type SubagentResultIntercomChild,
|
|
7
|
+
type SubagentResultIntercomPayload,
|
|
8
|
+
type SubagentResultStatus,
|
|
9
|
+
SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT,
|
|
10
|
+
SUBAGENT_RESULT_INTERCOM_EVENT,
|
|
11
|
+
} from "./types.ts";
|
|
12
|
+
|
|
13
|
+
export function resolveSubagentResultStatus(input: {
|
|
14
|
+
exitCode?: number;
|
|
15
|
+
success?: boolean;
|
|
16
|
+
state?: string;
|
|
17
|
+
interrupted?: boolean;
|
|
18
|
+
detached?: boolean;
|
|
19
|
+
}): SubagentResultStatus {
|
|
20
|
+
if (input.detached) return "detached";
|
|
21
|
+
if (input.interrupted || input.state === "paused") return "paused";
|
|
22
|
+
if (typeof input.success === "boolean") return input.success ? "completed" : "failed";
|
|
23
|
+
if (input.state === "complete") return "completed";
|
|
24
|
+
if (input.state === "failed") return "failed";
|
|
25
|
+
if (typeof input.exitCode === "number") return input.exitCode === 0 ? "completed" : "failed";
|
|
26
|
+
return "failed";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function countStatuses(children: SubagentResultIntercomChild[]): Record<SubagentResultStatus, number> {
|
|
30
|
+
const counts: Record<SubagentResultStatus, number> = {
|
|
31
|
+
completed: 0,
|
|
32
|
+
failed: 0,
|
|
33
|
+
paused: 0,
|
|
34
|
+
detached: 0,
|
|
35
|
+
};
|
|
36
|
+
for (const child of children) {
|
|
37
|
+
counts[child.status] += 1;
|
|
38
|
+
}
|
|
39
|
+
return counts;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatStatusCounts(counts: Record<SubagentResultStatus, number>): string {
|
|
43
|
+
const parts = [
|
|
44
|
+
counts.completed ? `${counts.completed} completed` : undefined,
|
|
45
|
+
counts.failed ? `${counts.failed} failed` : undefined,
|
|
46
|
+
counts.paused ? `${counts.paused} paused` : undefined,
|
|
47
|
+
counts.detached ? `${counts.detached} detached` : undefined,
|
|
48
|
+
].filter((part): part is string => Boolean(part));
|
|
49
|
+
return parts.length ? parts.join(", ") : "0 results";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function resolveGroupedStatus(children: SubagentResultIntercomChild[]): SubagentResultStatus {
|
|
53
|
+
const counts = countStatuses(children);
|
|
54
|
+
if (counts.failed > 0) return "failed";
|
|
55
|
+
if (counts.paused > 0) return "paused";
|
|
56
|
+
if (counts.completed > 0) return "completed";
|
|
57
|
+
if (counts.detached > 0) return "detached";
|
|
58
|
+
return "failed";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface GroupedResultIntercomMessageInput {
|
|
62
|
+
to: string;
|
|
63
|
+
runId: string;
|
|
64
|
+
mode: "single" | "parallel" | "chain";
|
|
65
|
+
source: "foreground" | "async";
|
|
66
|
+
children: SubagentResultIntercomChild[];
|
|
67
|
+
asyncId?: string;
|
|
68
|
+
asyncDir?: string;
|
|
69
|
+
chainSteps?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function formatSubagentResultIntercomMessage(input: {
|
|
73
|
+
runId: string;
|
|
74
|
+
mode: "single" | "parallel" | "chain";
|
|
75
|
+
status: SubagentResultStatus;
|
|
76
|
+
children: SubagentResultIntercomChild[];
|
|
77
|
+
asyncId?: string;
|
|
78
|
+
asyncDir?: string;
|
|
79
|
+
chainSteps?: number;
|
|
80
|
+
}): string {
|
|
81
|
+
const counts = countStatuses(input.children);
|
|
82
|
+
const lines: string[] = [
|
|
83
|
+
"subagent results",
|
|
84
|
+
"",
|
|
85
|
+
`Run: ${input.runId}`,
|
|
86
|
+
`Mode: ${input.mode}`,
|
|
87
|
+
`Status: ${input.status}`,
|
|
88
|
+
`Children: ${formatStatusCounts(counts)}`,
|
|
89
|
+
];
|
|
90
|
+
if (input.mode === "chain" && typeof input.chainSteps === "number") {
|
|
91
|
+
lines.push(`Chain steps: ${input.chainSteps}`);
|
|
92
|
+
}
|
|
93
|
+
if (input.asyncId) lines.push(`Async id: ${input.asyncId}`);
|
|
94
|
+
if (input.asyncDir) lines.push(`Async dir: ${input.asyncDir}`);
|
|
95
|
+
if (input.children.some((child) => child.intercomTarget)) {
|
|
96
|
+
lines.push("");
|
|
97
|
+
lines.push("For clarification, message a listed subagent at its Intercom target.");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (let index = 0; index < input.children.length; index++) {
|
|
101
|
+
const child = input.children[index]!;
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(`${index + 1}. ${child.agent} — ${child.status}`);
|
|
104
|
+
if (child.intercomTarget) lines.push(`Intercom target: ${child.intercomTarget}`);
|
|
105
|
+
if (child.artifactPath) lines.push(`Output artifact: ${child.artifactPath}`);
|
|
106
|
+
if (child.sessionPath) lines.push(`Session: ${child.sessionPath}`);
|
|
107
|
+
lines.push("Summary:");
|
|
108
|
+
lines.push(child.summary);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return lines.join("\n");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function buildSubagentResultIntercomPayload(input: GroupedResultIntercomMessageInput): SubagentResultIntercomPayload {
|
|
115
|
+
const children = input.children.map((child) => ({
|
|
116
|
+
...child,
|
|
117
|
+
summary: child.summary.trim() || "(no output)",
|
|
118
|
+
}));
|
|
119
|
+
const status = resolveGroupedStatus(children);
|
|
120
|
+
const summary = formatStatusCounts(countStatuses(children));
|
|
121
|
+
const firstChild = children[0];
|
|
122
|
+
const payload: SubagentResultIntercomPayload = {
|
|
123
|
+
to: input.to,
|
|
124
|
+
runId: input.runId,
|
|
125
|
+
mode: input.mode,
|
|
126
|
+
status,
|
|
127
|
+
summary,
|
|
128
|
+
source: input.source,
|
|
129
|
+
children,
|
|
130
|
+
...(input.asyncId ? { asyncId: input.asyncId } : {}),
|
|
131
|
+
...(input.asyncDir ? { asyncDir: input.asyncDir } : {}),
|
|
132
|
+
...(typeof input.chainSteps === "number" ? { chainSteps: input.chainSteps } : {}),
|
|
133
|
+
...(firstChild?.agent ? { agent: firstChild.agent } : {}),
|
|
134
|
+
...(firstChild?.index !== undefined ? { index: firstChild.index } : {}),
|
|
135
|
+
...(firstChild?.artifactPath ? { artifactPath: firstChild.artifactPath } : {}),
|
|
136
|
+
...(firstChild?.sessionPath ? { sessionPath: firstChild.sessionPath } : {}),
|
|
137
|
+
message: "",
|
|
138
|
+
};
|
|
139
|
+
payload.message = formatSubagentResultIntercomMessage(payload);
|
|
140
|
+
return payload;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function deliverSubagentResultIntercomEvent(
|
|
144
|
+
events: IntercomEventBus,
|
|
145
|
+
payload: SubagentResultIntercomPayload,
|
|
146
|
+
timeoutMs = 500,
|
|
147
|
+
): Promise<boolean> {
|
|
148
|
+
if (typeof events.on !== "function" || typeof events.emit !== "function") return false;
|
|
149
|
+
const requestId = payload.requestId ?? randomUUID();
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
let settled = false;
|
|
152
|
+
let unsubscribe: (() => void) | undefined;
|
|
153
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
154
|
+
const finish = (delivered: boolean) => {
|
|
155
|
+
if (settled) return;
|
|
156
|
+
settled = true;
|
|
157
|
+
if (timer) clearTimeout(timer);
|
|
158
|
+
unsubscribe?.();
|
|
159
|
+
resolve(delivered);
|
|
160
|
+
};
|
|
161
|
+
unsubscribe = events.on(SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT, (data) => {
|
|
162
|
+
if (!data || typeof data !== "object") return;
|
|
163
|
+
const delivery = data as { requestId?: unknown; delivered?: unknown };
|
|
164
|
+
if (delivery.requestId !== requestId) return;
|
|
165
|
+
finish(delivery.delivered === true);
|
|
166
|
+
});
|
|
167
|
+
timer = setTimeout(() => finish(false), timeoutMs);
|
|
168
|
+
try {
|
|
169
|
+
events.emit(SUBAGENT_RESULT_INTERCOM_EVENT, { ...payload, requestId });
|
|
170
|
+
} catch {
|
|
171
|
+
finish(false);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function stripSingleResultOutputs(result: SingleResult): SingleResult {
|
|
177
|
+
return {
|
|
178
|
+
...result,
|
|
179
|
+
messages: undefined,
|
|
180
|
+
finalOutput: undefined,
|
|
181
|
+
truncation: undefined,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function stripDetailsOutputsForIntercomReceipt(details: Details): Details {
|
|
186
|
+
return {
|
|
187
|
+
...details,
|
|
188
|
+
results: details.results.map(stripSingleResultOutputs),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function formatSubagentResultReceipt(input: {
|
|
193
|
+
mode: "single" | "parallel" | "chain";
|
|
194
|
+
runId: string;
|
|
195
|
+
payload: SubagentResultIntercomPayload;
|
|
196
|
+
}): string {
|
|
197
|
+
const counts = countStatuses(input.payload.children);
|
|
198
|
+
const modeLabel = input.mode === "single"
|
|
199
|
+
? "single subagent result"
|
|
200
|
+
: input.mode === "parallel"
|
|
201
|
+
? "parallel subagent results"
|
|
202
|
+
: "chain subagent results";
|
|
203
|
+
const lines = [
|
|
204
|
+
`Delivered ${modeLabel} via intercom.`,
|
|
205
|
+
`Run: ${input.runId}`,
|
|
206
|
+
`Children: ${formatStatusCounts(counts)}`,
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
const artifacts = input.payload.children.filter((child) => typeof child.artifactPath === "string");
|
|
210
|
+
if (artifacts.length > 0) {
|
|
211
|
+
lines.push("Artifacts:");
|
|
212
|
+
for (const child of artifacts) {
|
|
213
|
+
lines.push(`- ${child.agent} [${child.status}]: ${child.artifactPath}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const intercomTargets = input.payload.children.filter((child) => typeof child.intercomTarget === "string");
|
|
218
|
+
if (intercomTargets.length > 0) {
|
|
219
|
+
lines.push("Intercom targets:");
|
|
220
|
+
for (const child of intercomTargets) {
|
|
221
|
+
lines.push(`- ${child.agent} [${child.status}]: ${child.intercomTarget}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const sessions = input.payload.children.filter((child) => typeof child.sessionPath === "string");
|
|
226
|
+
if (sessions.length > 0) {
|
|
227
|
+
lines.push("Sessions:");
|
|
228
|
+
for (const child of sessions) {
|
|
229
|
+
lines.push(`- ${child.agent} [${child.status}]: ${child.sessionPath}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
lines.push("Full grouped output was sent over intercom.");
|
|
234
|
+
return lines.join("\n");
|
|
235
|
+
}
|
package/result-watcher.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
|
-
import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.
|
|
5
|
-
import { createFileCoalescer } from "./file-coalescer.
|
|
6
|
-
import {
|
|
4
|
+
import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.ts";
|
|
5
|
+
import { createFileCoalescer } from "./file-coalescer.ts";
|
|
6
|
+
import {
|
|
7
|
+
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
8
|
+
type SubagentState,
|
|
9
|
+
} from "./types.ts";
|
|
10
|
+
import {
|
|
11
|
+
buildSubagentResultIntercomPayload,
|
|
12
|
+
deliverSubagentResultIntercomEvent,
|
|
13
|
+
resolveSubagentResultStatus,
|
|
14
|
+
} from "./result-intercom.ts";
|
|
7
15
|
|
|
8
16
|
function isNotFoundError(error: unknown): boolean {
|
|
9
17
|
return typeof error === "object"
|
|
@@ -22,13 +30,30 @@ export function createResultWatcher(
|
|
|
22
30
|
primeExistingResults: () => void;
|
|
23
31
|
stopResultWatcher: () => void;
|
|
24
32
|
} {
|
|
25
|
-
const handleResult = (file: string) => {
|
|
33
|
+
const handleResult = async (file: string) => {
|
|
26
34
|
const resultPath = path.join(resultsDir, file);
|
|
27
35
|
if (!fs.existsSync(resultPath)) return;
|
|
28
36
|
try {
|
|
29
37
|
const data = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as {
|
|
38
|
+
id?: string;
|
|
39
|
+
runId?: string;
|
|
40
|
+
agent?: string;
|
|
41
|
+
success?: boolean;
|
|
42
|
+
state?: string;
|
|
43
|
+
mode?: string;
|
|
44
|
+
summary?: string;
|
|
45
|
+
results?: Array<{
|
|
46
|
+
agent?: string;
|
|
47
|
+
output?: string;
|
|
48
|
+
success?: boolean;
|
|
49
|
+
artifactPaths?: { outputPath?: string };
|
|
50
|
+
intercomTarget?: string;
|
|
51
|
+
}>;
|
|
30
52
|
sessionId?: string;
|
|
31
53
|
cwd?: string;
|
|
54
|
+
sessionFile?: string;
|
|
55
|
+
asyncDir?: string;
|
|
56
|
+
intercomTarget?: string;
|
|
32
57
|
};
|
|
33
58
|
if (data.sessionId && data.sessionId !== state.currentSessionId) return;
|
|
34
59
|
if (!data.sessionId && data.cwd && data.cwd !== state.baseCwd) return;
|
|
@@ -40,6 +65,45 @@ export function createResultWatcher(
|
|
|
40
65
|
return;
|
|
41
66
|
}
|
|
42
67
|
|
|
68
|
+
const intercomTarget = data.intercomTarget?.trim();
|
|
69
|
+
if (intercomTarget) {
|
|
70
|
+
const childResults = Array.isArray(data.results) && data.results.length > 0
|
|
71
|
+
? data.results
|
|
72
|
+
: [{
|
|
73
|
+
agent: data.agent,
|
|
74
|
+
output: data.summary,
|
|
75
|
+
success: data.success,
|
|
76
|
+
}];
|
|
77
|
+
const runId = data.runId ?? data.id ?? file.replace(/\.json$/i, "");
|
|
78
|
+
const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain"
|
|
79
|
+
? data.mode
|
|
80
|
+
: childResults.length > 1 ? "chain" : "single";
|
|
81
|
+
const payload = buildSubagentResultIntercomPayload({
|
|
82
|
+
to: intercomTarget,
|
|
83
|
+
runId,
|
|
84
|
+
mode,
|
|
85
|
+
source: "async",
|
|
86
|
+
children: childResults.map((result = {}, index) => ({
|
|
87
|
+
agent: result.agent ?? data.agent ?? `step-${index + 1}`,
|
|
88
|
+
status: resolveSubagentResultStatus({
|
|
89
|
+
success: result.success,
|
|
90
|
+
state: data.state === "paused" || typeof result.success !== "boolean" ? data.state : undefined,
|
|
91
|
+
}),
|
|
92
|
+
summary: result.output ?? data.summary ?? "(no output)",
|
|
93
|
+
index,
|
|
94
|
+
artifactPath: result.artifactPaths?.outputPath,
|
|
95
|
+
sessionPath: data.sessionFile,
|
|
96
|
+
intercomTarget: result.intercomTarget,
|
|
97
|
+
})),
|
|
98
|
+
asyncId: data.id,
|
|
99
|
+
asyncDir: data.asyncDir,
|
|
100
|
+
});
|
|
101
|
+
const delivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
|
|
102
|
+
if (!delivered) {
|
|
103
|
+
console.error(`Subagent async grouped result intercom delivery was not acknowledged for '${resultPath}'.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
43
107
|
pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, data);
|
|
44
108
|
fs.unlinkSync(resultPath);
|
|
45
109
|
} catch (error) {
|
|
@@ -48,7 +112,9 @@ export function createResultWatcher(
|
|
|
48
112
|
}
|
|
49
113
|
};
|
|
50
114
|
|
|
51
|
-
state.resultFileCoalescer = createFileCoalescer(
|
|
115
|
+
state.resultFileCoalescer = createFileCoalescer((file) => {
|
|
116
|
+
void handleResult(file);
|
|
117
|
+
}, 50);
|
|
52
118
|
|
|
53
119
|
const scheduleRestart = () => {
|
|
54
120
|
state.watcherRestartTimer = setTimeout(() => {
|
|
@@ -16,7 +16,7 @@ agents into a workflow, or create/edit agents and chains on demand.
|
|
|
16
16
|
## When to Use
|
|
17
17
|
|
|
18
18
|
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or fork to `oracle` when inherited decisions and drift matter
|
|
19
|
-
- **Implementation handoff**: have `oracle` advise, then `
|
|
19
|
+
- **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
|
|
20
20
|
- **Recon and planning**: use `scout` or `context-builder`, then `planner`
|
|
21
21
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
22
22
|
- **Long-running work**: launch async/background runs and inspect them later
|
|
@@ -43,7 +43,6 @@ Packaged prompt shortcuts are also available for repeatable workflows:
|
|
|
43
43
|
- `/parallel-review` — fresh-context reviewers with distinct review angles, then synthesis
|
|
44
44
|
- `/parallel-research` — combine `researcher` and `scout` for external evidence plus local code context
|
|
45
45
|
- `/gather-context-and-clarify` — scout/research first, then ask the user clarifying questions with `interview`
|
|
46
|
-
- `/oracle-executor` — send an explicitly approved implementation task to `oracle-executor`
|
|
47
46
|
|
|
48
47
|
## Builtin Agents
|
|
49
48
|
|
|
@@ -54,13 +53,12 @@ and user/project agents override builtins with the same name.
|
|
|
54
53
|
|-------|---------|-------|------------------------|
|
|
55
54
|
| `scout` | Fast codebase recon | `openai-codex/gpt-5.4-mini` | Writes `context.md` handoff material |
|
|
56
55
|
| `planner` | Creates implementation plans | `openai-codex/gpt-5.5` | Writes `plan.md` |
|
|
57
|
-
| `worker` |
|
|
56
|
+
| `worker` | Implementation and approved oracle handoffs | `openai-codex/gpt-5.3-codex` | Single-writer implementation with decision escalation |
|
|
58
57
|
| `reviewer` | Review-and-fix specialist | `openai-codex/gpt-5.5` | Can edit/fix reviewed code |
|
|
59
58
|
| `context-builder` | Requirements/codebase handoff builder | `openai-codex/gpt-5.5` | Writes structured context files |
|
|
60
59
|
| `researcher` | Web research brief generator | `openai-codex/gpt-5.5` | Writes `research.md` |
|
|
61
60
|
| `delegate` | Lightweight generic delegate | inherits parent model | No fixed output; generic delegated work |
|
|
62
61
|
| `oracle` | Decision-consistency advisory review | `openai-codex/gpt-5.5` | Advisory review, intercom coordination |
|
|
63
|
-
| `oracle-executor` | Implementation after approval | `openai-codex/gpt-5.5` | Single-writer implementation after approval |
|
|
64
62
|
|
|
65
63
|
Override builtin defaults before copying full agent files when a small tweak is enough.
|
|
66
64
|
|
|
@@ -282,7 +280,7 @@ The intended oracle loop is:
|
|
|
282
280
|
2. `oracle` reviews direction, drift, assumptions, and risks
|
|
283
281
|
3. `oracle` can coordinate back to the orchestrator via `intercom`
|
|
284
282
|
4. the main agent decides what direction to approve
|
|
285
|
-
5. only then should `
|
|
283
|
+
5. only then should `worker` implement
|
|
286
284
|
|
|
287
285
|
```typescript
|
|
288
286
|
// Advisory review in a branched thread
|
|
@@ -294,7 +292,7 @@ subagent({
|
|
|
294
292
|
|
|
295
293
|
// Implementation only after explicit approval
|
|
296
294
|
subagent({
|
|
297
|
-
agent: "
|
|
295
|
+
agent: "worker",
|
|
298
296
|
task: "Implement the approved approach: ...",
|
|
299
297
|
context: "fork"
|
|
300
298
|
})
|
|
@@ -319,7 +317,7 @@ Use `intercom` when:
|
|
|
319
317
|
Message conventions:
|
|
320
318
|
- `ask` means the child needs a decision or clarification from the parent session.
|
|
321
319
|
- `send` means a short blocked/progress update, only when blocked or explicitly asked.
|
|
322
|
-
-
|
|
320
|
+
- 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 full child summaries.
|
|
323
321
|
|
|
324
322
|
If a bridge target is available, a child can ask:
|
|
325
323
|
|
|
@@ -426,9 +424,8 @@ copying a full builtin file.
|
|
|
426
424
|
## Prompt Template Integration
|
|
427
425
|
|
|
428
426
|
The package includes prompt shortcuts for common workflows: `/parallel-review`,
|
|
429
|
-
`/parallel-research`, `/gather-context-and-clarify
|
|
430
|
-
|
|
431
|
-
approved execution patterns.
|
|
427
|
+
`/parallel-research`, and `/gather-context-and-clarify`. Use them when the user
|
|
428
|
+
wants repeatable review, research, or clarification patterns.
|
|
432
429
|
|
|
433
430
|
If `pi-prompt-template-model` is installed, additional user prompt templates can delegate into
|
|
434
431
|
`pi-subagents`. This is useful when a slash command should always run through a
|
|
@@ -453,8 +450,7 @@ particular agent or with forked context.
|
|
|
453
450
|
### Keep writes single-threaded by default
|
|
454
451
|
|
|
455
452
|
A strong pattern is one main decision-maker plus advisory/research/review
|
|
456
|
-
subagents around it. Use `oracle` for advice and `
|
|
457
|
-
for the actual write path.
|
|
453
|
+
subagents around it. Use `oracle` for advice and `worker` for the actual write path.
|
|
458
454
|
|
|
459
455
|
### Use fork for branched advisory or execution threads
|
|
460
456
|
|
package/subagent-executor.ts
CHANGED
|
@@ -32,6 +32,13 @@ import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBrid
|
|
|
32
32
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "./subagent-control.ts";
|
|
33
33
|
import { finalizeSingleOutput, injectSingleOutputInstruction, resolveSingleOutputPath } from "./single-output.ts";
|
|
34
34
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, readStatus, resolveChildCwd } from "./utils.ts";
|
|
35
|
+
import {
|
|
36
|
+
buildSubagentResultIntercomPayload,
|
|
37
|
+
deliverSubagentResultIntercomEvent,
|
|
38
|
+
formatSubagentResultReceipt,
|
|
39
|
+
resolveSubagentResultStatus,
|
|
40
|
+
stripDetailsOutputsForIntercomReceipt,
|
|
41
|
+
} from "./result-intercom.ts";
|
|
35
42
|
import { inspectSubagentStatus } from "./run-status.ts";
|
|
36
43
|
import { applyForceTopLevelAsyncOverride } from "./top-level-async.ts";
|
|
37
44
|
import {
|
|
@@ -261,6 +268,64 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
|
|
|
261
268
|
});
|
|
262
269
|
}
|
|
263
270
|
|
|
271
|
+
async function emitForegroundResultIntercom(input: {
|
|
272
|
+
pi: ExtensionAPI;
|
|
273
|
+
intercomBridge: IntercomBridgeState;
|
|
274
|
+
runId: string;
|
|
275
|
+
mode: "single" | "parallel" | "chain";
|
|
276
|
+
results: SingleResult[];
|
|
277
|
+
chainSteps?: number;
|
|
278
|
+
}): Promise<ReturnType<typeof buildSubagentResultIntercomPayload> | null> {
|
|
279
|
+
if (!input.intercomBridge.active || !input.intercomBridge.orchestratorTarget) return null;
|
|
280
|
+
const children = input.results.flatMap((result, index) => result.detached ? [] : [{
|
|
281
|
+
agent: result.agent,
|
|
282
|
+
status: resolveSubagentResultStatus({
|
|
283
|
+
exitCode: result.exitCode,
|
|
284
|
+
interrupted: result.interrupted,
|
|
285
|
+
detached: result.detached,
|
|
286
|
+
}),
|
|
287
|
+
summary: getSingleResultOutput(result) || result.error || "(no output)",
|
|
288
|
+
index,
|
|
289
|
+
artifactPath: result.artifactPaths?.outputPath,
|
|
290
|
+
sessionPath: result.sessionFile,
|
|
291
|
+
intercomTarget: resolveSubagentIntercomTarget(input.runId, result.agent, index),
|
|
292
|
+
}]);
|
|
293
|
+
if (children.length === 0) return null;
|
|
294
|
+
const payload = buildSubagentResultIntercomPayload({
|
|
295
|
+
to: input.intercomBridge.orchestratorTarget,
|
|
296
|
+
runId: input.runId,
|
|
297
|
+
mode: input.mode,
|
|
298
|
+
source: "foreground",
|
|
299
|
+
children,
|
|
300
|
+
...(typeof input.chainSteps === "number" ? { chainSteps: input.chainSteps } : {}),
|
|
301
|
+
});
|
|
302
|
+
const delivered = await deliverSubagentResultIntercomEvent(input.pi.events, payload);
|
|
303
|
+
if (!delivered) return null;
|
|
304
|
+
return payload;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function maybeBuildForegroundIntercomReceipt(input: {
|
|
308
|
+
pi: ExtensionAPI;
|
|
309
|
+
intercomBridge: IntercomBridgeState;
|
|
310
|
+
runId: string;
|
|
311
|
+
mode: "single" | "parallel" | "chain";
|
|
312
|
+
details: Details;
|
|
313
|
+
}): Promise<{ text: string; details: Details } | null> {
|
|
314
|
+
const payload = await emitForegroundResultIntercom({
|
|
315
|
+
pi: input.pi,
|
|
316
|
+
intercomBridge: input.intercomBridge,
|
|
317
|
+
runId: input.runId,
|
|
318
|
+
mode: input.mode,
|
|
319
|
+
results: input.details.results,
|
|
320
|
+
...(typeof input.details.totalSteps === "number" ? { chainSteps: input.details.totalSteps } : {}),
|
|
321
|
+
});
|
|
322
|
+
if (!payload) return null;
|
|
323
|
+
return {
|
|
324
|
+
text: formatSubagentResultReceipt({ mode: input.mode, runId: input.runId, payload }),
|
|
325
|
+
details: stripDetailsOutputsForIntercomReceipt(input.details),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
264
329
|
function validateExecutionInput(
|
|
265
330
|
params: SubagentParamsLike,
|
|
266
331
|
agents: AgentConfig[],
|
|
@@ -563,6 +628,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
563
628
|
concurrency: resolveTopLevelParallelConcurrency(params.concurrency, deps.config.parallel?.concurrency),
|
|
564
629
|
worktree: params.worktree,
|
|
565
630
|
}],
|
|
631
|
+
resultMode: "parallel",
|
|
566
632
|
agents,
|
|
567
633
|
ctx: asyncCtx,
|
|
568
634
|
availableModels,
|
|
@@ -746,6 +812,24 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
746
812
|
});
|
|
747
813
|
}
|
|
748
814
|
|
|
815
|
+
const chainDetails = chainResult.details ? compactForegroundDetails(chainResult.details) : undefined;
|
|
816
|
+
const intercomReceipt = chainDetails && !chainDetails.results.some((result) => result.interrupted)
|
|
817
|
+
? await maybeBuildForegroundIntercomReceipt({
|
|
818
|
+
pi: deps.pi,
|
|
819
|
+
intercomBridge: data.intercomBridge,
|
|
820
|
+
runId,
|
|
821
|
+
mode: "chain",
|
|
822
|
+
details: chainDetails,
|
|
823
|
+
})
|
|
824
|
+
: null;
|
|
825
|
+
if (intercomReceipt) {
|
|
826
|
+
return {
|
|
827
|
+
...chainResult,
|
|
828
|
+
content: [{ type: "text", text: intercomReceipt.text }],
|
|
829
|
+
details: intercomReceipt.details,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
|
|
749
833
|
return chainResult;
|
|
750
834
|
}
|
|
751
835
|
|
|
@@ -1120,6 +1204,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1120
1204
|
}));
|
|
1121
1205
|
return executeAsyncChain(id, {
|
|
1122
1206
|
chain: [{ parallel: parallelTasks, concurrency: parallelConcurrency, worktree: params.worktree }],
|
|
1207
|
+
resultMode: "parallel",
|
|
1123
1208
|
agents,
|
|
1124
1209
|
ctx: asyncCtx,
|
|
1125
1210
|
availableModels,
|
|
@@ -1216,15 +1301,30 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1216
1301
|
}
|
|
1217
1302
|
|
|
1218
1303
|
const interrupted = results.find((result) => result.interrupted);
|
|
1304
|
+
const details = compactForegroundDetails({
|
|
1305
|
+
mode: "parallel",
|
|
1306
|
+
results,
|
|
1307
|
+
progress: params.includeProgress ? allProgress : undefined,
|
|
1308
|
+
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1309
|
+
});
|
|
1219
1310
|
if (interrupted) {
|
|
1220
1311
|
return {
|
|
1221
1312
|
content: [{ type: "text", text: `Parallel run paused after interrupt (${interrupted.agent}). Waiting for explicit next action.` }],
|
|
1222
|
-
details
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1313
|
+
details,
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
const intercomReceipt = await maybeBuildForegroundIntercomReceipt({
|
|
1318
|
+
pi: deps.pi,
|
|
1319
|
+
intercomBridge: data.intercomBridge,
|
|
1320
|
+
runId,
|
|
1321
|
+
mode: "parallel",
|
|
1322
|
+
details,
|
|
1323
|
+
});
|
|
1324
|
+
if (intercomReceipt) {
|
|
1325
|
+
return {
|
|
1326
|
+
content: [{ type: "text", text: intercomReceipt.text }],
|
|
1327
|
+
details: intercomReceipt.details,
|
|
1228
1328
|
};
|
|
1229
1329
|
}
|
|
1230
1330
|
|
|
@@ -1248,12 +1348,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1248
1348
|
|
|
1249
1349
|
return {
|
|
1250
1350
|
content: [{ type: "text", text: fullContent }],
|
|
1251
|
-
details
|
|
1252
|
-
mode: "parallel",
|
|
1253
|
-
results,
|
|
1254
|
-
progress: params.includeProgress ? allProgress : undefined,
|
|
1255
|
-
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1256
|
-
}),
|
|
1351
|
+
details,
|
|
1257
1352
|
};
|
|
1258
1353
|
} finally {
|
|
1259
1354
|
if (worktreeSetup) cleanupWorktrees(worktreeSetup);
|
|
@@ -1472,54 +1567,54 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1472
1567
|
savedPath: r.savedOutputPath,
|
|
1473
1568
|
saveError: r.outputSaveError,
|
|
1474
1569
|
});
|
|
1570
|
+
const details = compactForegroundDetails({
|
|
1571
|
+
mode: "single",
|
|
1572
|
+
results: [r],
|
|
1573
|
+
progress: params.includeProgress ? allProgress : undefined,
|
|
1574
|
+
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1575
|
+
truncation: r.truncation,
|
|
1576
|
+
});
|
|
1577
|
+
|
|
1578
|
+
if (!r.detached && !r.interrupted) {
|
|
1579
|
+
const intercomReceipt = await maybeBuildForegroundIntercomReceipt({
|
|
1580
|
+
pi: deps.pi,
|
|
1581
|
+
intercomBridge: data.intercomBridge,
|
|
1582
|
+
runId,
|
|
1583
|
+
mode: "single",
|
|
1584
|
+
details,
|
|
1585
|
+
});
|
|
1586
|
+
if (intercomReceipt) {
|
|
1587
|
+
return {
|
|
1588
|
+
content: [{ type: "text", text: intercomReceipt.text }],
|
|
1589
|
+
details: intercomReceipt.details,
|
|
1590
|
+
...(r.exitCode !== 0 ? { isError: true } : {}),
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1475
1594
|
|
|
1476
1595
|
if (r.detached) {
|
|
1477
1596
|
return {
|
|
1478
1597
|
content: [{ type: "text", text: `Detached for intercom coordination: ${params.agent}` }],
|
|
1479
|
-
details
|
|
1480
|
-
mode: "single",
|
|
1481
|
-
results: [r],
|
|
1482
|
-
progress: params.includeProgress ? allProgress : undefined,
|
|
1483
|
-
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1484
|
-
truncation: r.truncation,
|
|
1485
|
-
}),
|
|
1598
|
+
details,
|
|
1486
1599
|
};
|
|
1487
1600
|
}
|
|
1488
1601
|
|
|
1489
1602
|
if (r.interrupted) {
|
|
1490
1603
|
return {
|
|
1491
1604
|
content: [{ type: "text", text: `Run paused after interrupt (${params.agent}). Waiting for explicit next action.` }],
|
|
1492
|
-
details
|
|
1493
|
-
mode: "single",
|
|
1494
|
-
results: [r],
|
|
1495
|
-
progress: params.includeProgress ? allProgress : undefined,
|
|
1496
|
-
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1497
|
-
truncation: r.truncation,
|
|
1498
|
-
}),
|
|
1605
|
+
details,
|
|
1499
1606
|
};
|
|
1500
1607
|
}
|
|
1501
1608
|
|
|
1502
1609
|
if (r.exitCode !== 0)
|
|
1503
1610
|
return {
|
|
1504
1611
|
content: [{ type: "text", text: r.error || "Failed" }],
|
|
1505
|
-
details
|
|
1506
|
-
mode: "single",
|
|
1507
|
-
results: [r],
|
|
1508
|
-
progress: params.includeProgress ? allProgress : undefined,
|
|
1509
|
-
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1510
|
-
truncation: r.truncation,
|
|
1511
|
-
}),
|
|
1612
|
+
details,
|
|
1512
1613
|
isError: true,
|
|
1513
1614
|
};
|
|
1514
1615
|
return {
|
|
1515
1616
|
content: [{ type: "text", text: finalizedOutput.displayOutput || "(no output)" }],
|
|
1516
|
-
details
|
|
1517
|
-
mode: "single",
|
|
1518
|
-
results: [r],
|
|
1519
|
-
progress: params.includeProgress ? allProgress : undefined,
|
|
1520
|
-
artifacts: allArtifactPaths.length ? { dir: artifactsDir, files: allArtifactPaths } : undefined,
|
|
1521
|
-
truncation: r.truncation,
|
|
1522
|
-
}),
|
|
1617
|
+
details,
|
|
1523
1618
|
};
|
|
1524
1619
|
}
|
|
1525
1620
|
|
package/subagent-runner.ts
CHANGED
|
@@ -75,6 +75,7 @@ interface SubagentRunConfig {
|
|
|
75
75
|
controlConfig?: ResolvedControlConfig;
|
|
76
76
|
controlIntercomTarget?: string;
|
|
77
77
|
childIntercomTargets?: Array<string | undefined>;
|
|
78
|
+
resultMode?: "single" | "parallel" | "chain";
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
interface StepResult {
|
|
@@ -82,6 +83,7 @@ interface StepResult {
|
|
|
82
83
|
output: string;
|
|
83
84
|
success: boolean;
|
|
84
85
|
skipped?: boolean;
|
|
86
|
+
intercomTarget?: string;
|
|
85
87
|
model?: string;
|
|
86
88
|
attemptedModels?: string[];
|
|
87
89
|
modelAttempts?: ModelAttempt[];
|
|
@@ -542,6 +544,7 @@ async function runSingleStep(
|
|
|
542
544
|
modelAttempts?: ModelAttempt[];
|
|
543
545
|
artifactPaths?: ArtifactPaths;
|
|
544
546
|
interrupted?: boolean;
|
|
547
|
+
intercomTarget?: string;
|
|
545
548
|
}> {
|
|
546
549
|
const placeholderRegex = new RegExp(ctx.placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
|
547
550
|
const task = step.task.replace(placeholderRegex, () => ctx.previousOutput);
|
|
@@ -671,6 +674,7 @@ async function runSingleStep(
|
|
|
671
674
|
output: outputForSummary,
|
|
672
675
|
exitCode: finalResult?.exitCode ?? 1,
|
|
673
676
|
error: finalResult?.error,
|
|
677
|
+
intercomTarget: ctx.childIntercomTarget,
|
|
674
678
|
model: finalResult?.model,
|
|
675
679
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
676
680
|
modelAttempts,
|
|
@@ -1147,6 +1151,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1147
1151
|
output: pr.output,
|
|
1148
1152
|
success: pr.exitCode === 0,
|
|
1149
1153
|
skipped: pr.skipped,
|
|
1154
|
+
intercomTarget: pr.intercomTarget,
|
|
1150
1155
|
model: pr.model,
|
|
1151
1156
|
attemptedModels: pr.attemptedModels,
|
|
1152
1157
|
modelAttempts: pr.modelAttempts,
|
|
@@ -1225,6 +1230,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1225
1230
|
agent: singleResult.agent,
|
|
1226
1231
|
output: singleResult.output,
|
|
1227
1232
|
success: singleResult.exitCode === 0,
|
|
1233
|
+
intercomTarget: singleResult.intercomTarget,
|
|
1228
1234
|
model: singleResult.model,
|
|
1229
1235
|
attemptedModels: singleResult.attemptedModels,
|
|
1230
1236
|
modelAttempts: singleResult.modelAttempts,
|
|
@@ -1386,6 +1392,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1386
1392
|
writeJson(resultPath, {
|
|
1387
1393
|
id,
|
|
1388
1394
|
agent: agentName,
|
|
1395
|
+
mode: config.resultMode ?? statusPayload.mode,
|
|
1389
1396
|
success: !interrupted && results.every((r) => r.success),
|
|
1390
1397
|
state: interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed",
|
|
1391
1398
|
summary: interrupted ? "Paused after interrupt. Waiting for explicit next action." : summary,
|
|
@@ -1394,6 +1401,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1394
1401
|
output: r.output,
|
|
1395
1402
|
success: r.success,
|
|
1396
1403
|
skipped: r.skipped || undefined,
|
|
1404
|
+
intercomTarget: r.intercomTarget,
|
|
1397
1405
|
model: r.model,
|
|
1398
1406
|
attemptedModels: r.attemptedModels,
|
|
1399
1407
|
modelAttempts: r.modelAttempts,
|
|
@@ -1409,6 +1417,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1409
1417
|
asyncDir,
|
|
1410
1418
|
sessionId: config.sessionId,
|
|
1411
1419
|
sessionFile: effectiveSessionFile,
|
|
1420
|
+
intercomTarget: config.controlIntercomTarget,
|
|
1412
1421
|
shareUrl,
|
|
1413
1422
|
gistUrl,
|
|
1414
1423
|
shareError,
|
package/types.ts
CHANGED
|
@@ -69,6 +69,37 @@ export interface ControlEvent {
|
|
|
69
69
|
message: string;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export type SubagentResultStatus = "completed" | "failed" | "paused" | "detached";
|
|
73
|
+
|
|
74
|
+
export interface SubagentResultIntercomChild {
|
|
75
|
+
agent: string;
|
|
76
|
+
status: SubagentResultStatus;
|
|
77
|
+
summary: string;
|
|
78
|
+
index?: number;
|
|
79
|
+
artifactPath?: string;
|
|
80
|
+
sessionPath?: string;
|
|
81
|
+
intercomTarget?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SubagentResultIntercomPayload {
|
|
85
|
+
to: string;
|
|
86
|
+
message: string;
|
|
87
|
+
requestId?: string;
|
|
88
|
+
runId: string;
|
|
89
|
+
mode: "single" | "parallel" | "chain";
|
|
90
|
+
status: SubagentResultStatus;
|
|
91
|
+
summary: string;
|
|
92
|
+
source: "foreground" | "async";
|
|
93
|
+
children: SubagentResultIntercomChild[];
|
|
94
|
+
asyncId?: string;
|
|
95
|
+
asyncDir?: string;
|
|
96
|
+
chainSteps?: number;
|
|
97
|
+
agent?: string;
|
|
98
|
+
index?: number;
|
|
99
|
+
artifactPath?: string;
|
|
100
|
+
sessionPath?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
// ============================================================================
|
|
73
104
|
// Progress Tracking
|
|
74
105
|
// ============================================================================
|
|
@@ -310,6 +341,8 @@ export const SUBAGENT_ASYNC_STARTED_EVENT = "subagent:async-started";
|
|
|
310
341
|
export const SUBAGENT_ASYNC_COMPLETE_EVENT = "subagent:async-complete";
|
|
311
342
|
export const SUBAGENT_CONTROL_EVENT = "subagent:control-event";
|
|
312
343
|
export const SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
|
|
344
|
+
export const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
|
|
345
|
+
export const SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
|
|
313
346
|
|
|
314
347
|
// ============================================================================
|
|
315
348
|
// Execution Options
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: oracle-executor
|
|
3
|
-
description: High-context implementation agent that executes only after main-agent approval
|
|
4
|
-
tools: read, grep, find, ls, bash, edit, write, intercom
|
|
5
|
-
model: openai-codex/gpt-5.5
|
|
6
|
-
thinking: high
|
|
7
|
-
systemPromptMode: replace
|
|
8
|
-
inheritProjectContext: true
|
|
9
|
-
inheritSkills: false
|
|
10
|
-
defaultProgress: true
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
You are `oracle-executor`: a high-context implementation subagent.
|
|
14
|
-
|
|
15
|
-
You are the single writer thread. Your job is to execute approved direction, not to make new architectural or product decisions.
|
|
16
|
-
|
|
17
|
-
You are invoked after the main agent has already decided on a direction, often based on advice from `oracle`. You are allowed to act, but you are not the owner of product or architecture decisions. The main agent remains the final decision authority.
|
|
18
|
-
|
|
19
|
-
If runtime bridge instructions are present, use them as the source of truth for which orchestrator session to contact and how to coordinate. Use `intercom({ action: "ask", ... })` when a new decision is needed to continue safely. Use `intercom({ action: "send", ... })` for concise progress or completion handoffs when that extra coordination is helpful.
|
|
20
|
-
|
|
21
|
-
First understand the inherited context and the explicit task. Then execute carefully and minimally.
|
|
22
|
-
|
|
23
|
-
If the task appears to require a new decision that has not clearly been approved by the main agent, stop and ask via `intercom` instead of making that decision yourself.
|
|
24
|
-
|
|
25
|
-
Default responsibilities:
|
|
26
|
-
- validate the approved direction against the actual code
|
|
27
|
-
- implement the approved change with minimal, coherent edits
|
|
28
|
-
- verify the result with appropriate checks
|
|
29
|
-
- report back clearly, including risks and next steps
|
|
30
|
-
|
|
31
|
-
Working rules:
|
|
32
|
-
- Follow existing patterns in the codebase.
|
|
33
|
-
- Prefer narrow, correct changes over broad rewrites.
|
|
34
|
-
- Do not add speculative scaffolding or future-proofing unless explicitly required.
|
|
35
|
-
- Use `bash` for inspection, validation, and relevant tests.
|
|
36
|
-
- Escalate uncertainty to the main agent with `intercom` when needed.
|
|
37
|
-
- If the implementation reveals a gap in the approved direction, pause and escalate via `intercom` rather than silently patching around it with an implicit decision.
|
|
38
|
-
- If implementation reveals an unapproved product or architecture choice, pause and ask via `intercom` instead of deciding it yourself.
|
|
39
|
-
- If you send a completion handoff through `intercom`, keep it short and still return the full structured task result normally.
|
|
40
|
-
- Keep `progress.md` accurate when asked to maintain it.
|
|
41
|
-
- Do not silently change the scope of the task.
|
|
42
|
-
|
|
43
|
-
Your completion handoff should follow this exact shape:
|
|
44
|
-
|
|
45
|
-
Implemented X.
|
|
46
|
-
Changed files: Y.
|
|
47
|
-
Validation: Z.
|
|
48
|
-
Open risks/questions: R.
|
|
49
|
-
Recommended next step: N.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Send an explicitly approved task to oracle-executor with full inherited context.
|
|
3
|
-
subagent: oracle-executor
|
|
4
|
-
inheritContext: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Launch the oracle-executor subagent with a strict implementation meta prompt that points it at the plan and asks it to execute:
|
|
8
|
-
|
|
9
|
-
$@
|