@selesai/code 0.5.29 → 0.6.2

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 (94) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -1
  3. package/dist/config.d.ts +16 -3
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +106 -5
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/system-prompt.d.ts.map +1 -1
  8. package/dist/core/system-prompt.js +18 -0
  9. package/dist/core/system-prompt.js.map +1 -1
  10. package/dist/core/system-prompt.test.d.ts +2 -0
  11. package/dist/core/system-prompt.test.d.ts.map +1 -0
  12. package/dist/core/system-prompt.test.js +89 -0
  13. package/dist/core/system-prompt.test.js.map +1 -0
  14. package/dist/defaults/models.json +13 -45
  15. package/dist/defaults/settings.json +5 -7
  16. package/dist/extensions/copy-turn.test.ts +131 -0
  17. package/dist/extensions/copy-turn.ts +6 -1
  18. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  19. package/dist/extensions/package.json +0 -1
  20. package/dist/extensions/pi-subagents/CHANGELOG.md +3 -0
  21. package/dist/extensions/pi-subagents/README.md +27 -32
  22. package/dist/extensions/pi-subagents/agents/architect.md +4 -4
  23. package/dist/extensions/pi-subagents/agents/builder.md +5 -4
  24. package/dist/extensions/pi-subagents/agents/commentator.md +3 -2
  25. package/dist/extensions/pi-subagents/agents/explorer.md +3 -2
  26. package/dist/extensions/pi-subagents/agents/recapper.md +3 -2
  27. package/dist/extensions/pi-subagents/agents/researcher.md +4 -3
  28. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -0
  29. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +10 -9
  30. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +12 -11
  31. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +10 -11
  32. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +56 -9
  33. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +125 -0
  34. package/dist/extensions/pi-subagents/src/api/preflight.ts +1 -1
  35. package/dist/extensions/pi-subagents/src/extension/index.ts +5 -1
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +2 -2
  37. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +24 -7
  38. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +23 -5
  39. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +27 -1
  40. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +64 -6
  41. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +16 -1
  42. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +72 -18
  43. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +19 -5
  44. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +127 -31
  45. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +4 -6
  46. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +63 -9
  47. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +21 -0
  48. package/dist/extensions/pi-subagents/src/shared/types.ts +41 -2
  49. package/dist/extensions/pi-subagents/src/shared/utils.ts +29 -1
  50. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -1
  51. package/dist/extensions/pi-subagents/src/tui/render.ts +32 -6
  52. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +111 -6
  53. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +74 -43
  54. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +36 -21
  55. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +5 -3
  56. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -8
  57. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +14 -7
  58. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +227 -0
  59. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +81 -5
  60. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +49 -10
  61. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +18 -2
  62. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  63. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -6
  64. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +161 -1
  65. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +63 -0
  66. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +34 -0
  67. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +24 -0
  68. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +6 -1
  69. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +29 -0
  70. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +2 -0
  71. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +12 -0
  72. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +91 -1
  73. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +213 -0
  74. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +23 -1
  75. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +60 -9
  76. package/dist/extensions/pi-web-agent/package.json +1 -1
  77. package/dist/skills/pi-subagents/SKILL.md +43 -0
  78. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +257 -0
  79. package/dist/skills/pi-subagents/references/execution-controls.md +431 -0
  80. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  81. package/dist/skills/pi-subagents/references/prompting-and-roles.md +281 -0
  82. package/dist/skills/ponytail/SKILL.md +1 -3
  83. package/docs/plans/subagent-delegation/phase-0-correctness.md +265 -0
  84. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +486 -0
  85. package/docs/plans/subagent-delegation/phase-2-context-controls.md +282 -0
  86. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +362 -0
  87. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +381 -0
  88. package/package.json +2 -2
  89. package/dist/extensions/caveman/caveman-instructions.cjs +0 -11
  90. package/dist/extensions/caveman/index.js +0 -118
  91. package/dist/extensions/caveman/package.json +0 -8
  92. package/dist/extensions/caveman/test/extension.test.js +0 -203
  93. package/dist/extensions/caveman/test/helpers.test.js +0 -58
  94. package/dist/skills/caveman/SKILL.md +0 -50
@@ -1,12 +1,13 @@
1
1
  ---
2
2
  name: recapper
3
- description: Summarizes the current conversation and prepares a handoff document
3
+ description: Read-only handoff and context synthesis
4
4
  tools: read, grep, find, ls
5
5
  systemPromptMode: replace
6
6
  inheritProjectContext: true
7
7
  inheritSkills: false
8
- skill: ponytail, caveman
8
+ skill: ponytail
9
9
  defaultContext: fork
10
+ acceptanceRole: read-only
10
11
  ---
11
12
 
12
13
  Create a concise, self-contained handoff for a fresh agent. Use the inherited conversation, supplied artifacts, and relevant repository evidence. Do not edit project files, write output files, or launch subagents.
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  name: researcher
3
- description: Autonomous code-first researcher that produces a focused sourced brief
4
- tools: read, grep_app_search, grep_app_fetch, web_explore
3
+ description: Read-only external and code-first research
4
+ tools: read, mcp:grep_app_search, mcp:grep_app_fetch, web_explore
5
5
  thinking: medium
6
6
  systemPromptMode: replace
7
7
  inheritProjectContext: false
8
8
  inheritSkills: false
9
9
  defaultContext: fresh
10
- skill: ponytail, caveman
10
+ skill: ponytail
11
+ acceptanceRole: read-only
11
12
  ---
12
13
 
13
14
  You are a code-first research subagent. Answer the supplied question with a concise, well-sourced brief. Do not edit project files, write output files, or launch subagents.
