@ferris1225/pi-subagents 4.3.4 → 4.3.5

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 (37) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +59 -66
  3. package/agents/artisan.md +0 -1
  4. package/agents/steward.md +1 -2
  5. package/{src/index.ts → index.ts} +19 -19
  6. package/package.json +4 -3
  7. package/src/{config.ts → configuration/config.ts} +19 -24
  8. package/src/configuration/setup.ts +375 -0
  9. package/src/configuration/ui.ts +245 -0
  10. package/src/{agents.ts → delegation/agents.ts} +3 -3
  11. package/src/{dispatch.ts → delegation/dispatch.ts} +12 -18
  12. package/src/{prompt.ts → delegation/prompt.ts} +3 -8
  13. package/src/{background.ts → execution/background.ts} +3 -6
  14. package/src/execution/rpc-control.ts +200 -0
  15. package/src/{rpc-run.ts → execution/rpc-run.ts} +11 -199
  16. package/src/{session-fork.ts → execution/session-fork.ts} +1 -1
  17. package/src/{spawn.ts → execution/spawn.ts} +10 -8
  18. package/src/isolation/git-command.ts +147 -0
  19. package/src/{recovery.ts → isolation/recovery.ts} +1 -1
  20. package/src/{worktree.ts → isolation/worktree.ts} +10 -147
  21. package/src/{completion.ts → lifecycle/completion.ts} +2 -2
  22. package/src/{durable.ts → lifecycle/durable.ts} +3 -3
  23. package/src/{runtime.ts → lifecycle/runtime.ts} +7 -7
  24. package/src/{thread-lifecycle.ts → lifecycle/thread-lifecycle.ts} +25 -519
  25. package/src/lifecycle/thread-restore.ts +250 -0
  26. package/src/lifecycle/thread-shared.ts +269 -0
  27. package/src/{tools.ts → lifecycle/tools.ts} +8 -8
  28. package/src/{announcements.ts → presentation/announcements.ts} +4 -4
  29. package/src/{format.ts → presentation/format.ts} +3 -3
  30. package/src/{monitor.ts → presentation/monitor.ts} +2 -2
  31. package/src/{widget.ts → presentation/widget.ts} +1 -1
  32. package/agents/sentinel.md +0 -16
  33. package/src/setup.ts +0 -344
  34. package/src/ui.ts +0 -160
  35. /package/src/{models.ts → configuration/models.ts} +0 -0
  36. /package/src/{temp-hygiene.ts → isolation/temp-hygiene.ts} +0 -0
  37. /package/src/{status.ts → presentation/status.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ Published versions of `@ferris1225/pi-subagents`. Unpublished numbers
4
4
  (`4.2.3`, `4.2.6`, `4.2.9`–`4.2.11`) never shipped on npm; their changes
5
5
  landed in the next published release.
6
6
 
7
+ ## 4.3.5
8
+
9
+ - Restore `/subagents-setup`'s nested menu flow, fuzzy model picker, and disabled
10
+ custom-role discovery.
11
+ - Retire the built-in `sentinel` role and mandatory pre-commit review workflow.
12
+ Config normalization, loading, and saving now remove its enabled/known entries
13
+ and model/thinking overrides while preserving every other custom role.
14
+ - Keep role prompts self-contained: direct diagnosis, test, and cleanup rules remain,
15
+ while external loading directives are removed.
16
+ - Delegate substantial independent phases more proactively while capping the child-process
17
+ pool at six and retaining phase leases, duplicate-dispatch rejection, and single-route delivery.
18
+ - Move the extension assembly to package-root `index.ts`, group `src/` by responsibility,
19
+ and split thread restoration, shared lifecycle coordination, RPC control, and Git command
20
+ execution out of the largest modules. Pi now shows the package name without a `:src` suffix.
21
+
7
22
  ## 4.3.4
8
23
 
9
24
  - Keep artisan, steward, and sentinel fully usable when Ferris skills are absent.
package/README.md CHANGED
@@ -6,15 +6,17 @@
6
6
  ![platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey)
7
7
  ![pi](https://img.shields.io/badge/pi-extension-orange)
8
8
 
9
- A managed engineering team for [pi](https://github.com/earendil-works/pi): four
9
+ A managed engineering team for [pi](https://github.com/earendil-works/pi): three
10
10
  focused sub-agents, durable threads, and Git worktree isolation. You install it
11
11
  once and your main agent delegates on its own.
12
12
 
13
13
  ## What's new
14
14
 
15
- **4.3.4** — makes Ferris skills optional enhancements instead of runtime
16
- requirements. Artisan, steward, and sentinel remain fully operational from their
17
- standalone role prompts when users have no Ferris skills installed.
15
+ **4.3.5** — restores the nested setup menus, returns to the three built-in roles,
16
+ removes mandatory review/skill directives, delegates independent phases more proactively
17
+ with at most six child processes, and uses a package-root entry so Pi shows the clean
18
+ package name. Existing configs retain custom roles while dropping the retired `sentinel`.
19
+
18
20
  See [CHANGELOG.md](./CHANGELOG.md).
19
21
 
20
22
  ## Contents
@@ -41,8 +43,9 @@ at "spawn a child with a prompt" and leave the hard parts — when to delegate,
41
43
  wide to fan out, what happens when a model dies, how results come
42
44
  back — with you. This extension owns them:
43
45
 
44
- - The main model gets a cost-aware routing contract and delegates only when a leaf
45
- context saves more work than its handoff costs.
46
+ - The main model gets a cost-aware routing contract and proactively delegates
47
+ substantial self-contained phases when a fresh context saves more work than its
48
+ handoff costs.
46
49
  - One active normalized task and working directory owns its phase, so an exact
47
50
  duplicate dispatch is rejected instead of paying twice.
48
51
  - Background completions wake the main model; `wait: true` returns the same result
@@ -63,11 +66,14 @@ Requires **pi >= 0.84.4** and **Node.js >= 22.19.0**.
63
66
  pi install npm:@ferris1225/pi-subagents
64
67
  ```
65
68
 
66
- Open pi and run `/subagents-setup`. One overlay shows every role's enabled state,
67
- model, and effective thinking level. Move through the grid, search models in place,
68
- then choose **Save & Exit** to write everything once; **Cancel** or `Esc` discards
69
- the draft. Fresh installs select all four, and an upgrade surfaces a new built-in
70
- once without re-enabling it after you deliberately turn it off. Then ask for work:
69
+ Pi's extension list shows `@ferris1225/pi-subagents` without an internal source-path suffix.
70
+
71
+ Open pi and run `/subagents-setup`. The original menu flow lets you enable or
72
+ disable roles, configure one role's model and thinking level, or run the full setup
73
+ again. Each screen uses the usual arrow-key/Enter/Esc navigation, and model lists
74
+ remain searchable. Fresh installs select all three. A newly shipped built-in is
75
+ surfaced once without being re-enabled after you deliberately turn it off. Then ask
76
+ for work:
71
77
 
72
78
  ```text
73
79
  Map how authentication works, fix the refresh race, run the tests, and review the diff.
@@ -78,18 +84,14 @@ directly when you want exact control.
78
84
 
79
85
  ## The team
80
86
 
81
- | Agent | Access | Owns |
82
- | ---------- | ----------- | ---- |
83
- | `scout` | Read-only | Broad or unfamiliar code reconnaissance and external research. Returns compact file citations or source URLs as leads, not proof. |
84
- | `artisan` | Full | One substantial primary change—implementation, fix, refactor, test, or docs—through root cause, affected verification, and local hygiene. |
85
- | `steward` | Full | One final cleanup and cross-cutting docs/comment sync pass after a broad or multi-writer change. |
86
- | `sentinel` | Review-only | A post-cleanup adversarial review using standalone evidence gates plus any matching Ferris skills; reports only evidence-backed defects and concrete test gaps. |
87
+ | Agent | Access | Owns |
88
+ | --------- | --------- | ---- |
89
+ | `scout` | Read-only | Broad or unfamiliar code reconnaissance and external research. Returns compact file citations or source URLs as leads, not proof. |
90
+ | `artisan` | Full | One substantial primary change—implementation, fix, refactor, test, or docs—through root cause, affected verification, and local hygiene. |
91
+ | `steward` | Full | One final cleanup and cross-cutting docs/comment sync pass after a broad or multi-writer change. |
87
92
 
88
- Role prompts are standalone: they embed root-cause-first diagnosis, meaningful test
89
- evidence, bounded cleanup, and evidence-only review. Optional Ferris skills remain
90
- the canonical source of deeper language, platform, debugging, testing, and audit
91
- guidance. Artisan and sentinel load matching skills when available; steward uses
92
- `ferris-audit`; a missing skill never blocks a role or changes its ownership contract.
93
+ Role prompts are self-contained and directly embed root-cause-first diagnosis,
94
+ meaningful test evidence, and bounded cleanup.
93
95
 
94
96
  Custom roles join them with a Markdown file (see [Custom agents](#custom-agents)).
95
97
 
@@ -116,11 +118,10 @@ subagent({
116
118
  });
117
119
  ```
118
120
 
119
- Breadth is the main agent's call, not a configured limit. There is no per-call
120
- task cap: put every genuinely independent unit in one `tasks` array. The runtime
121
- paces execution instead, running a pool of child processes that scales with the
122
- machine (half its cores, bounded to 4–16) and starting queued runs automatically
123
- as slots free.
121
+ Breadth is the main agent's call, not a configured task cap: put every genuinely
122
+ independent unit in one `tasks` array. The runtime paces execution instead, running
123
+ half the machine's cores with a 4–6 child-process bound; wider batches queue and
124
+ start automatically as slots free.
124
125
 
125
126
  An active run leases its normalized task and resolved working directory across
126
127
  agent names. Dispatching the same pair again is rejected and names the existing
@@ -133,26 +134,23 @@ starting its child — alongside the slot capacity. A run that waits for the wri
133
134
  lane releases its slot first, so serialized writers never starve new dispatches.
134
135
 
135
136
  One child owns one coherent phase. Dependent work starts only after its
136
- prerequisite delivers. Artisan owns a complete primary change with affected
137
- tests, docs, comments, targeted checks, and local hygiene. Scout owns broad code
138
- mapping or external research and stays read-only.
137
+ prerequisite delivers. Main consumes the child's compact result and citations
138
+ without repeating delegated reconnaissance, implementation, or cleanup. Artisan
139
+ owns a complete primary change with affected tests, docs, comments, targeted
140
+ checks, and local hygiene. Scout owns broad code mapping or external research and
141
+ stays read-only.
139
142
 
140
- With the default team, every commit ends in one order: cleanup -> `sentinel`. A
141
- focused diff gets a bounded cleanup pass inline; a broad or multi-writer diff gets
143
+ A focused diff gets a bounded cleanup pass inline. A broad or multi-writer diff gets
142
144
  one `steward` pass that attacks touched dead code, duplication, tangled conditionals,
143
- needless layers, and spaghetti growth without widening into a repo refactor.
144
- Sentinel then reviews the cleaned diff with its standalone evidence gates plus any
145
- available matching skills.
146
- A review-driven edit repeats that sequence once; unresolved findings block the
147
- commit. Main inspects the final diff and runs the final gate.
145
+ needless layers, and spaghetti growth without widening into a repository refactor.
146
+ Main inspects the integrated diff and runs the final gate.
148
147
 
149
148
  ## Parallel edits
150
149
 
151
150
  - Single tasks use your checkout. Every parallel write-capable agent (`artisan`,
152
151
  `steward`, and custom writers) defaults to a detached Git worktree, so
153
- parallel writers run at the same time. Worktree mode needs a committed `HEAD`,
154
- and scout/sentinel reject it. Sentinel stays shared so it sees the caller's
155
- uncommitted diff.
152
+ parallel writers run at the same time. Worktree mode needs a committed `HEAD`;
153
+ read-only roles such as scout stay on the shared checkout.
156
154
  - A role file can pin its own default with `isolation: worktree` or
157
155
  `isolation: shared` in the frontmatter. Precedence is an explicit per-dispatch
158
156
  `isolation`, then the role's declaration, then the parallel write default.
@@ -279,17 +277,15 @@ rather than a fabricated number.
279
277
  ## Models, thinking, and tools
280
278
 
281
279
  Each agent runs on the current main model or one picked in `/subagents-setup`,
282
- which labels vision and text-only models. Without its own override, `sentinel`
283
- uses `artisan`'s configured model; if artisan also follows main, sentinel does
284
- too. If a selected model is missing, rate-limited, or fails at the provider level,
285
- the **same retained
280
+ which labels vision and text-only models. If a selected model is missing,
281
+ rate-limited, or fails at the provider level, the **same retained
286
282
  session** continues on the main model, so finished searches, reads, and edits
287
283
  survive. Ordinary task failures do not trigger a handoff.
288
284
 
289
- Thinking is a **role default** — scout `low`, artisan `high`, steward `medium`,
290
- sentinel `max` — clamped to what the effective model supports. The unified setup
291
- grid shows the effective level; changing the thinking cell cycles only supported
292
- levels, and returning to the role default clears the stored override. There is no
285
+ Thinking is a **role default** — scout `low`, artisan `high`, steward `medium` —
286
+ clamped to what the effective model supports. `/subagents-setup`
287
+ _Configure an agent_ lists only the levels that model supports and marks the role
288
+ default; selecting it clears the stored override. There is no
293
289
  Auto choice, no per-dispatch `thinking` flag, and
294
290
  no `thinking` field in agent Markdown. Precedence: your setup override > the
295
291
  role default, then the model clamp. There is no separate vision mode — assign
@@ -314,25 +310,19 @@ For external research scout prefers official documentation, specifications, rele
314
310
  notes, and first-party repositories; it fetches decisive pages rather than citing
315
311
  search snippets, records material dates/versions, and marks uncertainty.
316
312
 
317
- `sentinel` has an explicit retrieval/documentation list plus a portable shell
318
- slot for Git inspection and the smallest proving check. It is pinned to `shared`
319
- so it sees the current uncommitted diff. Its concise prompt uses matching available
320
- Ferris skills, preserves their owners, and forbids mutation; missing skills do not
321
- block review. This is a review contract,
322
- not a hard shell sandbox.
323
-
324
313
  ## Configuration
325
314
 
326
- `/subagents-setup` opens one transactional overlay for every built-in and already
327
- configured custom role. Its grid edits enabled state, model, and thinking before
328
- **Save & Exit** persists the complete draft; **Cancel**/`Esc` writes nothing. Model
329
- selection remains inside the overlay and supports fuzzy search. Other settings live in
315
+ `/subagents-setup` opens the original settings menu: enable or disable roles,
316
+ configure one enabled role's model and thinking level, or walk through a full
317
+ re-setup. `Esc` moves back through the menu stack, and model lists support fuzzy
318
+ search. Built-in and previously configured custom roles remain available in the
319
+ enable menu. Other settings live in
330
320
  `~/.pi/agent/pi-subagents.json` (following `PI_CODING_AGENT_DIR`):
331
321
 
332
322
  ```json
333
323
  {
334
- "enabledAgents": ["scout", "artisan", "steward", "sentinel"],
335
- "knownAgents": ["scout", "artisan", "steward", "sentinel"],
324
+ "enabledAgents": ["scout", "artisan", "steward"],
325
+ "knownAgents": ["scout", "artisan", "steward"],
336
326
  "agentModels": { "scout": "anthropic/claude-haiku-4-5" },
337
327
  "agentThinkingLevels": { "artisan": "high" },
338
328
  "maxResultLines": 40,
@@ -345,7 +335,7 @@ selection remains inside the overlay and supports fuzzy search. Other settings l
345
335
  | --------------------- | ------- |
346
336
  | `enabledAgents` | Agents available for discovery and delegation. `[]` disables all. |
347
337
  | `knownAgents` | Roles already surfaced by setup; retains disabled custom roles and tracks built-in adoption. |
348
- | `agentModels` | Optional model per agent; missing means main, except sentinel inherits artisan's override. |
338
+ | `agentModels` | Optional model per agent; missing means the current main model. |
349
339
  | `agentThinkingLevels` | Optional setup override per agent; missing means the role default. |
350
340
  | `maxResultLines` | Lines kept in a completion message before the artifact takes over. Default `40`. |
351
341
  | `agentScope` | Discover `user`, `project`, or `both` agent directories. Default `user`. |
@@ -354,8 +344,10 @@ selection remains inside the overlay and supports fuzzy search. Other settings l
354
344
  When at least one role is enabled, the cost-aware delegation directive is injected
355
345
  automatically. `enabledAgents` is authoritative after catalog adoption: a newly
356
346
  shipped built-in is appended once, then `knownAgents` records that it was surfaced
357
- so a deliberate later disable remains disabled. Invalid known fields fall back
358
- safely, and unknown fields are dropped when canonical config is persisted.
347
+ so a deliberate later disable remains disabled. On upgrade, the retired `sentinel`
348
+ entry is removed from enabled and known agents plus model and thinking overrides;
349
+ all other custom roles and known-agent entries remain intact. Invalid known fields
350
+ fall back safely, and unknown fields are dropped when canonical config is persisted.
359
351
 
360
352
  At session start, model overrides that pi no longer reports are removed with a
361
353
  one-time notice. If pi's own session compaction fails mid-thread, a notice surfaces
@@ -418,8 +410,9 @@ npm run check
418
410
 
419
411
  `npm run check` is `tsc --noEmit` plus the unit tests (`npm test`). There are
420
412
  no bundled runtime dependencies; pi and TypeBox are peers. The source is
421
- split by responsibility: dispatch policy, thread lifecycle, RPC
422
- transport, worktree integration, completion delivery, tools, and TUI status.
413
+ grouped by responsibility under `src/`: configuration, delegation, execution, isolation,
414
+ lifecycle, and presentation. Thread restoration, shared lifecycle coordination, RPC control,
415
+ and Git command execution live in focused modules rather than oversized catch-all files.
423
416
 
424
417
  ## Changelog
425
418
 
package/agents/artisan.md CHANGED
@@ -7,7 +7,6 @@ You own one primary change phase: implementation, fix, refactor, test, or substa
7
7
 
8
8
  ## Rules
9
9
 
10
- - Use matching ferris skills when available: `ferris-debug` for unexplained failures, `ferris-tests` for test changes, and the relevant language or platform skill. Missing skills are not a blocker; the rules below are the fallback contract.
11
10
  - For a reported defect or failure, inspect current behavior, confirm the defect before editing, and establish its root cause; a disproved issue means zero edits.
12
11
  - Make the smallest coherent root-cause change. Preserve unrelated work and existing conventions; avoid speculative abstractions and unrelated cleanup.
13
12
  - Own the complete primary change plus directly affected tests, README/docs, comments, and local diff hygiene. Remove debug output, dead code, stale comments, and other debris introduced in your scope.
package/agents/steward.md CHANGED
@@ -3,11 +3,10 @@ name: steward
3
3
  description: Pre-commit cleanup and cross-cutting docs/comment sync for a completed broad or multi-writer change.
4
4
  ---
5
5
 
6
- You own one final hygiene phase after primary writing has finished and before sentinel review. The task brief is your only context.
6
+ You own one final hygiene phase after primary writing has finished. The task brief is your only context.
7
7
 
8
8
  ## Rules
9
9
 
10
- - Use `ferris-audit` when available and apply its automatic pre-commit tier. Missing skills are not a blocker; the rules below are the fallback contract and must not widen into repo-wide cleanup.
11
10
  - Require a named completed scope such as an uncommitted diff or Git range. Start there; never repeat implementation or reconnaissance, and stop if primary writing is still active.
12
11
  - Hunt hard inside the touched scope: dead or unreachable code, unused imports/exports, duplicated facts or branches, debug residue, stale comments, one-off flags, tangled conditionals, pass-through wrappers, cast/optional fallback sprawl, feature logic in shared paths, and growth toward 1000-line files.
13
12
  - Prefer deleting branches, state, and layers; otherwise reuse the canonical helper. Never merely move spaghetti. Prove every cut has no live consumer, and keep uncertain dynamic behavior, public APIs, persisted formats, and compatibility.
@@ -3,12 +3,12 @@
3
3
  *
4
4
  * Assembly point: builds the shared runtime and registers everything.
5
5
  * The heavy lifting lives in focused modules:
6
- * - dispatch.ts tool contract, managed role policy, internal steps
7
- * - thread-lifecycle.tsstable generations, controls, final integration/delivery
8
- * - tools.ts subagent_control / subagent_stop
9
- * - announcements.ts session-start recovery, notices, and widget install
10
- * - widget.ts active-only TUI run status
11
- * - runtime.ts shared per-session state
6
+ * - delegation/ role discovery, routing prompts, and tool contract
7
+ * - configuration/persisted settings, model routes, and setup UI
8
+ * - execution/ process queue, RPC transport/control, and model handoff
9
+ * - lifecycle/ durable threads, restoration, controls, and delivery
10
+ * - isolation/ Git worktrees, recovery, and temporary-state hygiene
11
+ * - presentation/ announcements, formatting, monitor, status, and widget
12
12
  *
13
13
  * Also registers the `/subagents-setup` command and a `before_agent_start` hook
14
14
  * that injects a delegation directive into the parent system prompt so the main
@@ -20,19 +20,19 @@
20
20
 
21
21
  import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
22
22
  import { Text } from "@earendil-works/pi-tui";
23
- import { discoverAgents } from "./agents.ts";
24
- import { registerAnnouncements } from "./announcements.ts";
25
- import { getConfigPath, loadConfig } from "./config.ts";
26
- import { registerSubagentTool } from "./dispatch.ts";
27
- import { matchRunIds } from "./format.ts";
28
- import { buildDelegationDirective } from "./prompt.ts";
29
- import { createRuntime } from "./runtime.ts";
30
- import { runSetup } from "./setup.ts";
31
- import { currentSubagentDepth } from "./spawn.ts";
32
- import { clearActiveRunsStatus } from "./status.ts";
33
- import { bootstrapDurableState } from "./thread-lifecycle.ts";
34
- import { registerLookupTools } from "./tools.ts";
35
- import { clearActiveRunsWidget } from "./widget.ts";
23
+ import { getConfigPath, loadConfig } from "./src/configuration/config.ts";
24
+ import { runSetup } from "./src/configuration/setup.ts";
25
+ import { discoverAgents } from "./src/delegation/agents.ts";
26
+ import { registerSubagentTool } from "./src/delegation/dispatch.ts";
27
+ import { buildDelegationDirective } from "./src/delegation/prompt.ts";
28
+ import { currentSubagentDepth } from "./src/execution/spawn.ts";
29
+ import { createRuntime } from "./src/lifecycle/runtime.ts";
30
+ import { bootstrapDurableState } from "./src/lifecycle/thread-restore.ts";
31
+ import { registerLookupTools } from "./src/lifecycle/tools.ts";
32
+ import { registerAnnouncements } from "./src/presentation/announcements.ts";
33
+ import { matchRunIds } from "./src/presentation/format.ts";
34
+ import { clearActiveRunsStatus } from "./src/presentation/status.ts";
35
+ import { clearActiveRunsWidget } from "./src/presentation/widget.ts";
36
36
 
37
37
  export { matchRunIds };
38
38
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ferris1225/pi-subagents",
3
- "version": "4.3.4",
4
- "description": "A managed sub-agent team for pi: scout, artisan, steward, and sentinel roles, durable threads, model fallback, and Git worktree isolation.",
3
+ "version": "4.3.5",
4
+ "description": "A managed sub-agent team for pi: scout, artisan, and steward roles, durable threads, model fallback, and Git worktree isolation.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -25,6 +25,7 @@
25
25
  "dead-code"
26
26
  ],
27
27
  "files": [
28
+ "index.ts",
28
29
  "src",
29
30
  "agents",
30
31
  "README.md",
@@ -33,7 +34,7 @@
33
34
  ],
34
35
  "pi": {
35
36
  "extensions": [
36
- "./src/index.ts"
37
+ "./index.ts"
37
38
  ]
38
39
  },
39
40
  "scripts": {
@@ -13,11 +13,14 @@ import { dirname, join } from "node:path";
13
13
  import { getAgentDir, withFileMutationQueue } from "@earendil-works/pi-coding-agent";
14
14
 
15
15
  /** Full catalog of agents shipped with the package (selectable in /subagents-setup). */
16
- export const BUILTIN_AGENT_NAMES = ["scout", "artisan", "steward", "sentinel"] as const;
16
+ export const BUILTIN_AGENT_NAMES = ["scout", "artisan", "steward"] as const;
17
17
 
18
- // Historical catalog for configs written before the marker existed. Keep this
19
- // frozen so future built-ins are still recognized as new.
20
- const PRE_SENTINEL_AGENT_NAMES = ["scout", "artisan", "steward"] as const;
18
+ // Historical catalog for configs written before built-in adoption tracking.
19
+ // Keep this frozen so future built-ins are still recognized as new.
20
+ const INITIAL_AGENT_NAMES = ["scout", "artisan", "steward"] as const;
21
+
22
+ /** Names that used to be built in and must not survive as custom roles. */
23
+ const RETIRED_AGENT_NAMES = new Set(["sentinel"]);
21
24
 
22
25
  /** Agents enabled out of the box on a fresh install. */
23
26
  export const DEFAULT_ENABLED_AGENTS: readonly string[] = [...BUILTIN_AGENT_NAMES];
@@ -38,8 +41,6 @@ export function roleThinkingLevel(agentName: string): ThinkingLevel {
38
41
  return "low";
39
42
  case "artisan":
40
43
  return "high";
41
- case "sentinel":
42
- return "max";
43
44
  case "steward":
44
45
  return "medium";
45
46
  default:
@@ -47,14 +48,6 @@ export function roleThinkingLevel(agentName: string): ThinkingLevel {
47
48
  }
48
49
  }
49
50
 
50
- /** Sentinel shares artisan's configured model unless it has its own override. */
51
- export function configuredModelForAgent(
52
- agentModels: Readonly<Record<string, string>>,
53
- agentName: string,
54
- ): string | undefined {
55
- return agentModels[agentName] ?? (agentName === "sentinel" ? agentModels.artisan : undefined);
56
- }
57
-
58
51
  /** Short responsibility line shown next to each built-in in setup lists. */
59
52
  export interface AgentProfile {
60
53
  /** A few words for picker rows. */
@@ -76,10 +69,6 @@ export const AGENT_PROFILES: Record<(typeof BUILTIN_AGENT_NAMES)[number], AgentP
76
69
  summary: "pre-commit finish",
77
70
  remark: "Cleans a completed broad or multi-writer diff and synchronizes cross-cutting docs/comments without changing behavior.",
78
71
  },
79
- sentinel: {
80
- summary: "adversarial review",
81
- remark: "Challenges every cleaned pre-commit diff with standalone evidence gates plus available matching skills; follows artisan's model with max thinking by default.",
82
- },
83
72
  };
84
73
 
85
74
  export function agentProfile(name: string): AgentProfile | undefined {
@@ -143,8 +132,7 @@ export const DEFAULT_CONFIG: SubagentsConfig = {
143
132
 
144
133
  export const FIRST_RUN_SETUP_HINT =
145
134
  "Run /subagents-setup to choose enabled roles, models, and thinking levels. " +
146
- "Sentinel follows artisan's model by default and requests max thinking; scout and steward can use efficient models. " +
147
- "Scout maps code or researches external sources, artisan owns the primary change, steward cleans broad final diffs, and sentinel reviews after cleanup before every commit.";
135
+ "Scout maps code or researches external sources, artisan owns the primary change, and steward cleans broad final diffs.";
148
136
 
149
137
  export function getConfigPath(agentDir: string = getAgentDir()): string {
150
138
  return join(agentDir, CONFIG_FILE_NAME);
@@ -181,15 +169,21 @@ export function normalizeConfig(raw: unknown): SubagentsConfig {
181
169
 
182
170
  if (Array.isArray(raw.enabledAgents)) {
183
171
  const names = raw.enabledAgents.filter(
184
- (name): name is string => typeof name === "string" && name.trim().length > 0,
172
+ (name): name is string =>
173
+ typeof name === "string" &&
174
+ name.trim().length > 0 &&
175
+ !RETIRED_AGENT_NAMES.has(name.trim()),
185
176
  );
186
177
  // An explicitly empty array is honored; duplicates collapse.
187
178
  config.enabledAgents = [...new Set(names.map((name) => name.trim()))];
188
179
  }
189
180
 
190
- const rawKnownAgents = Array.isArray(raw.knownAgents) ? raw.knownAgents : PRE_SENTINEL_AGENT_NAMES;
181
+ const rawKnownAgents = Array.isArray(raw.knownAgents) ? raw.knownAgents : INITIAL_AGENT_NAMES;
191
182
  config.knownAgents = [...new Set(rawKnownAgents.filter(
192
- (name): name is string => typeof name === "string" && name.trim().length > 0,
183
+ (name): name is string =>
184
+ typeof name === "string" &&
185
+ name.trim().length > 0 &&
186
+ !RETIRED_AGENT_NAMES.has(name.trim()),
193
187
  ).map((name) => name.trim()))];
194
188
  for (const name of config.enabledAgents) {
195
189
  if (!config.knownAgents.includes(name)) config.knownAgents.push(name);
@@ -198,7 +192,7 @@ export function normalizeConfig(raw: unknown): SubagentsConfig {
198
192
  if (isRecord(raw.agentModels)) {
199
193
  for (const [rawKey, value] of Object.entries(raw.agentModels)) {
200
194
  const key = rawKey.trim();
201
- if (key !== "" && isModelReference(value)) {
195
+ if (key !== "" && !RETIRED_AGENT_NAMES.has(key) && isModelReference(value)) {
202
196
  config.agentModels[key] = value.trim();
203
197
  }
204
198
  }
@@ -209,6 +203,7 @@ export function normalizeConfig(raw: unknown): SubagentsConfig {
209
203
  const key = rawKey.trim();
210
204
  if (
211
205
  key !== "" &&
206
+ !RETIRED_AGENT_NAMES.has(key) &&
212
207
  typeof value === "string" &&
213
208
  (THINKING_LEVEL_VALUES as readonly string[]).includes(value)
214
209
  ) {