specrails-desktop 2.59.3 → 2.60.0

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 (132) hide show
  1. package/client/dist/assets/{ActivityFeedPage-BGEayjTY.js → ActivityFeedPage-3J7fR8yB.js} +1 -1
  2. package/client/dist/assets/{AgentBrowserCapture-Qvg4y5Tr.js → AgentBrowserCapture-D4a3wYM1.js} +1 -1
  3. package/client/dist/assets/{AgentModeAnalyticsPane-CR7aFeLJ.js → AgentModeAnalyticsPane-Dps30tk9.js} +2 -2
  4. package/client/dist/assets/{AgentModeCodePane-gAd88Gng.js → AgentModeCodePane-CvLimey8.js} +2 -2
  5. package/client/dist/assets/{AgentModeJobsPane-EjCDuTow.js → AgentModeJobsPane-25tQlLpF.js} +1 -1
  6. package/client/dist/assets/{AgentsPage-CRHHcp1V.js → AgentsPage-CUDp_sfw.js} +2 -2
  7. package/client/dist/assets/{AnalyticsPage-a0b1fNEl.js → AnalyticsPage-DXWMGn8b.js} +1 -1
  8. package/client/dist/assets/{CodePage-BmV1m7l3.js → CodePage-D981zRHy.js} +1 -1
  9. package/client/dist/assets/{DesktopAnalyticsPage-B87WmXOQ.js → DesktopAnalyticsPage-BkFBq0E6.js} +1 -1
  10. package/client/dist/assets/{DocsDialog-Co0O672q.js → DocsDialog-BL7uSbIJ.js} +1 -1
  11. package/client/dist/assets/{DocsPage-DxGI6A2T.js → DocsPage-CsDLbmZX.js} +1 -1
  12. package/client/dist/assets/{ExportDropdown-1Ce031vB.js → ExportDropdown-B4Olg1Fk.js} +1 -1
  13. package/client/dist/assets/{InteractiveJobComposer-DkqR77pO.js → InteractiveJobComposer-Z6fl4791.js} +1 -1
  14. package/client/dist/assets/{JobDetailModal-DVLDVgzz.js → JobDetailModal-DS_Owxs6.js} +1 -1
  15. package/client/dist/assets/{JobDetailPage-RcP9N-D-.js → JobDetailPage-1TUQ9vlE.js} +1 -1
  16. package/client/dist/assets/{JobsPage-R9M4xQnp.js → JobsPage-BSrl8P7u.js} +1 -1
  17. package/client/dist/assets/LoopBuilderPage-Dh5uk2Qy.js +1 -0
  18. package/client/dist/assets/{LoopPreviewModal-DA2JeKWX.js → LoopPreviewModal-CH1r-KhU.js} +1 -1
  19. package/client/dist/assets/{LoopWindowSurface-BkkeD0hx.js → LoopWindowSurface-CiZdI6aw.js} +1 -1
  20. package/client/dist/assets/{LoopsPage-BHv--iI7.js → LoopsPage-BwFujdGi.js} +1 -1
  21. package/client/dist/assets/{MinimizedChatsContext-Bc9xHByW.js → MinimizedChatsContext-BD2bsRBe.js} +1 -1
  22. package/client/dist/assets/{PluginsPage-BEy62gxK.js → PluginsPage-B8f49Mvn.js} +1 -1
  23. package/client/dist/assets/{ProjectSettingsDialog-DDQ_f94T.js → ProjectSettingsDialog-D7q-O6h3.js} +1 -1
  24. package/client/dist/assets/{RepositoryDeliveries-DIWDFLRM.js → RepositoryDeliveries-NNorcGzT.js} +1 -1
  25. package/client/dist/assets/{RepositoryScopeSelector-D3PlHIM-.js → RepositoryScopeSelector-D-jb4bI_.js} +1 -1
  26. package/client/dist/assets/{ReviewPacketPage-BXdPwmdE.js → ReviewPacketPage-DpZSzF-Q.js} +1 -1
  27. package/client/dist/assets/{TemplatePreviewModal-C7-G6lvI.js → TemplatePreviewModal-5CZdAZ0G.js} +1 -1
  28. package/client/dist/assets/{TicketDetailModalContext-gGUv7gsQ.js → TicketDetailModalContext-BHmtj1As.js} +1 -1
  29. package/client/dist/assets/{Trans-Br_OIUKP.js → Trans-wmTUDVyC.js} +1 -1
  30. package/client/dist/assets/{agentRuntime-TXPQowKJ.js → agentRuntime-7Ydcvr6P.js} +1 -1
  31. package/client/dist/assets/{agentRuntime-Bpx3yWHK.js → agentRuntime-BHVw9orA.js} +1 -1
  32. package/client/dist/assets/{agentRuntime-15Pkk6we.js → agentRuntime-DCPDaQcV.js} +1 -1
  33. package/client/dist/assets/{agentRuntime-C78n13To.js → agentRuntime-DKTw4Ajg.js} +1 -1
  34. package/client/dist/assets/{agentRuntime-CCI7XF4c.js → agentRuntime-DVhij_i_.js} +1 -1
  35. package/client/dist/assets/{agentRuntime-Ddqvp2bP.js → agentRuntime-Doss-T8o.js} +1 -1
  36. package/client/dist/assets/{agentRuntime-CKDHe2-a.js → agentRuntime-eZSMUlkM.js} +1 -1
  37. package/client/dist/assets/{agentRuntime-hqZRy08E.js → agentRuntime-qSSU7fQk.js} +1 -1
  38. package/client/dist/assets/agents-B6ZsnARo.js +1 -0
  39. package/client/dist/assets/agents-BORdhe0K.js +1 -0
  40. package/client/dist/assets/agents-C6aq9Oqs.js +1 -0
  41. package/client/dist/assets/agents-Cbsc4bcX.js +1 -0
  42. package/client/dist/assets/agents-D0uYR6hq.js +1 -0
  43. package/client/dist/assets/agents-Doe1sHY5.js +1 -0
  44. package/client/dist/assets/agents-DyNi_I9m.js +1 -0
  45. package/client/dist/assets/agents-StKxiTg0.js +1 -0
  46. package/client/dist/assets/agentstudio-7cYCXn-L.js +1 -0
  47. package/client/dist/assets/{agentstudio-QdAJIDef.js → agentstudio-BHWQh8G3.js} +1 -1
  48. package/client/dist/assets/agentstudio-BjnWHyRs.js +1 -0
  49. package/client/dist/assets/{agentstudio-fLXpRGIi.js → agentstudio-BkV8vcK4.js} +1 -1
  50. package/client/dist/assets/{agentstudio-BWAKeGgB.js → agentstudio-BzugqB_N.js} +1 -1
  51. package/client/dist/assets/{agentstudio-Cja8Sjcp.js → agentstudio-CWbp7KvH.js} +1 -1
  52. package/client/dist/assets/agentstudio-DG6plf5o.js +1 -0
  53. package/client/dist/assets/agentstudio-DkZVF-Cc.js +1 -0
  54. package/client/dist/assets/{formatDistanceToNow-Q7QPRFV4.js → formatDistanceToNow-Dax4zqPF.js} +1 -1
  55. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-Bq0CXBaJ.js → getTimezoneOffsetInMilliseconds-dpIo42JZ.js} +1 -1
  56. package/client/dist/assets/{index-DVkWHOR3.js → index-g8S62tpS.js} +7 -7
  57. package/client/dist/assets/{jira-api-C2Tzc362.js → jira-api-CLrIvXFm.js} +1 -1
  58. package/client/dist/assets/{project-repositories-DZKmieH3.js → project-repositories-BkyT8AjU.js} +1 -1
  59. package/client/dist/assets/{spending-EXaboRU0.js → spending-Oov7p52A.js} +1 -1
  60. package/client/dist/assets/{useDesktop-ChSmmJfc.js → useDesktop-DpiS8Uov.js} +1 -1
  61. package/client/dist/assets/{useRuntimeRuns-w9-5OzZl.js → useRuntimeRuns-DBm1mul0.js} +1 -1
  62. package/client/dist/assets/{useSharedWebSocket-g0nTHfTT.js → useSharedWebSocket-BZxKaVNT.js} +2 -2
  63. package/client/dist/index.html +17 -17
  64. package/docs/getting-started.md +2 -2
  65. package/docs/guide/de/agents/1-meet-the-agents.md +1 -1
  66. package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +1 -1
  67. package/docs/guide/de/agents/3-customizing-models-per-agent.md +1 -1
  68. package/docs/guide/de/agents/4-custom-agents-catalog.md +3 -3
  69. package/docs/guide/en/agents/1-meet-the-agents.md +1 -1
  70. package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +1 -1
  71. package/docs/guide/en/agents/3-customizing-models-per-agent.md +1 -1
  72. package/docs/guide/en/agents/4-custom-agents-catalog.md +3 -3
  73. package/docs/guide/es/agents/1-meet-the-agents.md +1 -1
  74. package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +1 -1
  75. package/docs/guide/es/agents/3-customizing-models-per-agent.md +1 -1
  76. package/docs/guide/es/agents/4-custom-agents-catalog.md +3 -3
  77. package/docs/guide/fr/agents/1-meet-the-agents.md +1 -1
  78. package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +1 -1
  79. package/docs/guide/fr/agents/3-customizing-models-per-agent.md +1 -1
  80. package/docs/guide/fr/agents/4-custom-agents-catalog.md +3 -3
  81. package/docs/guide/it/agents/1-meet-the-agents.md +1 -1
  82. package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +1 -1
  83. package/docs/guide/it/agents/3-customizing-models-per-agent.md +1 -1
  84. package/docs/guide/it/agents/4-custom-agents-catalog.md +3 -3
  85. package/docs/guide/ja/agents/1-meet-the-agents.md +1 -1
  86. package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +1 -1
  87. package/docs/guide/ja/agents/3-customizing-models-per-agent.md +1 -1
  88. package/docs/guide/ja/agents/4-custom-agents-catalog.md +3 -3
  89. package/docs/guide/pt/agents/1-meet-the-agents.md +1 -1
  90. package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +1 -1
  91. package/docs/guide/pt/agents/3-customizing-models-per-agent.md +1 -1
  92. package/docs/guide/pt/agents/4-custom-agents-catalog.md +3 -3
  93. package/docs/guide/zh/agents/1-meet-the-agents.md +1 -1
  94. package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +1 -1
  95. package/docs/guide/zh/agents/3-customizing-models-per-agent.md +1 -1
  96. package/docs/guide/zh/agents/4-custom-agents-catalog.md +3 -3
  97. package/docs/internals/adding-a-provider.md +7 -6
  98. package/docs/internals/core-runtime-updates.md +19 -0
  99. package/docs/internals/profiles.md +17 -10
  100. package/docs/internals/review-packet.md +1 -1
  101. package/docs/internals/source-map.md +1 -1
  102. package/docs/running-pipelines.md +2 -2
  103. package/package.json +1 -1
  104. package/server/dist/core-compat.js +7 -3
  105. package/server/dist/mcp/guide.js +4 -3
  106. package/server/dist/modules/agent-runtime/runtime/agent-runtime-bridge.js +7 -3
  107. package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings.js +24 -1
  108. package/server/dist/modules/agents/runtime/profiles-router.js +74 -36
  109. package/server/dist/modules/execution/runtime/queue-manager.js +7 -9
  110. package/server/dist/modules/loops/runtime/loop-agents.js +2 -5
  111. package/server/dist/modules/loops/runtime/loop-command-catalog.js +5 -5
  112. package/server/dist/modules/loops/runtime/loop-definition.js +1 -1
  113. package/server/dist/modules/loops/runtime/loop-executors.js +0 -2
  114. package/server/dist/modules/loops/runtime/loop-implement-recipe.js +5 -4
  115. package/server/dist/modules/loops/runtime/loops-router.js +3 -1
  116. package/server/dist/providers/gemini-agent-ack.js +13 -10
  117. package/server/dist/setup-manager.js +28 -43
  118. package/server/dist/workspace-manager.js +13 -71
  119. package/client/dist/assets/LoopBuilderPage-C4S-rkWp.js +0 -1
  120. package/client/dist/assets/agents-CA5eT1d0.js +0 -1
  121. package/client/dist/assets/agents-CAgy-5uS.js +0 -1
  122. package/client/dist/assets/agents-CNm6Qzlv.js +0 -1
  123. package/client/dist/assets/agents-CTwbx-fb.js +0 -1
  124. package/client/dist/assets/agents-DEGV1Vao.js +0 -1
  125. package/client/dist/assets/agents-HsDF1aQU.js +0 -1
  126. package/client/dist/assets/agents-IQjdA-z9.js +0 -1
  127. package/client/dist/assets/agents-RkGoteXh.js +0 -1
  128. package/client/dist/assets/agentstudio-B2CTtQgZ.js +0 -1
  129. package/client/dist/assets/agentstudio-DtfPcr99.js +0 -1
  130. package/client/dist/assets/agentstudio-X70BKf6u.js +0 -1
  131. package/client/dist/assets/agentstudio-qXKqVnWS.js +0 -1
  132. package/server/dist/modules/loops/runtime/loop-agent-defaults.json +0 -6