@@ -27,6 +27,8 @@ Read the matching reference file before acting. Paths are relative to this `SKIL
27
27
 
28
28
  Selesai default: use Fable-style parent orchestration for complex work (multiple moving parts, unclear acceptance, cross-cutting code, meaningful user impact, expensive validation, or broad review surface). Lightweight one-off delegation stays lightweight.
29
29
 
30
+ Routing rule: keep tiny targeted reads and simple answers with the parent. For broad local investigation, external research, or mutation work, call `{ action: "list" }`, choose an executable entry from its runtime metadata, then delegate. Treat list output—not hardcoded role names—as the agent-selection authority.
31
+
30
32
  For broad or uncertain requests, read more than one reference. For complex work, start with `references/prompting-and-roles.md` and `references/execution-controls.md`, then consult `references/constraints-and-recipes.md` before launching or reviewing child work.
31
33
 
32
34
  ## Always-on constraints
@@ -5,9 +5,10 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
5
5
  ## Important Constraints
6
6
 
7
7
  - **Forking requires a persisted parent session.** If the current session does not
8
- have a persisted session file, forked runs fail. Packaged `architect`, `builder`,
9
- `commentator`, and `commentator` default to forked context, so use `context: "fresh"` explicitly
10
- when that is not available or not wanted.
8
+ have a persisted session file, forked runs fail. Packaged `architect` and `recapper`
9
+ default to forked context; `builder`, `commentator`, `explorer`, and `researcher`
10
+ default to fresh context. Use explicit `context: "fork"` or `context: "fresh"` when
11
+ you intentionally want one context for every child.
11
12
  - **Forked runs inherit parent history.** They are branched threads, not fresh
12
13
  filtered contexts. Use fresh context for adversarial commentators unless the user explicitly asks for forked context.
13
14
  - **Default subagent nesting depth is 2.** Deeper recursive delegation is blocked
@@ -18,7 +19,7 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
18
19
  - **Keep conversational authority clear.** Advisory subagents should not silently
19
20
  become second decision-makers.
20
21
 
21
- Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `subagent_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. `artifactDir` is `project` (default), `session`, or `temp` and chooses where subagent artifacts are stored. Set `asyncWidget: false` to hide the above-editor background-run widget when a companion footer or dashboard owns that space (fleet inspector remains available). Per-run `artifacts: false` disables artifact capture for that launch. Async status and result artifacts are versioned with fields such as `lifecycleArtifactVersion`, `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`. Child protocol failures expose a structured `protocolError`; `protocol_output_limit` means a child emitted a JSONL line above the 4 MiB live-parser cap. Prefer these artifacts and `status` views over scraping terminal output.
22
+ Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `subagent_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. `artifactDir` is `project` (default), `session`, or `temp` and chooses where subagent artifacts are stored. Set `asyncWidget: false` to hide the above-editor background-run widget when a companion footer or dashboard owns that space (fleet inspector remains available). Artifact capture is off by default; set per-run `artifacts: true` when debug files are needed. Async status and result artifacts are versioned with fields such as `lifecycleArtifactVersion`, `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`. Child protocol failures expose a structured `protocolError`; `protocol_output_limit` means a child emitted a JSONL line above the 4 MiB live-parser cap. Prefer these artifacts and `status` views over scraping terminal output.
22
23
 
23
24
  ## Best Practices
24
25
 
@@ -91,7 +92,7 @@ Fable mode is the default orchestration posture for complex work. It is not a se
91
92
 
92
93
  Run the work through seven gated phases:
93
94
 
94
- 1. **Understand** — use `explorer` or `explorer` fanout for breadth, but the parent personally reads the load-bearing files and lets direct source reading decide disagreements. Gate: the parent can quote the exact code or behavior being changed and knows the repo's verification harness.
95
+ 1. **Understand** — use `explorer` fanout for breadth, but the parent personally reads the load-bearing files and lets direct source reading decide disagreements. Gate: the parent can quote the exact code or behavior being changed and knows the repo's verification harness.
95
96
  2. **Decide** — separate user-owned decisions from implementation judgments. Use `interview` for product, naming, cost, taste, or risk decisions; decide routine engineering details in the parent and state them. Gate: every user-owned decision needed for design is answered.
96
97
  3. **Design** — use `architect`, `explorer`, or read-only design/review children for parallel perspectives. Before parallel workstreams, write seam contracts: ownership boundaries, composition points, assumptions, and validation handoffs. Gate: one parent-synthesized plan and written seams for parallel work.
97
98
  4. **Implement** — capture a baseline first, then launch one async `builder` as the sole writer for the active worktree unless isolated worktrees were intentionally requested. Break large work into serial milestones instead of concurrent writes. Gate: build/typecheck is green and every output or diff delta is characterized as intended or fixed.
@@ -103,7 +104,7 @@ Run the work through seven gated phases:
103
104
 
104
105
  For straightforward non-trivial work, this sequence is the lightweight version of the parent-owned loop. When the task is complex, use Fable mode above. In either case, factor in the packaged prompt workflows without literally invoking slash commands. Use the same patterns through tools and subagents.
105
106
 
106
- Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior. In particular, packaged `architect`, `builder`, `commentator`, and `commentator` default to forked context.
107
+ Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior. In particular, packaged `architect` and `recapper` default to forked context; `builder`, `commentator`, `explorer`, and `researcher` default to fresh context.
107
108
 
108
109
  When the user approves launching a subagent to carry out a plan or workflow, treat that as approval to generate a proper role-specific meta prompt for that subagent. Include the approved plan path or summary, clarified requirements, non-goals, relevant context, role boundaries, files or areas to inspect, acceptance criteria, expected output, and validation expectations. Do not pass vague instructions like “implement the plan fully” or “review this” by themselves.
109
110
 
@@ -125,7 +126,7 @@ The validation contract defines acceptance before code is written: expected beha
125
126
 
126
127
  Use the structured `acceptance` field when the run should carry an explicit acceptance contract. If omitted, subagents infer an effective policy from role, mode, and risk. Evidence levels end at `verified`: use `level: "checked"` for ordinary writer evidence and `level: "verified"` when the runtime should run explicit validation commands. Independent review is orthogonal; use `review: { required: true, agent: "commentator" }` and orchestrate the commentator separately. `review-required` means evidence passed but review is pending, while `reviewed` means a real independent result found no blockers. For commentator/read-only calls, omit `acceptance`. Never explicitly request `level: "reviewed"`; that value remains recognized only so preflight can return an actionable correction. To disable gates, use `{ level: "none", reason: "..." }`; the bare string `"none"` is rejected, and `false` is accepted only as a deprecated shorthand. Child-reported command success is evidence, not runtime verification.
127
128
 
128
- The first `builder` implements the approved plan. The parent continues with independent inspection or validation prep while it runs, not parallel edits to the same worktree. When the async builder completes, treat its handoff as the transition into review, not as final completion, unless the user explicitly asked for builder-only work, review-only output, or to stop after implementation. Parallel commentators inspect the resulting diff from fresh context. Validators check behavior with the best available evidence: commands, tests, browser/CLI interaction, screenshots, logs, or manual reproduction notes. The final `builder` applies synthesized review fixes in forked context, then the parent looks over the final diff before completing. The parent may launch these steps as an initial async chain when the workflow is already clear, or as follow-up subagent runs after each async completion. Initial chains should pass `async: true` so the main chat is unblocked; avoid `clarify: true` unless the user asked for foreground clarification. Do not stop after parallel review unless the user explicitly asked for review-only output or the review surfaced a decision that needs approval first.
129
+ The first `builder` implements the approved plan. The parent continues with independent inspection or validation prep while it runs, not parallel edits to the same worktree. When the async builder completes, treat its handoff as the transition into review, not as final completion, unless the user explicitly asked for builder-only work, review-only output, or to stop after implementation. Parallel commentators inspect the resulting diff from fresh context. Validators check behavior with the best available evidence: commands, tests, browser/CLI interaction, screenshots, logs, or manual reproduction notes. The final `builder` applies synthesized review fixes with an explicit `context: "fork"` when the fix needs inherited parent context, then the parent looks over the final diff before completing. The parent may launch these steps as an initial async chain when the workflow is already clear, or as follow-up subagent runs after each async completion. Initial chains should pass `async: true` so the main chat is unblocked; avoid `clarify: true` unless the user asked for foreground clarification. Do not stop after parallel review unless the user explicitly asked for review-only output or the review surfaced a decision that needs approval first.
129
130
 
130
131
  For complex work, risky changes, broad refactors, or many changed lines, increase review and validation fanout rather than trusting one commentator. Use distinct angles such as correctness/regressions, tests/validation, simplicity/maintainability, security/privacy, performance, docs/API contracts, and user-flow behavior. When commentators find non-trivial issues or the fix builder touches many lines, run another focused review round before final validation.
131
132
 
@@ -135,10 +136,10 @@ For very large work, split into serial milestones instead of launching a swarm o
135
136
 
136
137
  Keep orchestration authority in the parent session. Child subagents should not launch more subagents, read this skill, or run their own orchestration loops unless the parent intentionally selected a fanout agent whose builtin `tools` includes `subagent`. Spawned subagents do not receive the `pi-subagents` skill, parent-only status/control/slash messages, or prior parent `subagent` tool-call/tool-result artifacts. Ordinary children also do not receive the `subagent` extension tool. Child context filtering strips old hidden orchestration-instruction messages when they appear in inherited history. Every child receives a boundary instruction: ordinary children are told the parent owns orchestration and they must not propose or run subagents; explicit fanout children are told to use `subagent` only for the assigned fanout work, with `maxSubagentDepth` still enforced. Implementation children must call real edit/write tools instead of printing pseudo tool calls. Pass children concrete role-specific work instead.
137
138
 
138
- 1. Clarify first. This is mandatory. Gather code context with `explorer` or `explorer`, add `researcher` only when external evidence matters, then ask the user clarifying questions with `interview` until scope, acceptance criteria, constraints, and non-goals are clear.
139
+ 1. Clarify first. This is mandatory. Gather code context with `explorer`, add `researcher` only when external evidence matters, then ask the user clarifying questions with `interview` until scope, acceptance criteria, constraints, and non-goals are clear.
139
140
  2. Define the validation contract. State acceptance before implementation: expected behavior, checks to run, user flows to exercise, and evidence required in the builder handoff. For UI, CLI, integration, or workflow changes, include at least one validator angle that uses the product the way a user would rather than only reading code.
140
141
  3. Plan when useful. For complex work, call `architect` or write a plan doc yourself and get approval before implementation. For simple work, confirm shared understanding and explicitly note why planning is skipped.
141
- 4. Implement with one writer. After approval, launch `builder` asynchronously with a proper meta prompt that includes clarified requirements, relevant context, plan path or summary, the validation contract, and output expectations. Packaged `builder` defaults to forked context; pass `context: "fresh"` only when you intentionally want a fresh child. While it runs, prepare validation or inspect adjacent code instead of editing the same worktree.
142
+ 4. Implement with one writer. After approval, launch `builder` asynchronously with a proper meta prompt that includes clarified requirements, relevant context, plan path or summary, the validation contract, and output expectations. Packaged `builder` defaults to fresh context; pass `context: "fork"` only when inherited parent context is intentionally required. While it runs, prepare validation or inspect adjacent code instead of editing the same worktree.
142
143
  5. Require a useful builder handoff. Ask the builder to report changed files, what was implemented, what was left undone, commands run with exit codes, validation evidence, surprises or new risks, decisions made inside approved scope, and decisions needing parent approval.
143
144
  6. Review after implementation. After the builder completes, launch parallel async fresh-context `commentator` agents for correctness/regressions, tests/validation, and simplicity/maintainability. Add security, performance, docs/API, domain-specific, or user-flow validators for complex work, risky changes, broad refactors, or many changed lines. Use `output: false` unless review artifacts are explicitly needed.
144
145
  7. Synthesize, then run the fix builder. Separate blockers, fixes worth doing now, optional improvements, and feedback to ignore/defer, then launch an async forked `builder` to apply fixes worth doing now when the workflow is implementation-authorized. If commentators found scope/product/architecture choices that were not approved, ask the user first instead of applying them.
@@ -6,12 +6,12 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
6
6
 
7
7
  Agent files can live in:
8
8
  - `~/.selesai/agent/agents/**/*.md` — user scope
9
- - `.pi/agents/**/*.md` — canonical project scope
10
- - legacy `.agents/**/*.md` — still read for compatibility, but `.pi/agents/` wins on conflicts
9
+ - `.selesai/agents/**/*.md` — canonical project scope
10
+ - legacy `.agents/**/*.md` — still read for compatibility, but `.selesai/agents/` wins on conflicts
11
11
 
12
12
  Chains live in:
13
13
  - `~/.selesai/agent/chains/**/*.chain.md` and `~/.selesai/agent/chains/**/*.chain.json` — user scope
14
- - `.pi/chains/**/*.chain.md` and `.pi/chains/**/*.chain.json` — project scope
14
+ - `.selesai/chains/**/*.chain.md` and `.selesai/chains/**/*.chain.json` — project scope
15
15
 
16
16
  Discovery is recursive. `.chain.md` files do not define agents. Use `.chain.md` for simple saved chains and `.chain.json` for dynamic fanout or inline schema objects. Agents and chains can set optional frontmatter/package metadata; `name: explorer` plus `package: code-analysis` registers as runtime name `code-analysis.explorer` while serialization keeps `name` and `package` separate.
17
17
 
@@ -20,7 +20,7 @@ Precedence is by parsed runtime name:
20
20
  2. user scope
21
21
  3. builtin agents
22
22
 
23
- Project settings resolve from the nearest parent directory containing `.pi` or `.agents` by default. In monorepos or git worktrees where an incidental nested `.pi` directory should not shadow the repository config, set `subagents.projectRootResolution: "git-root"` in the repository root `.selesai/settings.json`; a nested project can opt back with `"nearest"` in its own settings.
23
+ Project settings resolve from the nearest parent directory containing a `.selesai` config dir or a legacy `.agents` agent dir by default. In monorepos or git worktrees where an incidental nested `.selesai` directory should not shadow the repository config, set `subagents.projectRootResolution: "git-root"` in the repository root `.selesai/settings.json`; a nested project can opt back with `"nearest"` in its own settings.
24
24
 
25
25
  ## Running Subagents
26
26
 
@@ -88,7 +88,7 @@ subagent({
88
88
  })
89
89
  ```
