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.
Files changed (38) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/README.md +0 -1
  3. package/agents/context-builder.md +4 -4
  4. package/agents/delegate.md +2 -2
  5. package/agents/monitor.md +3 -4
  6. package/agents/oracle.md +3 -7
  7. package/agents/planner.md +3 -3
  8. package/agents/reviewer.md +3 -5
  9. package/agents/scout.md +3 -3
  10. package/agents/worker.md +3 -6
  11. package/package.json +1 -1
  12. package/skills/pi-cohort/SKILL.md +19 -81
  13. package/skills/pi-cohort/reference/config-fields.md +1 -1
  14. package/src/extension/control-notices.ts +5 -12
  15. package/src/extension/doctor.ts +0 -29
  16. package/src/extension/fanout-child.ts +1 -16
  17. package/src/extension/index.ts +2 -2
  18. package/src/runs/background/async-execution.ts +2 -31
  19. package/src/runs/background/async-job-tracker.ts +2 -11
  20. package/src/runs/background/async-resume.ts +7 -38
  21. package/src/runs/background/result-watcher.ts +5 -33
  22. package/src/runs/background/run-status.ts +0 -4
  23. package/src/runs/background/subagent-runner.ts +15 -45
  24. package/src/runs/foreground/chain-execution.ts +1 -54
  25. package/src/runs/foreground/execution.ts +18 -60
  26. package/src/runs/foreground/subagent-executor.ts +18 -274
  27. package/src/runs/shared/completion-guard.ts +5 -2
  28. package/src/runs/shared/nested-events.ts +0 -3
  29. package/src/runs/shared/pi-args.ts +0 -9
  30. package/src/runs/shared/result-children.ts +89 -0
  31. package/src/runs/shared/subagent-control.ts +8 -37
  32. package/src/runs/shared/subagent-prompt-runtime.ts +0 -6
  33. package/src/runs/shared/workflow-graph.ts +2 -6
  34. package/src/shared/types.ts +7 -49
  35. package/src/shared/utils.ts +2 -4
  36. package/src/tui/render.ts +8 -12
  37. package/src/intercom/intercom-bridge.ts +0 -379
  38. package/src/intercom/result-intercom.ts +0 -377
package/CHANGELOG.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
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, intercom
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/escalation rules: when to ask via `intercom`, when enough evidence is enough, and when to 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
- ## Supervisor coordination
45
- If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the plan. Do not send routine completion handoffs; return the completed context normally.
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.
@@ -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, contact_supervisor
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 runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and stay alive for the reply. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the plan. Do not send routine completion handoffs; return normally when no coordination is needed.
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. If contact_supervisor is available, send the delta with reason "progress_update".
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. Report it as "no output for <interval>, possible stall". After two consecutive silent cycles, escalate with contact_supervisor reason "need_decision". Never report "still working" without evidence.
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. Without contact_supervisor, the trail and final summary are the record; behave identically otherwise.
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, intercom
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 you need clarification from the main agent and runtime bridge instructions are present, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for concise updates when blocked, explicitly asked for progress, or when a recommendation or concern would benefit from immediate discussion. Keep coordination traffic tight and purposeful. Do not narrate your whole review through `contact_supervisor`.
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 and it matters, ask the main agent with `contact_supervisor` and `reason: "need_decision"` instead of guessing.
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, intercom
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
- ## Supervisor coordination
55
- If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the plan. Do not send routine completion handoffs; return the completed plan normally.
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.
@@ -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, intercom
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
- ## Supervisor coordination
76
- If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing; no-edit wins. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the review plan. Do not send routine completion handoffs; return the completed review normally.
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, intercom
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
- ## Supervisor coordination
50
- If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the plan. Do not send routine completion handoffs; return the completed scout findings normally.
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, contact_supervisor
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 the implementation reveals a decision that was not approved and is required to continue safely, pause and escalate through the live coordination channel. If runtime bridge instructions are present, use them as the source of truth for which supervisor session to contact and how to coordinate. Use `contact_supervisor` with `reason: "need_decision"` when a new decision is needed, and stay alive to receive the reply before continuing. Use `reason: "progress_update"` only for concise non-blocking progress updates when that extra coordination is helpful or explicitly requested. Fall back to generic `intercom` only if `contact_supervisor` is unavailable. Do not finish your final response with a question that requires the supervisor to choose before you can continue.
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 implementation reveals a gap in the approved direction, pause and escalate with `contact_supervisor` and `reason: "need_decision"` instead of silently patching around it with an implicit decision.
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": "5.3.4",
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, and intercom-coordinated workflows. Use
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, and intercom bridge state
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 with decision escalation |
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, intercom coordination |
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, or escalation for unapproved decisions.
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 ask via `intercom`, when to stop after enough evidence, and when not to keep searching.
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 when to escalate. They should not ask the child to create another subagent plan or continue the parent conversation.
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
- - If an async child is still running and reachable, `resume` sends the follow-up to that live child over intercom.
339
- - If an async child has completed, `resume` revives it by starting a new async child from the persisted child session file.
340
- - Multi-child async runs require `index` unless only one running child is selectable.
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 a live route or persisted nested session metadata is available.
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, and intercom bridge state.
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 `nudge`, `status`, and `interrupt` options. Visible notifications fire once per child run and attention state.
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. `oracle` can coordinate back through `contact_supervisor` when the bridge injects it
446
- 4. the main agent decides what direction to approve
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
- ### Escalate decisions upward
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, discovery, or intercom confusion**
742
+ **Setup or discovery confusion**
800
743
  ```typescript
801
744
  subagent({ action: "doctor" })
802
- // Check runtime paths, async support, discovery counts, current session, and intercom bridge state.
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"` \| `"intercom"` | Delivery channels. | all three |
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, controlNoticeTarget(details));
15
+ return details.noticeText ?? content ?? formatControlNoticeMessage(details.event);
21
16
  }
22
17
 
23
18
  function noticeTimerKey(details: SubagentControlMessageDetails): string {
24
- const childIntercomTarget = controlNoticeTarget(details);
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 childIntercomTarget = controlNoticeTarget(input.details);
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, childIntercomTarget);
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, childIntercomTarget, noticeText },
47
+ details: { ...input.details, noticeText },
55
48
  },
56
49
  { triggerTurn: input.details.source !== "foreground" || !input.isIdle() },
57
50
  );
@@ -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
- const index = control.currentIndex ?? 0;
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);
@@ -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, "intercomBridge": { "mode": "always", "instructionFile": "./intercom-bridge.md" }, "worktreeSetupHook": "./scripts/setup-worktree.mjs" }
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, sessions, and intercom`,
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) {