@@ -68,6 +68,25 @@ all workspace refreshes and the final recovery-state write succeed.
68
68
  Core 6 registry updates and same-version runtime repairs are offered using the
69
69
  same supported-major policy as runtime selection.
70
70
 
71
+ ## Role definitions follow the engine
72
+
73
+ Core owns how the implement roles think: `rolePromptDefaults()` returns the
74
+ factory architect, developer, reviewer and fixer definitions (one shared senior
75
+ engineer identity, blast-radius discipline, quality bar and the mandatory
76
+ OpenSpec binding). Desktop owns the workflows that use those roles, and never
77
+ keeps a copy of those definitions.
78
+
79
+ - The Implement rail (engine 1) reads the defaults from the selected Core at
80
+ launch, merged with the user's global overrides from Settings.
81
+ - Loop recipes store `inherit` for the built-in definitions (and
82
+ `inherit:<role>` for declared recipe roles such as `plan`/`build`). The
83
+ launch bridge resolves them to the same Core defaults plus global overrides
84
+ and freezes the result with the run, so every loop follows the installed
85
+ Core automatically. Text the user edits in the loop editor is stored verbatim
86
+ and stays frozen with the loop; "Use the Core definition" returns a role to
87
+ `inherit`. `/api/loop-agent-defaults` returns `rolePromptDefaults` so the
88
+ editor can preview what `inherit` resolves to today.
89
+
71
90
  ## Version reporting