90
90
 
91
- Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. In chains, relative `output` paths are chain-artifact paths under `{chain_dir}`, not project CWD paths; use an absolute `output` path or a persistent `chainDir` when a saved artifact must outlive the temp chain directory. Read-only children return the complete artifact in their final response and the runtime persists it, so missing write tools are not a supervisor blocker. Mutation-capable children still receive direct-write instructions. Failed runs and save errors still return inline details for debugging.
91
+ Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. Delivery is reference-first by default: every child gets a durable saved output unless `output: false`, omitted `output` uses a generated per-run path, omitted `outputMode` resolves to `file-only`, and the parent result contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` Inspect full output through the saved path, async status/transcript, or resume. Explicit `outputMode: "inline"` keeps the legacy full inline delivery; `output: false` disables durable result persistence (follow-up visibility falls back to bounded excerpts). Failed runs with a persisted result return the error/status plus the saved-output reference; persistence or read-back failures return only a bounded excerpt (first 80 lines / 4 KiB) together with the error, never raw unbounded output. Do not use `output: false` to get a file-only return; use file-only mode with an output path. In chains, relative `output` paths are chain-artifact paths under `{chain_dir}`, not project CWD paths; use an absolute `output` path or a persistent `chainDir` when a saved artifact must outlive the temp chain directory. Read-only children return the complete artifact in their final response and the runtime persists it, so missing write tools are not a supervisor blocker. Mutation-capable children still receive direct-write instructions.
92
92
 
93
93
  ### Chain execution
94
94
 
@@ -137,7 +137,7 @@ subagent({
137
137
  })
138
138
  ```
