pi-cohort 5.3.4 → 6.0.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 +15 -1
- package/README.md +0 -1
- package/agents/context-builder.md +4 -4
- package/agents/delegate.md +2 -2
- package/agents/monitor.md +3 -4
- package/agents/oracle.md +3 -7
- package/agents/planner.md +3 -3
- package/agents/reviewer.md +3 -5
- package/agents/scout.md +3 -3
- package/agents/worker.md +3 -6
- package/package.json +1 -1
- package/skills/pi-cohort/SKILL.md +19 -81
- package/skills/pi-cohort/reference/config-fields.md +1 -1
- package/src/extension/control-notices.ts +5 -12
- package/src/extension/doctor.ts +0 -29
- package/src/extension/fanout-child.ts +1 -16
- package/src/extension/index.ts +2 -2
- package/src/runs/background/async-execution.ts +2 -31
- package/src/runs/background/async-job-tracker.ts +2 -11
- package/src/runs/background/async-resume.ts +7 -38
- package/src/runs/background/result-watcher.ts +5 -33
- package/src/runs/background/run-status.ts +0 -4
- package/src/runs/background/subagent-runner.ts +15 -45
- package/src/runs/foreground/chain-execution.ts +1 -54
- package/src/runs/foreground/execution.ts +18 -60
- package/src/runs/foreground/subagent-executor.ts +18 -274
- package/src/runs/shared/completion-guard.ts +5 -2
- package/src/runs/shared/nested-events.ts +0 -3
- package/src/runs/shared/pi-args.ts +0 -9
- package/src/runs/shared/result-children.ts +89 -0
- package/src/runs/shared/subagent-control.ts +8 -37
- package/src/runs/shared/subagent-prompt-runtime.ts +0 -6
- package/src/runs/shared/workflow-graph.ts +2 -6
- package/src/shared/types.ts +7 -49
- package/src/shared/utils.ts +2 -4
- package/src/tui/render.ts +8 -12
- package/src/intercom/intercom-bridge.ts +0 -379
- package/src/intercom/result-intercom.ts +0 -377
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [6.0.1] - 2026-09-07
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `getFinalOutput` no longer truncates a multi-block assistant reply to its last text block; it now joins all non-empty text blocks with `\n`. Previously a `BLOCKED:` line in an earlier block was dropped, so the `BLOCKED:` classifier misread a blocked reply as successful (or a completed reply whose trailing block happened to start with `BLOCKED:` as failed).
|
|
8
|
+
|
|
9
|
+
## [6.0.0] - 2026-09-07
|
|
10
|
+
|
|
11
|
+
### Removed
|
|
12
|
+
|
|
13
|
+
- **BREAKING:** Removed the pi-intercom integration: bridge, `intercomBridge` config, `intercom`/`contact_supervisor` tools, `notifyChannels: ["intercom"]`, intercom result/receipt delivery, doctor section, and foreground detach lifecycle. Stale config keys are ignored. ([#11](https://github.com/jjuraszek/pi-cohort/issues/11))
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **BREAKING:** Unapproved decisions now use the `BLOCKED:` result contract; `resume` on a running child errors, while finished, failed, and paused siblings remain revivable; foreground abort terminates the child normally. Proposed version bump: 5.3.1 -> 6.0.0. ([#11](https://github.com/jjuraszek/pi-cohort/issues/11))
|
|
4
18
|
|
|
5
19
|
## [5.3.4] - 2026-09-07
|
|
6
20
|
|
package/README.md
CHANGED
|
@@ -121,7 +121,6 @@ Parent extension CLI flags (e.g. pi-lens's `--no-autofix`) are forwarded into sp
|
|
|
121
121
|
|
|
122
122
|
Optional companions:
|
|
123
123
|
|
|
124
|
-
- [pi-intercom](https://github.com/jjuraszek/pi-intercom) - lets a blocked child ask the parent a question instead of guessing. [doc/skills-and-companions.md](doc/skills-and-companions.md#optional-pi-intercom-companion)
|
|
125
124
|
- [pi-essentials](https://github.com/jjuraszek/pi-essentials) - lets `context-builder` read referenced URLs. [doc/skills-and-companions.md](doc/skills-and-companions.md#optional-pi-essentials-companion)
|
|
126
125
|
|
|
127
126
|
## Deeper reference
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-builder
|
|
3
3
|
description: Analyzes requirements and codebase, generates context and meta-prompt
|
|
4
|
-
tools: read, grep, find, ls, bash, write, fetch
|
|
4
|
+
tools: read, grep, find, ls, bash, write, fetch
|
|
5
5
|
thinking: medium
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -36,10 +36,10 @@ When running in a chain, expect to generate two files in the chain directory:
|
|
|
36
36
|
- hard constraints: true invariants only, such as no edits for review-only work or escalation for unapproved decisions
|
|
37
37
|
- suggested approach: concise direction without over-specifying every step
|
|
38
38
|
- validation: targeted checks to run, or the next-best check if validation is unavailable
|
|
39
|
-
- stop
|
|
39
|
+
- stop rules: when enough evidence is enough and when to stop
|
|
40
40
|
- resolved questions and assumptions
|
|
41
41
|
|
|
42
42
|
The goal is to hand the planner or another role subagent exactly enough code and requirement context to act without rediscovering the same ground. Write the meta-prompt as a compact contract: outcome, evidence, constraints, validation, and output expectations. Avoid long procedural scripts unless each step is a real requirement.
|
|
43
43
|
|
|
44
|
-
##
|
|
45
|
-
If
|
|
44
|
+
## Decision blockers
|
|
45
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
package/agents/delegate.md
CHANGED
|
@@ -3,10 +3,10 @@ name: delegate
|
|
|
3
3
|
description: Lightweight subagent that inherits the parent model with no default reads
|
|
4
4
|
systemPromptMode: append
|
|
5
5
|
inheritProjectContext: true
|
|
6
|
-
tools: read, grep, find, ls, bash, edit, write
|
|
6
|
+
tools: read, grep, find, ls, bash, edit, write
|
|
7
7
|
inheritSkills: false
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
You are a delegated agent. Execute the assigned task using the provided tools. Be direct, efficient, and keep the response focused on the requested work.
|
|
11
11
|
|
|
12
|
-
If
|
|
12
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
package/agents/monitor.md
CHANGED
|
@@ -16,11 +16,10 @@ Loop:
|
|
|
16
16
|
1. Record your start time. Run the first check immediately, before any sleep.
|
|
17
17
|
2. Each cycle: check the target is alive, collect progress (new log lines, counts, phases, best-effort ETA), and compose a one-line delta vs the previous cycle.
|
|
18
18
|
3. Append the delta with a timestamp to the trail.
|
|
19
|
-
4.
|
|
20
|
-
5. Sleep the cadence interval in chunks of <= 5 minutes, then repeat.
|
|
19
|
+
4. Sleep the cadence interval in chunks of <= 5 minutes, then repeat.
|
|
21
20
|
|
|
22
21
|
Cadence: every 15 minutes unless the task sets another interval.
|
|
23
22
|
|
|
24
|
-
Stall: no growth in the watched log and no change in status.json lastUpdate since the previous cycle. Judge stall only by the signals your target has; a signal that does not exist never counts as change.
|
|
23
|
+
Stall: no growth in the watched log and no change in status.json lastUpdate since the previous cycle. Judge stall only by the signals your target has; a signal that does not exist never counts as change. Record "no output for <interval>, possible stall" in the trail only. Never report "still working" without evidence.
|
|
25
24
|
|
|
26
|
-
Exit: when the target reaches a terminal state, send a final summary and end - the summary is your run result. Stop 24h after your recorded start time even if the target lives.
|
|
25
|
+
Exit: when the target reaches a terminal state, send a final summary and end - the summary is your run result. Stop 24h after your recorded start time even if the target lives. The trail and final summary are the record.
|
package/agents/oracle.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oracle
|
|
3
3
|
description: High-context decision-consistency oracle that protects inherited state and prevents drift
|
|
4
|
-
tools: read, grep, find, ls, bash
|
|
4
|
+
tools: read, grep, find, ls, bash
|
|
5
5
|
thinking: high
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -15,9 +15,7 @@ Your primary job is to prevent the main agent from making hidden, conflicting, o
|
|
|
15
15
|
|
|
16
16
|
Before you do anything else, reconstruct the key inherited decisions, constraints, and open questions from the forked conversation, codebase state, and task. Those decisions form your baseline contract. Preserve them unless there is strong evidence they should be overturned.
|
|
17
17
|
|
|
18
|
-
If
|
|
19
|
-
|
|
20
|
-
Do not send routine completion handoffs. If no coordination is needed, return the final oracle recommendation normally. Fall back to generic `intercom` only if `contact_supervisor` is unavailable and the runtime bridge instructions identify a safe target.
|
|
18
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
|
21
19
|
|
|
22
20
|
Core responsibilities:
|
|
23
21
|
- reconstruct inherited decisions, constraints, and open questions from the context
|
|
@@ -38,9 +36,7 @@ What you do not do by default:
|
|
|
38
36
|
|
|
39
37
|
Working rules:
|
|
40
38
|
- Use `bash` only for inspection, verification, or read-only analysis.
|
|
41
|
-
- If information is missing
|
|
42
|
-
- If the answer depends on a decision the main agent has not made yet, stop and ask with `contact_supervisor` before continuing.
|
|
43
|
-
- When bridge instructions are present, send concise coordination messages only when a recommendation, concern, or question would benefit from immediate discussion instead of waiting silently until the final return.
|
|
39
|
+
- If information is missing or depends on an unmade decision, follow the blocker rule.
|
|
44
40
|
- Prefer narrow, specific corrections to the current path over rewriting the whole plan.
|
|
45
41
|
|
|
46
42
|
Your output should follow this shape. If no executor handoff is warranted, say so plainly.
|
package/agents/planner.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: planner
|
|
3
3
|
description: Creates implementation plans from context and requirements
|
|
4
|
-
tools: read, grep, find, ls, write
|
|
4
|
+
tools: read, grep, find, ls, write
|
|
5
5
|
thinking: high
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -51,5 +51,5 @@ Anything likely to go wrong, need clarification, or need careful verification.
|
|
|
51
51
|
|
|
52
52
|
Keep the plan concrete. Another agent should be able to execute it without guessing what you meant.
|
|
53
53
|
|
|
54
|
-
##
|
|
55
|
-
If
|
|
54
|
+
## Decision blockers
|
|
55
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
package/agents/reviewer.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: Versatile review specialist for code diffs, plans, proposed solutions, codebase health, and PR/issue validation
|
|
4
|
-
tools: read, grep, find, ls, bash, edit, write
|
|
4
|
+
tools: read, grep, find, ls, bash, edit, write
|
|
5
5
|
thinking: high
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -72,10 +72,8 @@ When asked to review for over-engineering, bloat, or "what can we delete", run a
|
|
|
72
72
|
- If you are asked to maintain progress, record what you checked and what you found.
|
|
73
73
|
- If review-only or no-edit instructions conflict with progress-writing instructions, review-only/no-edit wins. Do not write `progress.md`; mention the conflict in your final review only if it matters.
|
|
74
74
|
|
|
75
|
-
##
|
|
76
|
-
If
|
|
77
|
-
|
|
78
|
-
Fall back to generic `intercom` only if `contact_supervisor` is unavailable and the runtime bridge instructions identify a safe target. If no safe target is discoverable, do not guess.
|
|
75
|
+
## Decision blockers
|
|
76
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing; no-edit wins.
|
|
79
77
|
|
|
80
78
|
## Review output format
|
|
81
79
|
Structure your findings clearly:
|
package/agents/scout.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: scout
|
|
3
3
|
description: Fast codebase recon that returns compressed context for handoff
|
|
4
|
-
tools: read, grep, find, ls, bash, write
|
|
4
|
+
tools: read, grep, find, ls, bash, write
|
|
5
5
|
thinking: low
|
|
6
6
|
systemPromptMode: replace
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -46,5 +46,5 @@ Explain how the pieces connect.
|
|
|
46
46
|
## Start Here
|
|
47
47
|
Name the first file another agent should open and why.
|
|
48
48
|
|
|
49
|
-
##
|
|
50
|
-
If
|
|
49
|
+
## Decision blockers
|
|
50
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
package/agents/worker.md
CHANGED
|
@@ -5,7 +5,7 @@ thinking: high
|
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
8
|
-
tools: read, grep, find, ls, bash, edit, write
|
|
8
|
+
tools: read, grep, find, ls, bash, edit, write
|
|
9
9
|
defaultContext: fork
|
|
10
10
|
defaultReads: context.md, plan.md
|
|
11
11
|
defaultProgress: true
|
|
@@ -19,7 +19,7 @@ Use the provided tools directly. First understand the inherited context, supplie
|
|
|
19
19
|
|
|
20
20
|
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.
|
|
21
21
|
|
|
22
|
-
If
|
|
22
|
+
If an unapproved decision is required to continue safely, stop: begin your reply `BLOCKED: <decision needed>`, then `Done: <complete>` and `Remaining: <left>`; no heading, bold, list marker, or code fence; do not guess or wait for a reply.
|
|
23
23
|
|
|
24
24
|
Default responsibilities:
|
|
25
25
|
- validate the task or approved direction against the actual code
|
|
@@ -47,10 +47,7 @@ Working rules:
|
|
|
47
47
|
- Mark a deliberate shortcut with a comment naming the ceiling and the upgrade path when the limit is non-obvious.
|
|
48
48
|
- Use `bash` for inspection, validation, and relevant tests.
|
|
49
49
|
- If there is supplied context or a plan, read it first.
|
|
50
|
-
- If
|
|
51
|
-
- If implementation reveals an unapproved product or architecture choice, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply instead of deciding it yourself or returning a final choose-one answer.
|
|
52
|
-
- If your delegated task expects code or file edits and you have not made those edits, do not return a success summary. Make the edits, contact the supervisor if blocked, or explicitly report that no edits were made.
|
|
53
|
-
- If you send a blocked/progress update through `contact_supervisor`, keep it short and still return the full structured task result normally.
|
|
50
|
+
- If your delegated task expects code or file edits and you have not made those edits, do not return a success summary. Make the edits or explicitly report that no edits were made.
|
|
54
51
|
- Do not send routine completion handoffs. Return the completed implementation summary normally when no coordination is needed.
|
|
55
52
|
|
|
56
53
|
When running in a chain, expect instructions about:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cohort",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"license": "MIT",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: pi-cohort
|
|
3
3
|
description: |
|
|
4
4
|
Delegate work to builtin or custom subagents with single-agent, chain,
|
|
5
|
-
parallel, async, forked-context
|
|
5
|
+
parallel, async, and forked-context workflows. Use
|
|
6
6
|
for advisory review, implementation handoffs, and multi-step tasks where a
|
|
7
7
|
single agent should stay in control while other agents contribute context,
|
|
8
8
|
planning, or execution.
|
|
@@ -33,7 +33,7 @@ Humans often use the slash-command layer instead:
|
|
|
33
33
|
- `/chain` — launch a chain of steps
|
|
34
34
|
- `/parallel` — launch top-level parallel tasks
|
|
35
35
|
- `/run-chain` — launch a saved `.chain.md` or `.chain.json` workflow
|
|
36
|
-
- `/cohort-doctor` — diagnose setup, discovery, async paths
|
|
36
|
+
- `/cohort-doctor` — diagnose setup, discovery, and async paths
|
|
37
37
|
|
|
38
38
|
Prefer the tool when you are writing agent logic. Prefer the slash commands when
|
|
39
39
|
you are guiding a human through an interactive flow.
|
|
@@ -147,11 +147,11 @@ and user/project agents override builtins with the same name.
|
|
|
147
147
|
|-------|---------|-------|------------------------|
|
|
148
148
|
| `scout` | Fast codebase recon | inherits default | Writes `context.md` handoff material |
|
|
149
149
|
| `planner` | Creates implementation plans | inherits default | Writes `plan.md` |
|
|
150
|
-
| `worker` | Implementation and approved oracle handoffs | inherits default | Single-writer implementation
|
|
150
|
+
| `worker` | Implementation and approved oracle handoffs | inherits default | Single-writer implementation |
|
|
151
151
|
| `reviewer` | Review-and-fix specialist | inherits default | Can edit/fix reviewed code |
|
|
152
152
|
| `context-builder` | Requirements/codebase handoff builder | inherits default | Writes structured context files |
|
|
153
153
|
| `delegate` | Lightweight generic delegate | inherits default | No fixed output; generic delegated work |
|
|
154
|
-
| `oracle` | Decision-consistency advisory review | inherits default | Advisory review
|
|
154
|
+
| `oracle` | Decision-consistency advisory review | inherits default | Advisory review |
|
|
155
155
|
|
|
156
156
|
Builtin agents inherit the current Pi default model unless a run, user setting, or project setting overrides `model`. Override builtin defaults before copying full agent files when a small tweak is enough.
|
|
157
157
|
|
|
@@ -171,14 +171,14 @@ A strong subagent prompt usually includes:
|
|
|
171
171
|
- **Goal**: the concrete outcome the child should produce.
|
|
172
172
|
- **Context/evidence**: relevant plan paths, files, diffs, decisions, or user constraints already approved.
|
|
173
173
|
- **Success criteria**: what must be true before the child can finish.
|
|
174
|
-
- **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
|
|
174
|
+
- **Hard constraints**: true invariants only, such as no edits for review-only tasks, one writer thread, or child must not run subagents unless it is an explicitly assigned `tools: subagent` fanout child.
|
|
175
175
|
- **Validation**: targeted checks to run, or the next-best check when validation is impossible.
|
|
176
176
|
- **Output**: the expected summary shape, artifact path, or finding format.
|
|
177
|
-
- **Stop rules**: when to
|
|
177
|
+
- **Stop rules**: when to stop after enough evidence, when not to keep searching, and when to report an unapproved decision.
|
|
178
178
|
|
|
179
179
|
Avoid carrying over old prompt habits that over-specify every step. Use `must`, `always`, and `never` for real invariants; for judgment calls, give decision rules. For example, tell a reviewer to inspect the staged diff directly and report only evidence-backed findings, rather than prescribing every file or command. Tell a `context-builder` the retrieval budget: fetch the referenced sources, extract the strongest evidence, fetch again only when a required fact is missing, then stop.
|
|
180
180
|
|
|
181
|
-
For implementation handoffs, name the approved scope and success criteria more clearly than the process. Good prompts say what to change, what not to change, where the evidence lives, how to validate, and
|
|
181
|
+
For implementation handoffs, name the approved scope and success criteria more clearly than the process. Good prompts say what to change, what not to change, where the evidence lives, how to validate, and which decisions are already approved. They should not ask the child to create another subagent plan or continue the parent conversation.
|
|
182
182
|
|
|
183
183
|
Settings locations:
|
|
184
184
|
- User scope: `~/.pi/agent/settings.json`
|
|
@@ -335,11 +335,11 @@ subagent({ action: "resume", id: "nested-run-id", message: "Continue this nested
|
|
|
335
335
|
```
|
|
336
336
|
|
|
337
337
|
Resume behavior:
|
|
338
|
-
-
|
|
339
|
-
-
|
|
340
|
-
- Multi-child async runs require `index` unless only one
|
|
338
|
+
- A running child cannot be resumed: `Selected child is still active; wait for completion, then resume.`
|
|
339
|
+
- A finished, failed, or paused child is revived by starting a new async child from its persisted child session file.
|
|
340
|
+
- Multi-child async runs require `index` unless only one child is selectable. A finished sibling can be revived while another sibling is running.
|
|
341
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
|
|
342
|
+
- Nested runs can be resumed by nested id when persisted nested session metadata is available; a running nested child errors with `Nested run <id> is still active; wait for completion, then resume.`
|
|
343
343
|
- Revive starts a new child process from the old session context; it does not restart the same OS process.
|
|
344
344
|
- If the chosen child has no persisted `.jsonl` session file, resume fails and reports that directly.
|
|
345
345
|
|
|
@@ -349,7 +349,7 @@ Use diagnostics when setup or child startup looks wrong:
|
|
|
349
349
|
subagent({ action: "doctor" })
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
-
Humans can use `/cohort-doctor` for the same read-only report. It checks runtime paths, discovery counts, async support, current session context
|
|
352
|
+
Humans can use `/cohort-doctor` for the same read-only report. It checks runtime paths, discovery counts, async support, and current session context.
|
|
353
353
|
|
|
354
354
|
Long-running job hygiene:
|
|
355
355
|
|
|
@@ -362,13 +362,12 @@ subagent({ agent: "worker", async: true, task: "<long job - emit progress lines
|
|
|
362
362
|
subagent({ agent: "monitor", async: true, task: "Watch async run R at <D>. Report every 15m. Stop when it ends." })
|
|
363
363
|
```
|
|
364
364
|
|
|
365
|
-
- Live 15m reports require the pi-intercom bridge; without it the monitor's trail and final summary are post-hoc records.
|
|
366
365
|
|
|
367
366
|
### Subagent control
|
|
368
367
|
|
|
369
368
|
Subagent control is the runtime visibility and intervention layer for delegated runs. It is separate from lifecycle status. Lifecycle status says whether a child is `queued`, `running`, `paused`, `complete`, or `failed`. Activity reporting is factual: it tracks the last observed activity time and the current tool when known. It does not pretend to know that a child is truly stuck.
|
|
370
369
|
|
|
371
|
-
Default behavior is intentionally conservative. When no activity has been observed past the configured threshold, the run emits a `needs_attention` control event. Foreground runs can push this as a `subagent:control-event` event, and async runs persist it to `events.jsonl` so the parent tracker can surface it without constant manual polling. Notification-worthy control events are also inserted into the visible transcript so both the user and the parent agent can see them, with a proactive hint plus concrete `
|
|
370
|
+
Default behavior is intentionally conservative. When no activity has been observed past the configured threshold, the run emits a `needs_attention` control event. Foreground runs can push this as a `subagent:control-event` event, and async runs persist it to `events.jsonl` so the parent tracker can surface it without constant manual polling. Notification-worthy control events are also inserted into the visible transcript so both the user and the parent agent can see them, with a proactive hint plus concrete `status` and `interrupt` options. Visible notifications fire once per child run and attention state.
|
|
372
371
|
|
|
373
372
|
Use soft interrupt when a child is clearly blocked or drifting and the parent needs to regain control:
|
|
374
373
|
|
|
@@ -398,8 +397,6 @@ subagent({
|
|
|
398
397
|
})
|
|
399
398
|
```
|
|
400
399
|
|
|
401
|
-
If the run already has an active intercom bridge target, needs-attention notifications can also prepare a compact intercom ping for the orchestrator. When a child route is available, the ping tells the orchestrator which agent needs attention and includes the exact `intercom({ action: "send", to: "..." })` target for a nudge. Do not invent a target or ask the child to self-report when no bridge exists.
|
|
402
|
-
|
|
403
400
|
## Clarify TUI
|
|
404
401
|
|
|
405
402
|
Single and parallel runs support a clarification TUI when you want to preview or
|
|
@@ -442,9 +439,8 @@ prefer a single-writer pattern instead.
|
|
|
442
439
|
The intended oracle loop is:
|
|
443
440
|
1. the main agent forks to `oracle`
|
|
444
441
|
2. `oracle` reviews direction, drift, assumptions, and risks
|
|
445
|
-
3.
|
|
446
|
-
4.
|
|
447
|
-
5. only then should `worker` implement
|
|
442
|
+
3. the main agent decides what direction to approve
|
|
443
|
+
4. only then should `worker` implement
|
|
448
444
|
|
|
449
445
|
```typescript
|
|
450
446
|
// Advisory review in a branched thread. Oracle defaults to forked context.
|
|
@@ -466,52 +462,6 @@ history as a baseline contract.
|
|
|
466
462
|
|
|
467
463
|
Use `oracle` as a smart-friend escalation when the parent needs help with trajectory rather than diff inspection: architectural boundaries, model capability routing, merge conflicts, reviewer disagreement, context drift after long work, a worker about to invent a pattern, or fixes that require product/scope tradeoffs. Ask broad questions when the right concern is unclear, and let `oracle` point out missing context or files the parent should inspect before asking again. Keep `oracle` advisory unless it has been explicitly assigned the single writer role.
|
|
468
464
|
|
|
469
|
-
## Subagent + Intercom Coordination
|
|
470
|
-
|
|
471
|
-
`pi-cohort` works without `pi-intercom`. When `pi-intercom` is installed and enabled, the intercom bridge can automatically give child agents a private coordination channel back to the parent session.
|
|
472
|
-
|
|
473
|
-
Most agents should not call generic `intercom` directly unless bridge instructions provide a target and `contact_supervisor` is unavailable. Do not invent a target. Prefer the tool from the injected bridge instructions.
|
|
474
|
-
|
|
475
|
-
Use `contact_supervisor` with `reason: "need_decision"` when:
|
|
476
|
-
- a subagent is blocked on a decision
|
|
477
|
-
- a child needs clarification instead of guessing
|
|
478
|
-
- an approval, product, API, or scope choice is required before continuing safely
|
|
479
|
-
|
|
480
|
-
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`.
|
|
481
|
-
|
|
482
|
-
Use `contact_supervisor` with `reason: "progress_update"` when:
|
|
483
|
-
- a child is explicitly asked for progress
|
|
484
|
-
- a meaningful discovery changes the plan
|
|
485
|
-
- a long-running child needs to report a blocked/progress checkpoint without waiting for normal tool return flow
|
|
486
|
-
|
|
487
|
-
Message conventions:
|
|
488
|
-
- `reason: "need_decision"` waits for the parent reply and returns it to the child.
|
|
489
|
-
- `reason: "progress_update"` is non-blocking and should stay concise.
|
|
490
|
-
- Child-side routine completion handoffs are not expected. With the intercom bridge active, parent-side `pi-cohort` 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.
|
|
491
|
-
|
|
492
|
-
If bridge instructions provide the child-facing tool, a child can ask:
|
|
493
|
-
|
|
494
|
-
```typescript
|
|
495
|
-
contact_supervisor({
|
|
496
|
-
reason: "need_decision",
|
|
497
|
-
message: "Should I optimize for readability or performance here?"
|
|
498
|
-
})
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
The parent replies with:
|
|
502
|
-
|
|
503
|
-
```typescript
|
|
504
|
-
intercom({ action: "reply", message: "Optimize for readability." })
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
Or inspects unresolved asks first:
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
intercom({ action: "pending" })
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
If intercom messages do not show up, run `subagent({ action: "doctor" })` or `/cohort-doctor`.
|
|
514
|
-
|
|
515
465
|
## Management Mode
|
|
516
466
|
|
|
517
467
|
The `subagent(...)` tool also supports management actions.
|
|
@@ -622,8 +572,6 @@ particular agent or with forked context.
|
|
|
622
572
|
- **Default subagent nesting depth is 2.** Deeper recursive delegation is blocked
|
|
623
573
|
unless configured otherwise.
|
|
624
574
|
- **Attention signals are not lifecycle state.** `needs_attention` means no activity has been observed past the configured threshold. `paused` means the child turn was intentionally interrupted or is awaiting direction; it is not the same as `failed`.
|
|
625
|
-
- **Intercom asks are blocking.** A session can only maintain one pending outbound
|
|
626
|
-
ask wait state at a time.
|
|
627
575
|
- **Keep conversational authority clear.** Advisory subagents should not silently
|
|
628
576
|
become second decision-makers.
|
|
629
577
|
|
|
@@ -650,19 +598,14 @@ user explicitly requests forked context.
|
|
|
650
598
|
Give subagents specific tasks rather than vague mandates.
|
|
651
599
|
`Review auth.ts for null-check gaps` works better than `Review everything`.
|
|
652
600
|
|
|
653
|
-
###
|
|
601
|
+
### Stop on unapproved decisions
|
|
654
602
|
|
|
655
|
-
If a subagent encounters an unapproved product, architecture, or scope choice,
|
|
656
|
-
it should coordinate back via `intercom` instead of deciding alone.
|
|
603
|
+
If a subagent encounters an unapproved product, architecture, or scope choice, it must stop with `BLOCKED: <decision needed>` as the first line, followed by `Done: <complete>` and `Remaining: <left>`. The parent receives an ordinary failed result, sequential chains stop at that step, and follow-up is a fresh dispatch after the parent or human decides.
|
|
657
604
|
|
|
658
605
|
### Intervene only on clear control signals
|
|
659
606
|
|
|
660
607
|
Use subagent control proactively when a delegated run emits `needs_attention`, or when a human asks you to regain control. Do not interrupt just because a child has briefly produced no output. Silence can be normal during long tool calls, test runs, or model reasoning.
|
|
661
608
|
|
|
662
|
-
### Name sessions meaningfully
|
|
663
|
-
|
|
664
|
-
Use `/name` so intercom targeting stays stable.
|
|
665
|
-
|
|
666
609
|
## Common Workflows
|
|
667
610
|
|
|
668
611
|
### Recon → Plan → Implement
|
|
@@ -796,10 +739,10 @@ subagent({ action: "list" })
|
|
|
796
739
|
// Check available agents and chains, then confirm scope/precedence.
|
|
797
740
|
```
|
|
798
741
|
|
|
799
|
-
**Setup
|
|
742
|
+
**Setup or discovery confusion**
|
|
800
743
|
```typescript
|
|
801
744
|
subagent({ action: "doctor" })
|
|
802
|
-
// Check runtime paths, async support, discovery counts, current session
|
|
745
|
+
// Check runtime paths, async support, discovery counts, and current session.
|
|
803
746
|
```
|
|
804
747
|
|
|
805
748
|
**"Max subagent depth exceeded"**
|
|
@@ -812,11 +755,6 @@ subagent({ action: "doctor" })
|
|
|
812
755
|
// Persist the current session before using context: "fork".
|
|
813
756
|
```
|
|
814
757
|
|
|
815
|
-
**Intercom "Already waiting for a reply"**
|
|
816
|
-
```typescript
|
|
817
|
-
// Resolve the current outbound ask before starting another one.
|
|
818
|
-
```
|
|
819
|
-
|
|
820
758
|
**Parallel output-path conflict**
|
|
821
759
|
```typescript
|
|
822
760
|
// Give each parallel task a distinct output path, or disable output for tasks that do not need it.
|
|
@@ -65,4 +65,4 @@ Per-call attention-tracking overrides: `subagent({ ..., control: {...} })`. Run-
|
|
|
65
65
|
| `activeNoticeAfterTokens` | integer >= 1 | Notice by total tokens. | off |
|
|
66
66
|
| `failedToolAttemptsBeforeAttention` | integer >= 1 | Mutating-tool failures before `needs_attention`. | `3` |
|
|
67
67
|
| `notifyOn` | array of `"active_long_running"` \| `"needs_attention"` | Which events notify the parent. | both |
|
|
68
|
-
| `notifyChannels` | array of `"event"` \| `"async"`
|
|
68
|
+
| `notifyChannels` | array of `"event"` \| `"async"` | Delivery channels. | both |
|
|
@@ -8,21 +8,15 @@ export interface SubagentControlMessageDetails {
|
|
|
8
8
|
event: ControlEvent;
|
|
9
9
|
source?: "foreground" | "async";
|
|
10
10
|
asyncDir?: string;
|
|
11
|
-
childIntercomTarget?: string;
|
|
12
11
|
noticeText?: string;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
export function controlNoticeTarget(details: SubagentControlMessageDetails): string | undefined {
|
|
16
|
-
return details.childIntercomTarget;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
14
|
export function formatSubagentControlNotice(details: SubagentControlMessageDetails, content?: string): string {
|
|
20
|
-
return details.noticeText ?? content ?? formatControlNoticeMessage(details.event
|
|
15
|
+
return details.noticeText ?? content ?? formatControlNoticeMessage(details.event);
|
|
21
16
|
}
|
|
22
17
|
|
|
23
18
|
function noticeTimerKey(details: SubagentControlMessageDetails): string {
|
|
24
|
-
|
|
25
|
-
return `${details.event.runId}:${controlNotificationKey(details.event, childIntercomTarget)}`;
|
|
19
|
+
return `${details.event.runId}:${controlNotificationKey(details.event)}`;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
export function clearPendingForegroundControlNotices(state: SubagentState, runId?: string): void {
|
|
@@ -41,17 +35,16 @@ function deliverControlNotice(input: {
|
|
|
41
35
|
details: SubagentControlMessageDetails;
|
|
42
36
|
isIdle: () => boolean;
|
|
43
37
|
}): void {
|
|
44
|
-
const
|
|
45
|
-
const key = controlNotificationKey(input.details.event, childIntercomTarget);
|
|
38
|
+
const key = controlNotificationKey(input.details.event);
|
|
46
39
|
if (input.visibleControlNotices.has(key)) return;
|
|
47
40
|
input.visibleControlNotices.add(key);
|
|
48
|
-
const noticeText = input.details.noticeText ?? formatControlNoticeMessage(input.details.event
|
|
41
|
+
const noticeText = input.details.noticeText ?? formatControlNoticeMessage(input.details.event);
|
|
49
42
|
input.pi.sendMessage(
|
|
50
43
|
{
|
|
51
44
|
customType: SUBAGENT_CONTROL_MESSAGE_TYPE,
|
|
52
45
|
content: noticeText,
|
|
53
46
|
display: true,
|
|
54
|
-
details: { ...input.details,
|
|
47
|
+
details: { ...input.details, noticeText },
|
|
55
48
|
},
|
|
56
49
|
{ triggerTurn: input.details.source !== "foreground" || !input.isIdle() },
|
|
57
50
|
);
|
package/src/extension/doctor.ts
CHANGED
|
@@ -2,7 +2,6 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { discoverAgentsAll, type AgentSource } from "../agents/agents.ts";
|
|
4
4
|
import { isAsyncAvailable } from "../runs/background/async-execution.ts";
|
|
5
|
-
import { diagnoseIntercomBridge, type IntercomBridgeDiagnostic } from "../intercom/intercom-bridge.ts";
|
|
6
5
|
import { discoverAvailableSkills, type SkillSource } from "../agents/skills.ts";
|
|
7
6
|
import {
|
|
8
7
|
ASYNC_DIR,
|
|
@@ -24,18 +23,15 @@ interface DoctorDeps {
|
|
|
24
23
|
isAsyncAvailable: () => boolean;
|
|
25
24
|
discoverAgentsAll: typeof discoverAgentsAll;
|
|
26
25
|
discoverAvailableSkills: typeof discoverAvailableSkills;
|
|
27
|
-
diagnoseIntercomBridge: typeof diagnoseIntercomBridge;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
interface DoctorReportInput {
|
|
31
29
|
cwd: string;
|
|
32
30
|
config: ExtensionConfig;
|
|
33
31
|
state: SubagentState;
|
|
34
|
-
context?: "fresh" | "fork";
|
|
35
32
|
requestedSessionDir?: string;
|
|
36
33
|
currentSessionFile?: string | null;
|
|
37
34
|
currentSessionId?: string | null;
|
|
38
|
-
orchestratorTarget?: string;
|
|
39
35
|
sessionError?: string;
|
|
40
36
|
expandTilde?: (value: string) => string;
|
|
41
37
|
paths?: DoctorPaths;
|
|
@@ -53,7 +49,6 @@ const DEFAULT_DEPS: DoctorDeps = {
|
|
|
53
49
|
isAsyncAvailable,
|
|
54
50
|
discoverAgentsAll,
|
|
55
51
|
discoverAvailableSkills,
|
|
56
|
-
diagnoseIntercomBridge,
|
|
57
52
|
};
|
|
58
53
|
|
|
59
54
|
function errorText(error: unknown): string {
|
|
@@ -186,22 +181,6 @@ function formatCostLines(input: DoctorReportInput): string[] {
|
|
|
186
181
|
return lines;
|
|
187
182
|
}
|
|
188
183
|
|
|
189
|
-
function formatIntercomDiagnostic(diagnostic: IntercomBridgeDiagnostic, context: "fresh" | "fork" | undefined): string[] {
|
|
190
|
-
const lines = [
|
|
191
|
-
`- bridge: ${diagnostic.active ? "active" : "inactive"}${diagnostic.reason ? ` (${diagnostic.reason})` : ""}`,
|
|
192
|
-
`- mode: ${diagnostic.mode}; context: ${context ?? "unspecified"}`,
|
|
193
|
-
`- orchestrator target: ${diagnostic.orchestratorTarget ?? "not available"}`,
|
|
194
|
-
`- pi-intercom: ${diagnostic.piIntercomAvailable ? "available" : "unavailable"} at ${diagnostic.extensionDir}`,
|
|
195
|
-
];
|
|
196
|
-
if (diagnostic.configPath && diagnostic.intercomConfigEnabled !== undefined) {
|
|
197
|
-
lines.push(`- intercom config: ${diagnostic.intercomConfigEnabled === false ? "disabled" : "enabled or absent"} (${diagnostic.configPath})`);
|
|
198
|
-
}
|
|
199
|
-
if (diagnostic.intercomConfigError) {
|
|
200
|
-
lines.push(`- intercom config warning: ${diagnostic.intercomConfigError}; runtime assumes enabled`);
|
|
201
|
-
}
|
|
202
|
-
return lines;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
184
|
export function buildDoctorReport(input: DoctorReportInput): string {
|
|
206
185
|
const paths = input.paths ?? DEFAULT_PATHS;
|
|
207
186
|
const deps = { ...DEFAULT_DEPS, ...input.deps };
|
|
@@ -222,14 +201,6 @@ export function buildDoctorReport(input: DoctorReportInput): string {
|
|
|
222
201
|
"Discovery",
|
|
223
202
|
...formatDiscovery(input, deps),
|
|
224
203
|
"",
|
|
225
|
-
"Intercom bridge",
|
|
226
|
-
...lineFromCheck("intercom bridge", () => formatIntercomDiagnostic(deps.diagnoseIntercomBridge({
|
|
227
|
-
config: input.config.intercomBridge,
|
|
228
|
-
context: input.context,
|
|
229
|
-
orchestratorTarget: input.orchestratorTarget,
|
|
230
|
-
cwd: input.cwd,
|
|
231
|
-
}), input.context).join("\n")).split("\n"),
|
|
232
|
-
"",
|
|
233
204
|
...formatCostLines(input),
|
|
234
205
|
];
|
|
235
206
|
return lines.join("\n");
|
|
@@ -7,8 +7,6 @@ import { getArtifactsDir } from "../shared/artifacts.ts";
|
|
|
7
7
|
import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
8
8
|
import { SUBAGENT_CHILD_ENV, SUBAGENT_FANOUT_CHILD_ENV } from "../runs/shared/pi-args.ts";
|
|
9
9
|
import { readNestedControlRequests, resolveNestedRouteFromEnv, writeNestedControlResult } from "../runs/shared/nested-events.ts";
|
|
10
|
-
import { deliverSubagentIntercomMessageEvent } from "../intercom/result-intercom.ts";
|
|
11
|
-
import { resolveSubagentIntercomTarget } from "../intercom/intercom-bridge.ts";
|
|
12
10
|
import { SubagentParams } from "./schemas.ts";
|
|
13
11
|
import { loadConfig } from "./config.ts";
|
|
14
12
|
import { deriveForwardedFlags } from "../runs/shared/forward-flags.ts";
|
|
@@ -84,21 +82,8 @@ function startNestedControlInboxListener(pi: ExtensionAPI, state: SubagentState)
|
|
|
84
82
|
: `Nested run ${request.targetRunId} has no active child step to interrupt.`;
|
|
85
83
|
} else if (!request.message?.trim()) {
|
|
86
84
|
message = "Nested resume requires message.";
|
|
87
|
-
} else if (!control.currentAgent) {
|
|
88
|
-
message = `Nested run ${request.targetRunId} has no active child message route.`;
|
|
89
85
|
} else {
|
|
90
|
-
|
|
91
|
-
const target = resolveSubagentIntercomTarget(request.targetRunId, control.currentAgent, index);
|
|
92
|
-
ok = await deliverSubagentIntercomMessageEvent(
|
|
93
|
-
pi.events,
|
|
94
|
-
target,
|
|
95
|
-
`Follow-up for nested run ${request.targetRunId} (${control.currentAgent}):\n\n${request.message.trim()}`,
|
|
96
|
-
500,
|
|
97
|
-
{ source: "nested-resume", runId: request.targetRunId, agent: control.currentAgent, index },
|
|
98
|
-
);
|
|
99
|
-
message = ok
|
|
100
|
-
? `Delivered follow-up to live nested run ${request.targetRunId}.`
|
|
101
|
-
: `Nested child intercom target is not registered: ${target}`;
|
|
86
|
+
message = `Nested run ${request.targetRunId} is still active; wait for completion, then resume.`;
|
|
102
87
|
}
|
|
103
88
|
} catch (error) {
|
|
104
89
|
message = error instanceof Error ? error.message : String(error);
|
package/src/extension/index.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Toggle: async parameter (default: false, configurable via config.json)
|
|
10
10
|
*
|
|
11
11
|
* Config file: ~/.pi/agent/extensions/pi-cohort/config.json
|
|
12
|
-
* { "asyncByDefault": true, "forceTopLevelAsync": true, "maxSubagentDepth": 1, "showRosterOnStart": true, "
|
|
12
|
+
* { "asyncByDefault": true, "forceTopLevelAsync": true, "maxSubagentDepth": 1, "showRosterOnStart": true, "worktreeSetupHook": "./scripts/setup-worktree.mjs" }
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import * as fs from "node:fs";
|
|
@@ -442,7 +442,7 @@ MANAGEMENT: action=list/get/create/update/delete (chainName for chains; packaged
|
|
|
442
442
|
CONTROL: action=status/interrupt/resume (id, message, index); details: pi-cohort skill.
|
|
443
443
|
|
|
444
444
|
DIAGNOSTICS:
|
|
445
|
-
• { action: "doctor" } - read-only report for runtime paths, discovery,
|
|
445
|
+
• { action: "doctor" } - read-only report for runtime paths, discovery, and sessions`,
|
|
446
446
|
parameters: SubagentParams,
|
|
447
447
|
|
|
448
448
|
execute(id, params, signal, onUpdate, ctx) {
|