72
91
 
73
92
  Global status distinguishes the selected runtime and its source, the active
@@ -21,20 +21,22 @@ Dashboard/Jobs/Analytics/Settings).
21
21
  - **Profiles** tab — create and edit profiles.
22
22
  - **Usage** tab — see which profiles are actually being used (backed by
23
23
  the `/analytics` endpoint covered in section 8).
24
- - **Catalog** tab — read the upstream `sr-*` agents or author custom
25
- `custom-*` ones via the Studio.
24
+ - **Catalog** tab — read the runtime-defined baseline roles (`sr-architect`,
25
+ `sr-developer`, `sr-reviewer`, shown read-only with the definition the Core
26
+ runtime executes) or author custom `custom-*` ones via the Studio.
26
27
 
27
28
  When the project has no profiles yet, the empty state offers two entry
28
29
  points:
29
30
 
30
- - **Migrate from current agents** — reads the primary provider's native role
31
- catalog (`.claude/agents/` or `.kimi-code/skills/`) and creates a
32
- `default` profile mirroring today's behavior. It requires the baseline trio
33
- `sr-architect`, `sr-developer`, and `sr-reviewer` to be present — the
34
- server rejects the migration if any is missing. Provider-specific model
35
- identifiers are retained only when they are in that provider's catalog;
36
- otherwise migration uses its default and stamps the provider into the saved
37
- profile.
31
+ - **Migrate from current agents** — seeds the baseline trio `sr-architect`,
32
+ `sr-developer` and `sr-reviewer` as role identifiers with the provider's
33
+ default model, reads the primary provider's native role catalog
34
+ (`.claude/agents/` or `.kimi-code/skills/`) for custom roles and creates a
35
+ `default` profile mirroring today's behavior. No `sr-*` file has to exist:
36
+ a `model:` is read only from role files an older install still carries.
37
+ Provider-specific model identifiers are retained only when they are in that
38
+ provider's catalog; otherwise migration uses its default and stamps the
39
+ provider into the saved profile.
38
40
  - **Blank profile** — start from scratch.
39
41
 
40
42
  ## 2. Saved profiles vs selection
@@ -128,6 +130,11 @@ template/duplicate/edit and rail execution remain available.
128
130
  `sr-developer`. Fix the listed issues and Save re-enables.
129
131
  - **"agent 'xyz' already exists" (409)** — the name collides with an
130
132
  existing provider role. Pick a different name.
133
+ - **No `.claude/agents/sr-*.md` in the project** — expected. The baseline
134
+ roles are defined by the Core runtime, not installed as files; read them in
135
+ the Catalog tab and edit their definitions, provider and model in
136
+ **Settings → Agent runtime**. Files left behind by an older Core are
137
+ tolerated until Core prunes them.
131
138
  - **The whole Agents section is missing** — it can be disabled server-side
132
139
  with `SPECRAILS_AGENTS_SECTION=false`, which 404s the entire
133
140
  `/profiles` router. Unset it (or leave it at its default) to restore the
@@ -140,7 +140,7 @@ one-active-generation-per-rail all come free from the shipped machinery.
140
140
 
141
141
  **The loop.** `factory:revision` is the fourth factory loop: `{{cmd:revise}}` (a
142
142
  distilled step that applies the one requested change on top of the branch and
143
- then runs `sr-reviewer` over the resulting diff, so packet v2 keeps its reviewer
143
+ then runs the reviewer role (`sr-reviewer`) over the resulting diff, so packet v2 keeps its reviewer
144
144
  tier) followed by the standard `{{cmd:verify}}`. No Architect step — the plan and
145
145
  the code already exist. It is resolvable by id but deliberately NOT listed in the
146
146
  public catalog: its prompt consumes `{{const:REVISION_REQUEST}}`, which only a
@@ -79,7 +79,7 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
79
79
 
80
80
  - [AgentRoleFields.tsx](../../client/src/features/agents/components/AgentRoleFields.tsx) · [test](../../client/src/features/agents/components/__tests__/AgentRoleFields.test.tsx)
81
81
  - [AgentStudio.tsx](../../client/src/features/agents/components/AgentStudio.tsx)
82
- - [AgentsCatalogTab.tsx](../../client/src/features/agents/components/AgentsCatalogTab.tsx)
82
+ - [AgentsCatalogTab.tsx](../../client/src/features/agents/components/AgentsCatalogTab.tsx) · [test](../../client/src/features/agents/components/__tests__/AgentsCatalogTab.test.tsx)
83
83
  - [AiRefineOverlay.tsx](../../client/src/features/agents/components/AiRefineOverlay.tsx)
84
84
  - [ProfileAnalyticsCard.tsx](../../client/src/features/agents/components/ProfileAnalyticsCard.tsx)
85
85
  - [ProfileEditor.tsx](../../client/src/features/agents/components/ProfileEditor.tsx) · [test](../../client/src/features/agents/components/__tests__/ProfileEditor.test.tsx)
@@ -173,9 +173,9 @@ Without profiles, every rail uses the project's frontmatter-baked models. With p
173
173
  Open **Agents** in the project's right sidebar. Two sub-tabs:
174
174
 
175
175
  - **Profiles** — full CRUD over `.specrails/profiles/*.json`. The live validator enforces the baseline trio and routing ordering — Save is disabled with an "N issues to resolve" hint while the profile is broken.
176
- - **Agents Catalog** — read-only viewer of upstream `sr-*` agents and your `custom-*` agents.
176
+ - **Agents Catalog** — read-only viewer of the runtime-defined baseline roles (`sr-architect`, `sr-developer`, `sr-reviewer`, shown with the definition the Core runtime actually executes) and your `custom-*` agents.
177
177
 
178
- The empty state offers **Migrate from current agents**: one click creates a `default` profile mirroring today's frontmatter.
178
+ The empty state offers **Migrate from current agents**: one click creates a `default` profile from the baseline roles and your existing custom agents — no role file has to exist for it to work.
179
179
 
180
180
  Each profile gets a per-profile analytics card showing usage for the last 7 / 30 / 90 days: jobs, success rate, avg tokens, avg duration.
181
181
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specrails-desktop",
3
- "version": "2.59.3",
3
+ "version": "2.60.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,8 +19,8 @@ const bundled_core_1 = require("./bundled-core");
19
19
  const core_runtime_1 = require("./core-runtime");
20
20
  // Windows has no `which`; probe PATH via `where` instead.
21
21
  const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