139
139
 
140
- File-only output mode also works for async single runs, top-level parallel task items, sequential chain steps, and chain parallel task items. In chains, `{previous}` receives the compact saved-file reference when the prior step used file-only mode. Relative chain output paths are resolved under `{chain_dir}`; pass a persistent `chainDir` or an absolute `output` path when a later human or process needs a stable path outside the temp chain run.
140
+ File-only output mode also works for async single runs, top-level parallel task items, sequential chain steps, and chain parallel task items. In chains, `{previous}` receives the compact saved-file reference when the prior step used file-only mode. Relative chain output paths are resolved under `{chain_dir}`; pass a persistent `chainDir` or an absolute `output` path when a later human or process needs a stable path outside the temp chain run. Async completion delivery is reference-first: the completion notification and grouped intercom payload carry per-child saved-output references (or `output-<index>.log` references) plus process status, never full child output. Inspect full output through the saved path, `{ action: "status", id, view: "transcript" }`, or resume.
141
141
 
142
142
  For review fanout where the parent continues a local audit:
143
143
 
@@ -353,20 +353,20 @@ worktree, first confirm dependencies were linked, installed, or provisioned by
353
353
  ## The commentator Workflow
354
354
 
355
355
  The intended commentator loop is:
356
- 1. the main agent forks to `commentator`
356
+ 1. the main agent launches `commentator` (fresh context by default; pass `context: "fork"` only when a branched advisory thread that inherits the parent session history is intended)
357
357
  2. `commentator` reviews direction, drift, assumptions, and risks
358
358
  3. `commentator` can coordinate back through `contact_supervisor` when the bridge injects it
359
359
  4. the main agent decides what direction to approve
360
360
  5. only then should `builder` implement
361
361
 
362
362
  ```typescript
363
- // Advisory review in a branched thread. commentator defaults to forked context.
363
+ // Advisory review. commentator defaults to fresh context; fork explicitly when a branched advisory thread is intended.
364
364
  subagent({
365
365
  agent: "commentator",
366
366
  task: "Review my current direction, challenge assumptions, and propose the best next move."
367
367
  })
368
368
 
369
- // Implementation only after explicit approval. builder defaults to forked context.
369
+ // Implementation only after explicit approval. builder defaults to fresh context; pass context: "fork" when inherited parent context is intentionally required.
370
370
  subagent({
371
371
  agent: "builder",
372
372
  task: "Implement the approved approach: ..."
@@ -374,8 +374,9 @@ subagent({
374
374
  ```