22
- /** Paired development target; older supported contracts remain compatible. */
23
- exports.EXPECTED_CORE_CONTRACT_SCHEMA_VERSION = '5.1';
22
+ /** Paired development target; older supported contracts (5.1) remain compatible. */
23
+ exports.EXPECTED_CORE_CONTRACT_SCHEMA_VERSION = '5.2';
24
24
  // These must mirror KNOWN_VERBS in cli/specrails-desktop.ts
25
25
  const DESKTOP_KNOWN_COMMANDS = new Set([
26
26
  'implement',
@@ -29,6 +29,10 @@ const DESKTOP_KNOWN_COMMANDS = new Set([
29
29
  // Commands older Cores still ship that Desktop no longer invokes. They are
30
30
  // tolerated (not drift) but never required: Batch was folded into implement.
31
31
  const DESKTOP_TOLERATED_LEGACY_COMMANDS = new Set(['batch-implement']);
32
+ // Checkpoints that contract 5.1 still declares but Desktop retired: role agents
33
+ // are runtime-defined since contract 5.2, so `agent_generation` is tolerated
34
+ // (not drift) and never required.
35
+ const DESKTOP_TOLERATED_LEGACY_CHECKPOINTS = new Set(['agent_generation']);
32
36
  function isRecord(value) {
33
37
  return typeof value === 'object' && value !== null && !Array.isArray(value);
34
38
  }
@@ -233,7 +237,7 @@ async function checkCoreCompat() {
233
237
  : (contract.checkpoints && typeof contract.checkpoints === 'object'
234
238
  ? Object.keys(contract.checkpoints)
235
239
  : []);
236
- const missingCheckpoints = contractCheckpoints.filter((c) => !desktopCheckpointKeys.includes(c));
240
+ const missingCheckpoints = contractCheckpoints.filter((c) => !desktopCheckpointKeys.includes(c) && !DESKTOP_TOLERATED_LEGACY_CHECKPOINTS.has(c));
237
241
  const deterministic = contract.lifecycle?.mode === 'deterministic' && contract.lifecycle.requiresEnrich === false;
238
242
  // Supporting legacy installation checkpoints is compatible with Core 5;
239
243
  // demanding them from a deterministic installer would recreate enrich.
@@ -385,9 +385,10 @@ can run Contract Refine require AI-spawn, including Explore conversions.
385
385
  - **Plugins** (\`specrails_plugins\`): per-project MCP integrations; \`preview\`
386
386
  the diff before \`install\`; a degraded plugin never blocks rail launches.
387
387
  - **Profiles** (\`specrails_agents\`): per-project agent chains; the baseline
388
- trio \`sr-architect\`/\`sr-developer\`/\`sr-reviewer\` is required; routing rules
389
- end in a single terminal \`default: true\` rule; requires specrails-core
390
- 4.1.0 or newer.
388
+ trio \`sr-architect\`/\`sr-developer\`/\`sr-reviewer\` are role identifiers
389
+ defined by the specrails-core runtime (no installed files) and are required
390
+ in every chain; routing rules end in a single terminal \`default: true\` rule;
391
+ requires specrails-core 4.1.0 or newer.
391
392
  - **Setup** (\`specrails_setup\`): \`prerequisites\` → \`add_project\` →
392
393
  \`install_config\` per provider → ONE \`install\` (provisions all chosen
393
394
  providers; quick-only, offline) → poll \`checkpoints\` until
@@ -148,14 +148,18 @@ async function runAgentRuntimeInvocation(options) {
148
148
  if (!Array.isArray(admittedContext.repositories) || !admittedContext.repositories.length || admittedContext.repositories.some(repo => !repo || typeof repo.id !== 'string' || !repo.id))
149
149
  throw new Error('Core context is missing its repository scope');
150
150
  const source = (0, node_fs_1.existsSync)(options.configPath) ? 'project-role' : 'default';
151
- const { config, origins } = (0, agent_runtime_effective_config_1.resolveEffectiveRuntimeConfig)(options.loopConfig ? (0, agent_runtime_settings_1.loadLoopRuntimeConfig)(options.configPath, options.loopConfig, options.providerOverride ?? { provider: options.defaultProvider ?? 'claude' }) : (0, agent_runtime_settings_1.loadRuntimeConfigFile)(options.configPath, options.defaultProvider), {
151
+ // The engine owns the factory role definitions; the user's global overrides sit on top. The Implement
152
+ // rail merges them under any project text, and loop recipes resolve their `inherit` definitions here.
153
+ const effectiveRolePrompts = { ...(await (0, agent_runtime_loader_1.loadCoreAgentRuntime)()).rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)() };
154
+ const loopConfig = options.loopConfig && (0, agent_runtime_settings_1.resolveInheritedRolePrompts)(options.loopConfig, effectiveRolePrompts);
155
+ const { config, origins } = (0, agent_runtime_effective_config_1.resolveEffectiveRuntimeConfig)(loopConfig ? (0, agent_runtime_settings_1.loadLoopRuntimeConfig)(options.configPath, loopConfig, options.providerOverride ?? { provider: options.defaultProvider ?? 'claude' }) : (0, agent_runtime_settings_1.loadRuntimeConfigFile)(options.configPath, options.defaultProvider), {
152
156
  repositoryIds: admittedContext.repositories.map(repo => repo.id), source: options.loopConfig ? 'loop-role' : source, providerOverride: options.loopConfig ? undefined : options.providerOverride,
153
157
  });
154
158
  config.verification = scopedHostChecks(config.verification, admittedContext.repositories);
155
159
  if (definitionEngine)
156
160
  completeHostChecks(config, admittedContext.repositories);
157
- if (!options.loopConfig)
158
- config.rolePrompts = { ...(await (0, agent_runtime_loader_1.loadCoreAgentRuntime)()).rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)(), ...config.rolePrompts };
161
+ if (!loopConfig)
162
+ config.rolePrompts = { ...effectiveRolePrompts, ...config.rolePrompts };
159
163
  // Core rejects unknown connection keys: drop the desktop-only local-engine
160
164
  // fields (label/defaultModel/rates/supportsReasoningEffort) before Core sees it.
161
165
  const runtime = await (0, agent_runtime_loader_1.loadCoreAgentRuntime)();
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AgentRuntimeConfigError = exports.REVIEW_THRESHOLD_FLOORS = exports.MAX_OUTPUT_TOKENS_MAX = exports.MAX_OUTPUT_TOKENS_MIN = exports.CONTEXT_WINDOW_TOKENS_MAX = exports.CONTEXT_WINDOW_TOKENS_MIN = exports.RUNTIME_ROLE_ID = void 0;
6
+ exports.INHERIT_ROLE_PROMPT = exports.AgentRuntimeConfigError = exports.REVIEW_THRESHOLD_FLOORS = exports.MAX_OUTPUT_TOKENS_MAX = exports.MAX_OUTPUT_TOKENS_MIN = exports.CONTEXT_WINDOW_TOKENS_MAX = exports.CONTEXT_WINDOW_TOKENS_MIN = exports.RUNTIME_ROLE_ID = void 0;
7
7
  exports.stripDesktopConnectionFields = stripDesktopConnectionFields;
8
8
  exports.coreConnectionFieldGates = coreConnectionFieldGates;
9
9
  exports.validateLoopRuntimeSettings = validateLoopRuntimeSettings;
@@ -18,6 +18,8 @@ exports.saveRuntimeProviders = saveRuntimeProviders;
18
18
  exports.loadRuntimeConfigFile = loadRuntimeConfigFile;
19
19
  exports.loadAgentRuntimeConfig = loadAgentRuntimeConfig;
20
20
  exports.saveAgentRuntimeConfig = saveAgentRuntimeConfig;
21
+ exports.inheritedRolePrompt = inheritedRolePrompt;
22
+ exports.resolveInheritedRolePrompts = resolveInheritedRolePrompts;
21
23
  exports.validateRuntimeRolePrompts = validateRuntimeRolePrompts;
22
24
  exports.loadRuntimeRolePrompts = loadRuntimeRolePrompts;
23
25
  exports.saveRuntimeRolePrompts = saveRuntimeRolePrompts;
@@ -419,6 +421,27 @@ function saveAgentRuntimeConfig(project, input) {
419
421
  return config;
420
422
  }
421
423
  const PROMPT_ROLES = [...ROLES, 'fixer'];
424
+ /** A loop recipe definition that follows the engine: resolved at launch to the selected Core's factory definition plus the user's global override. */
425
+ exports.INHERIT_ROLE_PROMPT = 'inherit';
426
+ const INHERITED_ROLE_PROMPT = /^inherit:(architect|developer|reviewer|fixer)$/;
427
+ /** The prompt a declared recipe role carries when it follows a built-in definition (`inherit:<role>`), or the recipe's own text. */
428
+ function inheritedRolePrompt(prompts, role) {
429
+ const value = prompts?.[role];
430
+ return value === undefined || value === exports.INHERIT_ROLE_PROMPT ? `${exports.INHERIT_ROLE_PROMPT}:${role}` : value;
431
+ }
432
+ /** Replace `inherit` definitions (built-in roles) and `inherit:<role>` prompts (declared roles) with the effective engine definitions. Explicit recipe text is kept verbatim. */
433
+ function resolveInheritedRolePrompts(settings, effective) {
434
+ // A Core predating the fixer stance has no fixer default: the fixer then follows the developer definition.
435
+ const resolved = { ...effective, fixer: effective.fixer ?? effective.developer };
436
+ const lookup = (role) => resolved[role];
437
+ const rolePrompts = settings.rolePrompts && Object.fromEntries(Object.entries(settings.rolePrompts).map(([role, text]) => [role, text === exports.INHERIT_ROLE_PROMPT ? lookup(role) ?? text : text]));
438
+ const roles = settings.roles && Object.fromEntries(Object.entries(settings.roles).map(([id, role]) => {
439
+ const inherited = role.prompt?.match(INHERITED_ROLE_PROMPT);
440
+ const text = inherited ? lookup(inherited[1]) : undefined;
441
+ return [id, text ? { ...role, prompt: text } : role];
442
+ }));
443
+ return { ...settings, ...(rolePrompts ? { rolePrompts } : {}), ...(roles ? { roles } : {}) };
444
+ }
422
445
  function validateRuntimeRolePrompts(input, extraRoles = []) {
423
446
  if (!input || typeof input !== 'object' || Array.isArray(input))
424
447
  throw new AgentRuntimeConfigError('Role prompts must be an object');
@@ -18,6 +18,8 @@ const providers_1 = require("../../../providers");
18
18
  const kimi_skill_prompt_1 = require("../../../providers/kimi-skill-prompt");
19
19
  const profile_manager_1 = require("./profile-manager");
20
20
  const workspace_resolution_1 = require("../../../workspace-resolution");
21
+ const agent_runtime_loader_1 = require("../../agent-runtime/runtime/agent-runtime-loader");
22
+ const agent_runtime_settings_1 = require("../../agent-runtime/runtime/agent-runtime-settings");
21
23
  const project_router_helpers_1 = require("../../../project-router-helpers");
22
24
  /**
23
25
  * Relocate-artifacts gate: the dir whose `.specrails/{profiles,specrails-version}`
@@ -70,6 +72,30 @@ function agentsCatalogDir(project, provider) {
70
72
  function listAgentFiles(project, provider) {
71
73
  return (0, agent_catalog_1.listNativeAgentFiles)(specRoot(project), provider ?? project.provider ?? 'claude');
72
74
  }
75
+ /**
76
+ * The baseline roles are identifiers of runtime-defined roles: specrails-core
77
+ * never reads an `sr-*` file for them. Their read-only catalog body is the Core
78
+ * runtime definition (defaults merged with the global Settings overrides).
79
+ */
80
+ const BASELINE_RUNTIME_ROLES = {
81
+ 'sr-architect': 'architect',
82
+ 'sr-developer': 'developer',
83
+ 'sr-reviewer': 'reviewer',
84
+ };
85
+ const RUNTIME_DEFINED_DESCRIPTION = 'Runtime-defined by specrails-core: the implement pipeline runs this role from the Core runtime definition below, not from an installed file.';
86
+ async function loadRuntimeRoleDefinitions() {
87
+ try {
88
+ const runtime = await (0, agent_runtime_loader_1.loadCoreAgentRuntime)();
89
+ return { prompts: { ...runtime.rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)() } };
90
+ }
91
+ catch (error) {
92
+ return { prompts: {}, error: error instanceof Error ? error.message : 'Core role prompt catalog is unavailable' };
93
+ }
94
+ }
95
+ function runtimeRoleBody(definitions, agentId) {
96
+ const role = BASELINE_RUNTIME_ROLES[agentId];
97
+ return role ? definitions.prompts[role] : undefined;
98
+ }
73
99
  const AGENTS_SECTION_ENABLED = process.env.SPECRAILS_AGENTS_SECTION !== 'false';
74
100
  function handleError(res, err) {
75
101
  if (err instanceof profile_manager_1.ProfileValidationError) {
@@ -175,12 +201,11 @@ function createProfilesRouter() {
175
201
  ? new Map((0, project_router_helpers_1.readAgentModels)({ ...project, provider })
176
202
  .map((entry) => [entry.name, entry.model]))
177
203
  : null;
178
- const agentsDir = agentsCatalogDir(project, provider);
179
- if (!fs_1.default.existsSync(agentsDir)) {
180
- res.status(400).json({ error: `no ${adapter.projectDirName} roles catalog found` });
181
- return;
182
- }
204
+ const baseline = [...adapter.baselineAgents()];
183
205
  const agents = [];
206
+ // Role files are optional: Core >= 6.3 defines the baseline roles in its
207
+ // runtime. Read `model:` only from `sr-*` files that still exist (older
208
+ // installs); every other baseline id is seeded with the adapter default.
184
209
  for (const entry of listAgentFiles(project, provider)) {
185
210
  if (!entry.id.startsWith('sr-'))
186
211
  continue;
@@ -202,13 +227,10 @@ function createProfilesRouter() {
202
227
  }
203
228
  agents.push({ id, model });
204
229
  }
205
- const baseline = [...adapter.baselineAgents()];
206
- const missing = baseline.filter((id) => !agents.some((a) => a.id === id));
207
- if (missing.length > 0) {
208
- res.status(400).json({
209
- error: `missing baseline agents in this project: ${missing.join(', ')}. Run 'npx specrails-core@latest update' first.`,
210
- });
211
- return;
230
+ for (const id of baseline) {
231
+ if (agents.some((a) => a.id === id))
232
+ continue;
233
+ agents.push({ id, model: projectedKimiModels?.get(id) ?? adapter.defaultModel() });
212
234
  }
213
235
  // Order: baseline trio first (architect, developer, reviewer), optional
214
236
  // agents in the middle. sr-merge-resolver is no longer a baseline agent;
@@ -379,39 +401,44 @@ function createProfilesRouter() {
379
401
  }
380
402
  });
381
403
  // GET /api/projects/:projectId/profiles/catalog
382
- // List all roles in the selected provider-native catalog (sr-* + custom-*).
383
- router.get('/catalog', (req, res) => {
404
+ // List the selected provider's roles: the runtime-defined baseline (upstream,
405
+ // synthesized from the adapter) plus the native `custom-*` catalog.
406
+ router.get('/catalog', async (req, res) => {
384
407
  try {
385
408
  const { project } = ctx(req);
386
409
  const provider = requestedProvider(req, project);
387
- const files = listAgentFiles(project, provider);
388
- if (files.length === 0) {
389
- res.json({ agents: [] });
390
- return;
391
- }
410
+ const adapter = projectAdapter(project, provider);
392
411
  const agents = [];
393
- for (const entry of files) {
412
+ // Baseline roles never depend on `sr-*` files; a missing roles directory
413
+ // still yields the three runtime-defined entries.
414
+ const definitions = await loadRuntimeRoleDefinitions();
415
+ for (const id of adapter.baselineAgents()) {
416
+ agents.push({
417
+ id,
418
+ kind: 'upstream',
419
+ description: RUNTIME_DEFINED_DESCRIPTION,
420
+ body: runtimeRoleBody(definitions, id) ?? '',
421
+ roleId: BASELINE_RUNTIME_ROLES[id],
422
+ ...(definitions.error ? { runtimeRoleError: definitions.error } : {}),
423
+ });
424
+ }
425
+ for (const entry of listAgentFiles(project, provider)) {
394
426
  const id = entry.id;
395
- const kind = id.startsWith('sr-')
396
- ? 'upstream'
397
- : id.startsWith('custom-')
398
- ? 'custom'
399
- : null;
400
- if (!kind)
427
+ // Stale `sr-*` files from older Cores are not catalog entries anymore.
428
+ if (!id.startsWith('custom-'))
401
429
  continue;
430
+ const kind = 'custom';
402
431
  let description;
403
432
  let model;
404
433
  let projected = {};
405
434
  try {
406
435
  const body = fs_1.default.readFileSync(entry.file, 'utf8');
407
- if (kind === 'custom') {
408
- try {
409
- const result = (0, agent_role_descriptor_1.projectCustomAgentRole)({ id, content: body }, { provider });
410
- projected = { roleId: result.id, runtimeRoleDefaults: result.role };
411
- }
412
- catch (error) {
413
- projected = { runtimeRoleError: error instanceof Error ? error.message : 'Invalid Core role descriptor' };
414
- }
436
+ try {
437
+ const result = (0, agent_role_descriptor_1.projectCustomAgentRole)({ id, content: body }, { provider });
438
+ projected = { roleId: result.id, runtimeRoleDefaults: result.role };
439
+ }
440
+ catch (error) {
441
+ projected = { runtimeRoleError: error instanceof Error ? error.message : 'Invalid Core role descriptor' };
415
442
  }
416
443
  if (provider === 'kimi') {
417
444
  // Use the same js-yaml metadata parser as validation/execution so
@@ -468,8 +495,9 @@ function createProfilesRouter() {
468
495
  }
469
496
  });
470
497
  // GET /api/projects/:projectId/profiles/catalog/:agentId
471
- // Return the full .md body of a single agent file (read-only for sr-*, editable for custom-*)
472
- router.get('/catalog/:agentId', (req, res) => {
498
+ // Return the full body of a single agent: the Core runtime definition for a
499
+ // baseline role (read-only), the native file for custom-* (editable).
500
+ router.get('/catalog/:agentId', async (req, res) => {
473
501
  try {
474
502
  const { project } = ctx(req);
475
503
  const provider = requestedProvider(req, project);
@@ -480,6 +508,16 @@ function createProfilesRouter() {
480
508
  }
481
509
  const file = agentFile(project, agentId, provider);
482
510
  if (!fs_1.default.existsSync(file)) {
511
+ if (projectAdapter(project, provider).baselineAgents().includes(agentId)) {
512
+ const definitions = await loadRuntimeRoleDefinitions();
513
+ const body = runtimeRoleBody(definitions, agentId);
514
+ if (body !== undefined) {
515
+ res.json({ id: agentId, body, runtimeDefined: true });
516
+ return;
517
+ }
518
+ res.status(503).json({ error: definitions.error ?? 'Core role prompt catalog is unavailable' });
519
+ return;
520
+ }
483
521
  res.status(404).json({ error: 'agent not found' });
484
522
  return;
485
523
  }
@@ -1935,17 +1935,15 @@ class QueueManager {
1935
1935
  const execution = this._resolveExecution();
1936
1936
  this._jobExecution.set(jobId, execution);
1937
1937
  const spawnCwd = execution.cwd;
1938
- // Windows repair: a relocated workspace whose `.claude/agents` was left empty
1939
- // by the broken `current`-junction read during assemble has no sr-* agents,
1940
- // so the implement pipeline can't delegate and runs inline. Self-heal here
1941
- // (per rail spawn) by copying the agents from the real version dir. NO-OP on
1942
- // POSIX (assemble's per-file symlinks already populate them).
1938
+ // Windows repair: a relocated workspace whose dir-linked subtrees
1939
+ // (commands/skills/rules) were left unreadable by the broken `current`
1940
+ // junction during assemble has no `/specrails:*` commands → the CLI reports
1941
+ // "Unknown command: /specrails:implement". Self-heal here (per rail spawn)
1942
+ // from the real version dir. Role agents (architect/developer/reviewer) are
1943
+ // defined by the Core runtime, not by workspace files, so nothing else is
1944
+ // repaired. NO-OP on POSIX (assemble's symlinks already populate them).
1943
1945
  if (execution.relocated) {
1944
1946
  try {
1945
- (0, workspace_manager_1.ensureFrameworkAgents)(execution.cwd, adapter.projectDirName);
1946
- // AND the dir-linked subtrees (commands/skills/rules): a broken Windows
1947
- // `current` junction leaves the workspace with no `/specrails:*` commands
1948
- // → the CLI reports "Unknown command: /specrails:implement".
1949
1947
  (0, workspace_manager_1.ensureFrameworkCommandSubtrees)(execution.cwd, adapter.projectDirName);
1950
1948
  }
1951
1949
  catch {
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.defaultLoopAgents = defaultLoopAgents;
7
- const loop_agent_defaults_json_1 = __importDefault(require("./loop-agent-defaults.json"));
4
+ const agent_runtime_settings_1 = require("../../agent-runtime/runtime/agent-runtime-settings");
8
5
  function defaultLoopAgents(mode = 'implementation') {
9
6
  return {
10
7
  schemaVersion: 1,
11
8
  agents: { architect: { provider: 'inherit' }, developer: { provider: 'inherit' }, reviewer: { provider: 'inherit' } },
12
9
  fixer: { provider: 'inherit' },
13
- rolePrompts: mode === 'implementation' ? { ...loop_agent_defaults_json_1.default } : {
10
+ rolePrompts: mode === 'implementation' ? { architect: agent_runtime_settings_1.INHERIT_ROLE_PROMPT, developer: agent_runtime_settings_1.INHERIT_ROLE_PROMPT, reviewer: agent_runtime_settings_1.INHERIT_ROLE_PROMPT, fixer: agent_runtime_settings_1.INHERIT_ROLE_PROMPT } : {
14
11
  architect: 'Explore the repositories and plan the requested work from the supplied goal and acceptance criteria.',
15
12
  developer: 'Implement the supplied spec directly in the existing codebase. Explore relevant code, make the requested changes and add meaningful tests. Use the project verification commands. If a human decision is required, finish with LOOP_BLOCKED: followed by the specific question.',
16
13
  reviewer: 'Review actual code and verification evidence against the supplied acceptance criteria. Report correctness, security and regression issues.',
@@ -116,10 +116,10 @@ exports.LOOP_COMMANDS = [
116
116
  {
117
117
  name: 'revision-verify',
118
118
  label: 'revision verify',
119
- description: 'Read-only independent Revision gate: run sr-reviewer, ensure one full-scope pass of record, write fresh confidence evidence when available, and emit VERIFICATION: PASS|FAIL.',
119
+ description: 'Read-only independent Revision gate: perform an independent senior review of the diff against the OpenSpec package, ensure one full-scope pass of record, write fresh confidence evidence when available, and emit VERIFICATION: PASS|FAIL.',
120
120
  ticketScope: 'all',
121
121
  // The Revision loop's SINGLE owner of review + verification. It exists because
122
- // running sr-reviewer inside `revise` and then a generic `{{cmd:verify}}` made
122
+ // running a review inside `revise` and then a generic `{{cmd:verify}}` made
123
123
  // two independent full gates for one one-sentence change — the exact cost the
124
124
  // Architect-less revision path was created to avoid. Kept read-only so a failed
125
125
  // gate routes to the loop's separate `fix` step instead of the grader patching
@@ -133,14 +133,14 @@ exports.LOOP_COMMANDS = [
133
133
  '',
134
134
  'Treat that briefing and the files on disk as the complete source context. Do not depend on the mutating agent remembering or summarizing it for you.',
135
135
  '',
136
- 'Reviewer output-format reconciliation: the installed `sr-reviewer` may require its review phase to finish with only `Score:` and `Verdict:` lines and then end. In this OUTER verification gate those two lines are an intermediate reviewer result, not the end of your turn. Preserve every reviewer rule except that terminal response-format instruction; after recording its score/verdict, continue with any missing project gates and emit the outer `VERIFICATION` sentinel required below.',
136
+ 'Reviewer output-format reconciliation: a senior review phase conventionally finishes with only `Score:` and `Verdict:` lines and then ends. In this OUTER verification gate those two lines are an intermediate reviewer result, not the end of your turn. Keep every review rule except that terminal response-format instruction; after recording the score/verdict, continue with any missing project gates and emit the outer `VERIFICATION` sentinel required below.',
137
137
  '',
138
138
  'Work in this order:',
139
- '1. Load and follow the installed `sr-reviewer` role over the resulting diff and the governing OpenSpec package (use its archived package when that is the delivery context; do not archive or re-archive anything). Produce a fresh `confidence-score.json` for this pass when the reviewer is applicable.',
139
+ '1. Perform an independent senior review of the resulting diff against the governing OpenSpec package: proposal, design, delta specs and tasks (use its archived package when that is the delivery context; do not archive or re-archive anything). Check correctness, scope discipline, test coverage and alignment with the spec, and record a `Score:` and `Verdict:`. Produce a fresh `confidence-score.json` for this pass when an OpenSpec package governs the candidate.',
140
140
  '2. Establish exactly ONE full-scope project gate for this candidate: the complete configured test suite plus typecheck, lint, and build when present. Inspect what the reviewer actually ran. If it already ran that full gate, treat those commands as the pass of record and DO NOT repeat them. If it ran only scoped/focused checks, run only the missing full-scope commands once.',
141
141
  '3. Independently map the user revision request and frozen spec to the real diff. A clean command exit alone is not enough when required behavior is missing or out-of-scope work was introduced.',
142
142
  '',
143
- 'If the reviewer is unavailable or inapplicable, run the full-scope project gate yourself exactly once, continue the semantic diff review, and report reviewer confidence as unavailable. Never infer PASS from missing reviewer evidence.',
143
+ 'If no OpenSpec package governs this candidate, review the diff against the frozen spec alone, run the full-scope project gate yourself exactly once, and report reviewer confidence as unavailable. Never infer PASS from missing review evidence.',
144
144
  '',
145
145
  'This gate is read-only: do NOT edit source, tests, configuration, or OpenSpec contract artifacts, and do NOT fix findings. The only permitted writes are reviewer/evidence artifacts. On any defect or failed/missing required gate, report FAIL so the loop routes to its separate fix step.',
146
146
  '',
@@ -75,7 +75,7 @@ function compileLoopToDefinition(graph, launch) {
75
75
  }
76
76
  }
77
77
  if (kind === 'prompt' && graph.config.agents) {
78
- const definition = graph.config.agents.rolePrompts?.[promptRole]?.replaceAll('{{', '{{{{');
78
+ const definition = agents?.rolePrompts?.[promptRole]?.replaceAll('{{', '{{{{');
79
79
  if (definition) {
80
80
  if (object(params.nativeCommand))
81
81
  params.nativeCommand = { ...params.nativeCommand, args: String(params.nativeCommand.args ?? '') + '\n\nLoop agent definition:\n' + definition };
@@ -347,7 +347,6 @@ function createLoopExecutors(opts = {}) {
347
347
  };
348
348
  if (repoDir) {
349
349
  try {
350
- (0, workspace_manager_1.ensureFrameworkAgents)(cwd, adapter.projectDirName);
351
350
  (0, workspace_manager_1.ensureFrameworkCommandSubtrees)(cwd, adapter.projectDirName);
352
351
  }
353
352
  catch { /* best-effort */ }
@@ -556,7 +555,6 @@ function createLoopExecutors(opts = {}) {
556
555
  const extraArgs = aiStepExtraArgs(adapter, cwd, repoDir, executionManifest);
557
556
  if (repoDir) {
558
557
  try {
559
- (0, workspace_manager_1.ensureFrameworkAgents)(cwd, adapter.projectDirName);
560
558
  (0, workspace_manager_1.ensureFrameworkCommandSubtrees)(cwd, adapter.projectDirName);
561
559
  }
562
560
  catch { /* best-effort */ }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.configurableImplementGraph = configurableImplementGraph;
4
+ const agent_runtime_settings_1 = require("../../agent-runtime/runtime/agent-runtime-settings");
4
5
  const loop_agents_1 = require("./loop-agents");
5
6
  const objectSchema = (properties, required = Object.keys(properties)) => ({ type: 'object', properties, required, additionalProperties: false });
6
7
  const string = { type: 'string' };
@@ -12,10 +13,10 @@ const reviewPolicy = 'approved == true; issues must be empty; score >= 70; ' + O
12
13
  function configurableImplementGraph() {
13
14
  const agents = (0, loop_agents_1.defaultLoopAgents)();
14
15
  agents.roles = {
15
- plan: { ...agents.agents.architect, access: 'read', artifacts: 'all', openspecSkill: 'openspec-ff-change', prompt: agents.rolePrompts?.architect },
16
- build: { ...agents.agents.developer, access: 'write', artifacts: 'tasks-checkboxes', openspecSkill: 'openspec-apply-change', prompt: agents.rolePrompts?.developer },
17
- assess: { ...agents.agents.reviewer, access: 'read', artifacts: 'none', openspecSkill: 'openspec-verify-change', prompt: agents.rolePrompts?.reviewer },
18
- correct: { ...agents.fixer, access: 'write', artifacts: 'tasks-checkboxes', openspecSkill: 'openspec-apply-change', prompt: agents.rolePrompts?.fixer },
16
+ plan: { ...agents.agents.architect, access: 'read', artifacts: 'all', openspecSkill: 'openspec-ff-change', prompt: (0, agent_runtime_settings_1.inheritedRolePrompt)(agents.rolePrompts, 'architect') },
17
+ build: { ...agents.agents.developer, access: 'write', artifacts: 'tasks-checkboxes', openspecSkill: 'openspec-apply-change', prompt: (0, agent_runtime_settings_1.inheritedRolePrompt)(agents.rolePrompts, 'developer') },
18
+ assess: { ...agents.agents.reviewer, access: 'read', artifacts: 'none', openspecSkill: 'openspec-verify-change', prompt: (0, agent_runtime_settings_1.inheritedRolePrompt)(agents.rolePrompts, 'reviewer') },
19
+ correct: { ...agents.fixer, access: 'write', artifacts: 'tasks-checkboxes', openspecSkill: 'openspec-apply-change', prompt: (0, agent_runtime_settings_1.inheritedRolePrompt)(agents.rolePrompts, 'fixer') },
19
20
  };
20
21
  const nodes = [{ id: 'start', type: 'start', position: { x: 0, y: 0 } }], edges = [];
21
22
  const node = (id, label, kind, params, outcomes) => {
@@ -63,7 +63,9 @@ function registerLoopsRoutes(router, deps) {
63
63
  if (!guard(res))
64
64
  return;
65
65
  const runtime = await (0, agent_runtime_loader_1.loadCoreAgentRuntime)().catch(() => null);
66
- res.json({ agents: (0, loop_agents_1.defaultLoopAgents)(), guardrails: { supported: runtime?.api?.capabilities?.configurableGuardrails === 1, catalog: runtime?.api?.guardrails ?? [] } });
66
+ // `inherit` definitions resolve at launch; the editor previews what they resolve to today.
67
+ const rolePromptDefaults = runtime ? { ...runtime.rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)() } : null;
68
+ res.json({ agents: (0, loop_agents_1.defaultLoopAgents)(), rolePromptDefaults, guardrails: { supported: runtime?.api?.capabilities?.configurableGuardrails === 1, catalog: runtime?.api?.guardrails ?? [] } });
67
69
  });
68
70
  // ── Templates ──────────────────────────────────────────────────────────────
69
71
  router.get('/loop-templates', async (_req, res) => {
@@ -1,18 +1,20 @@
1
1
  "use strict";
2
- // Gemini headless subagent pre-acknowledgment.
2
+ // Gemini headless subagent pre-acknowledgment (custom agents only).
3
3
  //
4
4
  // gemini 0.46+ DISCOVERS `<project>/.gemini/agents/*.md` but only ENABLES a
5
5
  // project's custom subagents after an interactive "New Agents Discovered →
6
6
  // Acknowledge and Enable" prompt. That prompt never fires in headless
7
7
  // (`gemini -p`) spawns — which is how the desktop runs every rail — so
8
- // `invoke_agent sr-architect` returns "Subagent not found" and the implement
9
- // orchestrator silently falls back to a generic agent (the specialised
10
- // architect/developer/reviewer personas never run in isolation).
8
+ // `invoke_agent custom-<name>` returns "Subagent not found" and the role that
9
+ // delegates to it silently falls back to inline work. The baseline roles
10
+ // (architect/developer/reviewer) are defined by the specrails-core runtime and
11
+ // are not `.gemini/agents` files, so only the project's `custom-*` agents need
12
+ // this acknowledgment.
11
13
  //
12
14
  // specrails-core writes the acknowledgment file at install time; this is the
13
15
  // defence-in-depth copy the desktop runs right before a gemini rail spawn, so a
14
- // project installed with an older core (or whose agents changed since install)
15
- // is still trusted headless. The file gemini reads is
16
+ // project whose custom agents changed since install is still trusted headless.
17
+ // The file gemini reads is
16
18
  // `~/.gemini/acknowledgments/agents.json`, shaped
17
19
  // { [projectRoot]: { [agentName]: <sha256-hex of the agent .md file> } }
18
20
  // where the hash is sha256 of the FULL agent markdown file (verified empirically
@@ -29,10 +31,11 @@ function ackFilePath() {
29
31
  return (0, path_1.join)((0, os_1.homedir)(), '.gemini', 'acknowledgments', 'agents.json');
30
32
  }
31
33
  /**
32
- * Pre-acknowledge every `<projectPath>/.gemini/agents/*.md` so gemini loads them
33
- * in headless mode. No-op when the project has no `.gemini/agents` dir or no
34
- * agent files. The `projectPath` is the key gemini uses (the spawn cwd / repo
35
- * root), matching what `specrails-core` writes at install.
34
+ * Pre-acknowledge every `<projectPath>/.gemini/agents/*.md` (the project's
35
+ * custom agents) so gemini loads them in headless mode. No-op when the project
36
+ * has no `.gemini/agents` dir or no agent files. The `projectPath` is the key
37
+ * gemini uses (the spawn cwd / repo root), matching what `specrails-core`
38
+ * writes at install.
36
39
  */
37
40
  function acknowledgeGeminiProjectAgents(projectPath) {
38
41
  const agentsDir = (0, path_1.join)(projectPath, '.gemini', 'agents');