375
375
 
376
376
  `commentator` is not a fresh-context commentator in the Cognition article sense. It is
377
- a forked advisory thread that inherits the parent session history and uses that
378
- history as a baseline contract.
377
+ an advisory thread that reviews direction, drift, and risks against the task/plan.
378
+ Pass `context: "fork"` when the review should inherit the parent session history and
379
+ use that history as a baseline contract; otherwise fresh context is the default.
379
380
 
380
381
  Use `commentator` as a smart-friend escalation when the parent needs help with trajectory rather than diff inspection: architectural boundaries, model capability routing, merge conflicts, commentator disagreement, context drift after long work, a builder about to invent a pattern, or fixes that require product/scope tradeoffs. Ask broad questions when the right concern is unclear, and let `commentator` point out missing context or files the parent should inspect before asking again. Keep `commentator` advisory unless it has been explicitly assigned the single writer role.
381
382
 
@@ -11,7 +11,7 @@ Parent extensions may register a session-scoped, out-of-band ceiling through `pi
11
11
  - **Complex work orchestration**: use Fable mode as the default parent-agent loop for complex work. Complex means the task has multiple moving parts, unclear acceptance, cross-cutting code, meaningful user-visible impact, expensive or irreversible validation, broad review surface, or the user asks for orchestration. Lightweight one-off delegation can stay lightweight.
12
12
  - **Advisory review**: use fresh-context `commentator` agents for adversarial code review, or fork to `commentator` when inherited decisions and drift matter
13
13
  - **Implementation handoff**: have `commentator` advise, then `builder` implement only after an approved direction
14
- - **Recon and planning**: use `explorer` or `explorer`, then `architect`
14
+ - **Recon and planning**: use `explorer`, then `architect`
15
15
  - **Parallel exploration**: run multiple non-conflicting tasks concurrently
16
16
  - **Regular skill specialists**: when discovery shows proactive skill subagent suggestions and the current work is broad enough, launch a small fresh-context fanout that asks one subagent per relevant regularly used skill to apply that skill's perspective to the task
17
17
  - **Long-running work**: launch async/background runs and inspect them later. For mutation-capable work, bound the delivery slice and elapsed runtime, then request checkpoints after active tool work returns. Reserve hard turn and tool-call caps for explicitly read-only children.
@@ -179,17 +179,16 @@ and user/project agents override builtins with the same name.
179
179
 
180
180
  | Agent | Purpose | Model | Typical output / role |
181
181
  |-------|---------|-------|------------------------|
182
- | `explorer` | Fast codebase recon | inherits default | Writes `context.md` handoff material |
183
- | `architect` | Creates implementation plans | inherits default | Writes `plan.md` |
182
+ | `architect` | Creates implementation plans | inherits default | Read-only planning; returns the complete plan in its final response |
184
183
  | `builder` | Implementation and approved commentator handoffs | inherits default | Single-writer implementation with decision escalation |
185
- | `commentator` | Review specialist | inherits default | Default recipes are review-only; tools include edit/write when a fix pass is explicit |
186
- | `explorer` | Requirements/codebase handoff builder | inherits default | Writes structured context files |
187
- | `researcher` | Web research brief generator | inherits default | Writes `research.md` |
188
- | `builder` | Lightweight generic builder | inherits default | No fixed output; generic delegated work |
189
- | `commentator` | Decision-consistency advisory review | inherits default | Advisory review, intercom coordination |
190
- | `commentator` | Claude Code-compatible alias for `commentator` | inherits default | Same advisory role as `commentator` |
184
+ | `commentator` | Review specialist | inherits default | Review-only findings in its final response; no edit/write tools |
185
+ | `explorer` | Fast codebase recon | inherits default | Read-only recon findings in its final response |
186
+ | `recapper` | Current-state handoff specialist | inherits default | Fork-context handoff; returns a self-contained handoff in its final response |
187
+ | `researcher` | Sourced research brief generator | inherits default | Read-only brief in its final response |
191
188
 
192
- Builtin `builder` and `builder` use strict tool allowlists and do not inherit ambient parent extension tools. To give a child an extension tool, name it in `tools` and load its provider via `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. Custom agents without an `extensions` field follow `subagents.defaultExtensions` when set.
189
+ Only `architect` and `recapper` resolve to forked context when a launch omits `context`; `builder`, `commentator`, `explorer`, and `researcher` default to fresh context. Read-only builtins return their output in the final response; output files are written only when the caller configures output persistence.
190
+
191
+ Explicit `tools` is an allowlist, but ambient extension discovery remains possible unless `extensions`, `subagentOnlyExtensions`, or a capability ceiling constrains it; naming a tool alone does not load its provider. To give a child an extension tool, name it in `tools` and load its provider via `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. Custom agents without an `extensions` field follow `subagents.defaultExtensions` when set.
193
192
 
194
193
  Builtin agents inherit the current Pi default model unless a run, user setting, project setting, or `subagents.defaultModel` overrides `model`. Set `subagents.defaultModel` when subagents should use a different default model than the parent session. Override builtin defaults before copying full agent files when a small tweak is enough.
195
194
 
@@ -266,7 +265,7 @@ agent with the same name only when you want a substantially different agent.
266
265
  When several providers are available, route agents by task shape instead of one model for everything:
267
266
 
268
267
  1. **Fast workhorse** — cheapest capable model at low thinking for recon, lookups, and mechanical edits (for example on `explorer`).
269
- 2. **Standard well-scoped** — mid-tier model at medium thinking for most delegations: routine multi-file edits, focused reviews, straightforward implementation (for example on `builder`, `commentator`, `builder`).
268
+ 2. **Standard well-scoped** — mid-tier model at medium thinking for most delegations: routine multi-file edits, focused reviews, straightforward implementation (for example on `builder` and `commentator`).
270
269
  3. **Deep but bounded** — top reasoning model at high thinking only for hard tasks that arrive with explicit goals and completion criteria; these models loop on vague goals (for example on `architect` and commentator-style agents).
271
270
  4. **Taste and intent** — a model that reads human intent well for ambiguous work: UX/design judgment, product tradeoffs, planning from vague requirements, writing quality.
272
271
 
@@ -28,13 +28,14 @@ import { discoverAvailableSkills, resolveSkills } from "./skills.ts";
28
28
  import {
29
29
  buildProactiveSkillSubagentRecommendationLines,
30
30
  } from "./proactive-skills.ts";
31
+ import { formatTaskAwareAgentRecommendation, recommendTaskAwareAgent } from "./task-aware-routing.ts";
31
32
  import { parseFrontmatter } from "./frontmatter.ts";
32
33
  import { toModelInfo } from "../shared/model-info.ts";
33
34
  import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-fallback.ts";
34
35
  import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
35
36
  import { resolveTurnBudgetConfig } from "../runs/shared/turn-budget.ts";
36
37
  import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
37
- import type { AcceptanceInput, Details, ExtensionConfig, ToolBudgetConfig } from "../shared/types.ts";
38
+ import type { AcceptanceInput, CatalogAgentMetadata, Details, ExtensionConfig, ToolBudgetConfig } from "../shared/types.ts";
38
39
  import { getProjectConfigDir } from "../shared/utils.ts";
39
40
  import { capabilityCeilingAgentRestrictionSources, isAgentAllowedByCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
40
41
 
@@ -48,10 +49,12 @@ interface ManagementParams {
48
49
  chainName?: string;
49
50
  agentScope?: string;
50
51
  config?: unknown;
52
+ /** Optional advisory intent for action:'list' only; never launches work. */
53
+ task?: string;
51
54
  }
52
55
 
53
- function result(text: string, isError = false): AgentToolResult<Details> {
54
- return { content: [{ type: "text", text }], isError, details: { mode: "management", results: [] } };
56
+ function result(text: string, isError = false, extraDetails: Partial<Details> = {}): AgentToolResult<Details> {
57
+ return { content: [{ type: "text", text }], isError, details: { mode: "management", results: [], ...extraDetails } };
55
58
  }
56
59
 
57
60
  function parseCsv(value: string): string[] {
@@ -585,8 +588,13 @@ function renamePath(
585
588
  return { filePath };
586
589
  }
587
590
 
591
+ /** Effective declared tools: normal tools plus mcp:-prefixed direct MCP tools. */
592
+ function effectiveAgentTools(agent: AgentConfig): string[] {
593
+ return [...(agent.tools ?? []), ...(agent.mcpDirectTools ?? []).map((t) => `mcp:${t}`)];
594
+ }
595
+
588
596
  function formatAgentDetail(agent: AgentConfig): string {
589
- const tools = [...(agent.tools ?? []), ...(agent.mcpDirectTools ?? []).map((t) => `mcp:${t}`)];
597
+ const tools = effectiveAgentTools(agent);
590
598
  const lines: string[] = [`Agent: ${agent.name} (${agent.source})`, `Path: ${agent.filePath}`, `Description: ${agent.description}`];
591
599
  if (agent.packageName) {
592
600
  lines.push(`Local name: ${frontmatterNameForConfig(agent)}`);
@@ -672,6 +680,33 @@ function formatChainDetail(chain: ChainConfig): string {
672
680
  return lines.join("\n");
673
681
  }
674
682
 
683
+ function formatCatalogAgentLine(agent: AgentConfig): string {
684
+ const parts: string[] = [agent.source, `context: ${agent.defaultContext ?? "fresh"}`];
685
+ if (agent.acceptanceRole) parts.push(`role: ${agent.acceptanceRole}`);
686
+ if (agent.aliases?.length) parts.push(`aliases: ${agent.aliases.join(", ")}`);
687
+ const tools = effectiveAgentTools(agent);
688
+ if (tools.length) parts.push(`tools: ${tools.join(", ")}`);
689
+ return `- ${agent.name} (${parts.join(", ")}): ${agent.description}`;
690
+ }
691
+
692
+ function catalogAgentMetadata(
693
+ agent: AgentConfig,
694
+ executable: boolean,
695
+ restrictionSources: string[] | undefined,
696
+ ): CatalogAgentMetadata {
697
+ return {
698
+ name: agent.name,
699
+ source: agent.source,
700
+ description: agent.description,
701
+ executable,
702
+ ...(restrictionSources?.length ? { restrictionSources } : {}),
703
+ ...(agent.aliases?.length ? { aliases: [...agent.aliases] } : {}),
704
+ defaultContext: agent.defaultContext ?? "fresh",
705
+ ...(agent.acceptanceRole ? { acceptanceRole: agent.acceptanceRole } : {}),
706
+ tools: effectiveAgentTools(agent),
707
+ };
708
+ }
709
+
675
710
  export function handleList(params: ManagementParams, ctx: ManagementContext): AgentToolResult<Details> {
676
711
  const scope = normalizeListScope(params.agentScope) ?? "both";
677
712
  const d = discoverAgentsAll(ctx.cwd);
@@ -690,23 +725,35 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
690
725
  config: ctx.config?.proactiveSkillSubagents,
691
726
  discoverAvailableSkills: () => discoverAvailableSkills(ctx.cwd),
692
727
  });
728
+ const taskAdvice = params.task?.trim()
729
+ ? formatTaskAwareAgentRecommendation(recommendTaskAwareAgent({ task: params.task, agents, capabilityCeiling }))
730
+ : [];
693
731
  const lines = [
694
732
  "Executable agents:",
695
- ...(agents.length
696
- ? agents.map((a) => `- ${a.name} (${a.source}${a.defaultContext ? `, context: ${a.defaultContext}` : ""}${a.aliases?.length ? `, aliases: ${a.aliases.join(", ")}` : ""}): ${a.description}`)
697
- : ["- (none)"]),
733
+ ...(agents.length ? agents.map(formatCatalogAgentLine) : ["- (none)"]),
698
734
  ...(restrictedAgents.length ? [
699
735
  "",
700
736
  `Restricted agents (not executable in this session${restrictedSources?.length ? `; capability ceiling: ${restrictedSources.join(", ")}` : ""}):`,
701
- ...restrictedAgents.map((a) => `- ${a.name} (${a.source}${a.aliases?.length ? `, aliases: ${a.aliases.join(", ")}` : ""}): ${a.description}`),
737
+ ...restrictedAgents.map(formatCatalogAgentLine),
702
738
  ] : []),
703
739
  "",
704
740
  "Chains:",
705
741
  ...(chains.length ? chains.map((c) => `- ${c.name} (${c.source}): ${c.description}`) : ["- (none)"]),
706
742
  ...(proactiveSuggestions.length ? ["", ...proactiveSuggestions] : []),
743
+ ...(taskAdvice.length ? ["", ...taskAdvice] : []),
707
744
  ...(diagnostics.length ? ["", "Chain diagnostics:", ...diagnostics.map((entry) => `- ${entry.filePath}: ${entry.error}`)] : []),
708
745
  ];
709
- return result(lines.join("\n"));
746
+ return result(lines.join("\n"), false, {
747
+ catalog: {
748
+ version: 1,
749
+ agents: [
750
+ ...agents.map((a) => catalogAgentMetadata(a, true, undefined)),
751
+ ...restrictedAgents.map((a) => catalogAgentMetadata(a, false, restrictedSources)),
752
+ ],
753
+ chains: chains.map((c) => ({ name: c.name, source: c.source, description: c.description })),
754
+ ...(restrictedSources?.length ? { capabilityCeilingSources: restrictedSources } : {}),
755
+ },
756
+ });
710
757
  }
711
758
 
712
759
  function formatModelSource(agent: AgentConfig, currentModel: ParentModel | undefined): string {
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Pure task-aware advisory agent recommender.
3
+ *
4
+ * Given an already-discovered, effective agent set and the current capability
5
+ * ceiling, deterministically selects at most one canonical agent to recommend
6
+ * for a task, or returns recovery guidance when intent is unknown or no safe
7
+ * candidate exists. This module is deliberately pure: it performs no
8
+ * filesystem/discovery access, no alias/chains/executor/RPC/preflight/settings
9
+ * access, no mutation, launch, scheduling, or persistence, and never writes to
10
+ * params. Launching stays explicit: the caller must make a separate execution
11
+ * call with the recommended canonical `agent.name`.
12
+ */
13
+
14
+ import type { AgentConfig, AgentSource } from "./agents.ts";
15
+ import { agentHasWriteTools } from "./agent-memory.ts";
16
+ import { classifyTaskMutationIntent, resolveAgentRoutingRole } from "../runs/shared/task-intent.ts";
17
+ import { isAgentAllowedByCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
18
+
19
+ /** Core tools that make an implementation agent able to write (matches agent-memory). */
20
+ const WRITER_TOOLS = new Set(["edit", "write", "bash"]);
21
+
22
+ /** Source precedence for deterministic ordering: project > user > package > builtin. */
23
+ const AGENT_SOURCE_PRECEDENCE: Record<AgentSource, number> = { builtin: 0, package: 1, user: 2, project: 3 };
24
+
25
+ export type TaskAwareAgentIntent = "implementation" | "read-only" | "unknown";
26
+
27
+ export interface TaskAwareAgentRecommendationAgent {
28
+ /** Canonical runtime agent name accepted by execution; never an alias. */
29
+ name: string;
30
+ source: AgentSource;
31
+ role: "writer" | "read-only";
32
+ roleBasis: "declared" | "inferred";
33
+ reason: string;
34
+ }
35
+
36
+ export interface TaskAwareAgentRecommendation {
37
+ intent: TaskAwareAgentIntent;
38
+ agent?: TaskAwareAgentRecommendationAgent;
39
+ /** Recovery guidance when no safe recommendation exists (unknown intent or no candidate). */
40
+ next?: string;
41
+ }
42
+
43
+ /**
44
+ * Recommend a canonical agent for a trimmed non-empty task, or `undefined` for
45
+ * an empty/whitespace task (no-op). Never recommends disabled or
46
+ * capability-disallowed agents, never guesses for unknown intent, and never
47
+ * outputs an alias or a role-incompatible agent.
48
+ */
49
+ export function recommendTaskAwareAgent(input: {
50
+ task: string;
51
+ agents: AgentConfig[];
52
+ capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
53
+ }): TaskAwareAgentRecommendation | undefined {
54
+ const task = input.task.trim();
55
+ if (!task) return undefined;
56
+
57
+ const intent = classifyTaskMutationIntent("builder", task).kind;
58
+ if (intent === "unknown") {
59
+ return {
60
+ intent,
61
+ next: "Clarify whether the task is read-only analysis/review or implementation allowed to edit files.",
62
+ };
63
+ }
64
+
65
+ const candidates: TaskAwareAgentRecommendationAgent[] = [];
66
+ for (const agent of input.agents) {
67
+ if (agent.disabled) continue;
68
+ if (!isAgentAllowedByCapabilityCeiling(agent.name, input.capabilityCeiling)) continue;
69
+ const role = resolveAgentRoutingRole(agent.name, agent.acceptanceRole);
70
+ if (!role) continue;
71
+ const hasWriteTools = agentHasWriteTools(agent);
72
+ if (intent === "implementation") {
73
+ if (role !== "writer" || !hasWriteTools) continue;
74
+ const allowedTools = input.capabilityCeiling?.allowedTools;
75
+ if (allowedTools !== undefined && !allowedTools.some((tool) => WRITER_TOOLS.has(tool))) continue;
76
+ } else {
77
+ if (role !== "read-only" || hasWriteTools) continue;
78
+ }
79
+ const roleBasis = agent.acceptanceRole !== undefined ? "declared" : "inferred";
80
+ candidates.push({
81
+ name: agent.name,
82
+ source: agent.source,
83
+ role,
84
+ roleBasis,
85
+ reason: intent === "implementation"
86
+ ? `${roleBasis} writer role with write tools`
87
+ : `${roleBasis} read-only role without known write tools`,
88
+ });
89
+ }
90
+
91
+ candidates.sort((a, b) => {
92
+ const sourceOrder = AGENT_SOURCE_PRECEDENCE[b.source] - AGENT_SOURCE_PRECEDENCE[a.source];
93
+ if (sourceOrder !== 0) return sourceOrder;
94
+ const declaredOrder = (a.roleBasis === "declared" ? 0 : 1) - (b.roleBasis === "declared" ? 0 : 1);
95
+ if (declaredOrder !== 0) return declaredOrder;
96
+ return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
97
+ });
98
+
99
+ const agent = candidates[0];
100
+ if (!agent) {
101
+ return {
102
+ intent,
103
+ next: intent === "implementation"
104
+ ? "No executable agent has a writer role with write tools for this task. Check the executable/restricted sections above or adjust the capability ceiling."
105
+ : "No executable agent has a read-only role without known write tools for this task. Check the executable/restricted sections above.",
106
+ };
107
+ }
108
+ return { intent, agent };
109
+ }
110
+
111
+ /** Text-only advisory lines; `undefined` (empty-task no-op) renders nothing. */
112
+ export function formatTaskAwareAgentRecommendation(recommendation: TaskAwareAgentRecommendation | undefined): string[] {
113
+ if (!recommendation) return [];
114
+ const lines = ["Task-aware advisory routing:", `- Intent: ${recommendation.intent}`];
115
+ if (recommendation.agent) {
116
+ lines.push(`- Recommended: ${recommendation.agent.name} (${recommendation.agent.source})`);
117
+ lines.push(`- Reason: ${recommendation.agent.reason}`);
118
+ lines.push("- Advisory only: no subagent was launched. To proceed, explicitly call subagent with this canonical agent name and the task.");
119
+ } else {
120
+ lines.push("- Recommendation: none");
121
+ lines.push(`- Next: ${recommendation.next ?? "Refine the task wording and retry."}`);
122
+ lines.push("- Advisory only: no subagent was launched.");
123
+ }
124
+ return lines;
125
+ }
@@ -284,7 +284,7 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
284
284
  diagnostics.push({ code: "denied_required_tool", severity: "error", message });
285
285
  return { ok: false, code: "denied_required_tool", message, diagnostics };
286
286
  }
287
- const artifactsEnabled = input.artifacts !== false;
287
+ const artifactsEnabled = input.artifacts === true;
288
288
  const artifactsDir = artifactsEnabled ? getArtifactsDir(input.parentSessionFile ?? null, effectiveCwd, input.artifactDir ?? "project") : undefined;
289
289
  const artifactPaths = artifactsDir ? getArtifactPaths(artifactsDir, runId, agent.name, 0) : undefined;
290
290
  const outputPath = resolveSingleOutputPath(behavior.output, effectiveCwd, effectiveCwd, artifactsDir ? path.join(artifactsDir, "outputs", runId) : undefined);
@@ -51,7 +51,7 @@ import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/
51
51
  import { resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
52
52
  import { formatDuration, shortenPath } from "../shared/formatters.ts";
53
53
  import { loadConfig } from "./config.ts";
54
- import { buildSubagentToolDescription } from "./tool-description.ts";
54
+ import { buildSubagentToolDescription, SUBAGENT_PARENT_ROUTING_GUIDANCE } from "./tool-description.ts";
55
55
  import {
56
56
  type Details,
57
57
  type SubagentState,
@@ -405,6 +405,10 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
405
405
  name: "subagent",
406
406
  label: "Subagent",
407
407
  description: buildSubagentToolDescription(config),
408
+ // Always-visible active-tool path: rendered into the main system prompt by
409
+ // buildSystemPrompt (default and custom-prompt branches). Parent-only; the
410
+ // child-safe fanout registration must not receive this guidance.
411
+ promptGuidelines: [SUBAGENT_PARENT_ROUTING_GUIDANCE],
408
412
  parameters: SubagentParams,
409
413
 
410
414
  prepareArguments(args) {
@@ -262,7 +262,7 @@ const ControlOverrides = Type.Object({
262
262
 
263
263
  const SubagentParamsSchema = Type.Object({
264
264
  agent: Type.Optional(Type.String({ description: "Agent name (SINGLE mode) or target for management get/update/delete" })),
265
- task: Type.Optional(Type.String({ description: "Task (SINGLE mode, optional for self-contained agents)" })),
265
+ task: Type.Optional(Type.String({ description: "Task for SINGLE-mode execution, or an optional advisory intent for action:'list' (list only appends a task-aware recommendation and never launches work; explicitly call subagent with the recommended canonical agent name and the task to execute)" })),
266
266
  // Management action (when present, tool operates in management mode)
267
267
  action: Type.Optional(Type.String({
268
268
  description: "Optional management/control action. Omit this field entirely for execution/delegation ({agent, task}, {tasks}, or {chain}); use it only for management/control actions."
@@ -321,7 +321,7 @@ const SubagentParamsSchema = Type.Object({
321
321
  usageBudget: Type.Optional(UsageBudgetOverride),
322
322
  agentScope: Type.Optional(Type.String({ description: "Agent discovery scope: 'user', 'project', or 'both' (default: 'both'; project wins on name collisions)" })),
323
323
  cwd: Type.Optional(Type.String()),
324
- artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: true)" })),
324
+ artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: false)" })),
325
325
  includeProgress: Type.Optional(Type.Boolean({ description: "Include full progress in result (default: false)" })),
326
326
  share: Type.Optional(Type.Boolean({ description: "Upload session to GitHub Gist for sharing (default: false)" })),
327
327
  sessionDir: Type.Optional(