@jaggerxtrm/specialists 3.17.0 → 3.18.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 (246) hide show
  1. package/README.md +268 -134
  2. package/config/mandatory-rules/json-only-final-output.md +13 -0
  3. package/config/mandatory-rules/service-skills-diff-scan-mandatory.md +26 -0
  4. package/config/mandatory-rules/service-skills-gitnexus-triage.md +5 -0
  5. package/config/skills/setup-specialists/SKILL.md +556 -0
  6. package/config/skills/specialists-creator/SKILL.md +132 -4
  7. package/config/skills/specialists-creator/scripts/audit-spec-uniformity.mjs +1 -1
  8. package/config/specialists/bare.specialist.json +3 -3
  9. package/config/specialists/changelog-drafter.specialist.json +5 -4
  10. package/config/specialists/changelog-keeper.specialist.json +7 -6
  11. package/config/specialists/debugger.specialist.json +2 -2
  12. package/config/specialists/executor.specialist.json +2 -2
  13. package/config/specialists/explorer.specialist.json +4 -4
  14. package/config/specialists/memory-processor.specialist.json +3 -3
  15. package/config/specialists/node-coordinator.specialist.json +3 -3
  16. package/config/specialists/obligations-scanner.specialist.json +67 -17
  17. package/config/specialists/overthinker.specialist.json +3 -3
  18. package/config/specialists/planner.specialist.json +4 -4
  19. package/config/specialists/quant-methodologist.specialist.json +145 -0
  20. package/config/specialists/quant-researcher.specialist.json +144 -0
  21. package/config/specialists/researcher.specialist.json +5 -5
  22. package/config/specialists/reviewer.specialist.json +1 -1
  23. package/config/specialists/seconder.specialist.json +2 -2
  24. package/config/specialists/security-auditor.specialist.json +2 -2
  25. package/config/specialists/service-skills-sync.specialist.json +90 -75
  26. package/config/specialists/specialists-creator.specialist.json +4 -4
  27. package/config/specialists/sync-docs.specialist.json +4 -4
  28. package/config/specialists/test-engineer.specialist.json +3 -3
  29. package/config/specialists/test-runner.specialist.json +7 -7
  30. package/config/specialists/transcriber.specialist.json +3 -3
  31. package/config/specialists/xt-merge.specialist.json +4 -4
  32. package/dist/asset-contract.json +21 -2
  33. package/dist/index.js +25704 -16376
  34. package/dist/lib.js +9849 -6147
  35. package/dist/types/cli/console/components.d.ts +83 -0
  36. package/dist/types/cli/console/components.d.ts.map +1 -0
  37. package/dist/types/cli/console/config-source.d.ts +58 -0
  38. package/dist/types/cli/console/config-source.d.ts.map +1 -0
  39. package/dist/types/cli/console/forensic.d.ts +11 -0
  40. package/dist/types/cli/console/forensic.d.ts.map +1 -0
  41. package/dist/types/cli/console/git.d.ts +28 -0
  42. package/dist/types/cli/console/git.d.ts.map +1 -0
  43. package/dist/types/cli/console/help.d.ts +2 -0
  44. package/dist/types/cli/console/help.d.ts.map +1 -0
  45. package/dist/types/cli/console/log.d.ts +13 -0
  46. package/dist/types/cli/console/log.d.ts.map +1 -0
  47. package/dist/types/cli/console/repo-config.d.ts +26 -0
  48. package/dist/types/cli/console/repo-config.d.ts.map +1 -0
  49. package/dist/types/cli/console/repo-discovery.d.ts +12 -0
  50. package/dist/types/cli/console/repo-discovery.d.ts.map +1 -0
  51. package/dist/types/cli/console/runtime.d.ts +12 -0
  52. package/dist/types/cli/console/runtime.d.ts.map +1 -0
  53. package/dist/types/cli/console/subscribe-prototype.d.ts +18 -0
  54. package/dist/types/cli/console/subscribe-prototype.d.ts.map +1 -0
  55. package/dist/types/cli/console/theme.d.ts +91 -0
  56. package/dist/types/cli/console/theme.d.ts.map +1 -0
  57. package/dist/types/cli/console/types.d.ts +231 -0
  58. package/dist/types/cli/console/types.d.ts.map +1 -0
  59. package/dist/types/cli/console/view-model.d.ts +252 -0
  60. package/dist/types/cli/console/view-model.d.ts.map +1 -0
  61. package/dist/types/cli/console.d.ts +2 -0
  62. package/dist/types/cli/console.d.ts.map +1 -0
  63. package/dist/types/cli/db.d.ts.map +1 -1
  64. package/dist/types/cli/doctor.d.ts.map +1 -1
  65. package/dist/types/cli/edit.d.ts.map +1 -1
  66. package/dist/types/cli/epic.d.ts.map +1 -1
  67. package/dist/types/cli/feed.d.ts.map +1 -1
  68. package/dist/types/cli/forensic.d.ts +2 -0
  69. package/dist/types/cli/forensic.d.ts.map +1 -0
  70. package/dist/types/cli/format-helpers.d.ts +4 -2
  71. package/dist/types/cli/format-helpers.d.ts.map +1 -1
  72. package/dist/types/cli/help.d.ts.map +1 -1
  73. package/dist/types/cli/init.d.ts +10 -0
  74. package/dist/types/cli/init.d.ts.map +1 -1
  75. package/dist/types/cli/list.d.ts.map +1 -1
  76. package/dist/types/cli/log.d.ts.map +1 -1
  77. package/dist/types/cli/metrics.d.ts +2 -0
  78. package/dist/types/cli/metrics.d.ts.map +1 -0
  79. package/dist/types/cli/ps.d.ts.map +1 -1
  80. package/dist/types/cli/result.d.ts.map +1 -1
  81. package/dist/types/cli/run.d.ts +1 -0
  82. package/dist/types/cli/run.d.ts.map +1 -1
  83. package/dist/types/cli/script.d.ts +3 -0
  84. package/dist/types/cli/script.d.ts.map +1 -1
  85. package/dist/types/cli/serve.d.ts.map +1 -1
  86. package/dist/types/cli/setup.d.ts +19 -1
  87. package/dist/types/cli/setup.d.ts.map +1 -1
  88. package/dist/types/cli/status.d.ts.map +1 -1
  89. package/dist/types/cli/version-check.d.ts +1 -0
  90. package/dist/types/cli/version-check.d.ts.map +1 -1
  91. package/dist/types/index.d.ts +1 -1
  92. package/dist/types/pi/session.d.ts +11 -1
  93. package/dist/types/pi/session.d.ts.map +1 -1
  94. package/dist/types/server.d.ts +15 -0
  95. package/dist/types/server.d.ts.map +1 -1
  96. package/dist/types/specialist/benchmarks.d.ts +37 -0
  97. package/dist/types/specialist/benchmarks.d.ts.map +1 -0
  98. package/dist/types/specialist/chain-identity.d.ts +7 -1
  99. package/dist/types/specialist/chain-identity.d.ts.map +1 -1
  100. package/dist/types/specialist/control.d.ts.map +1 -1
  101. package/dist/types/specialist/forensic-events.d.ts +138 -0
  102. package/dist/types/specialist/forensic-events.d.ts.map +1 -0
  103. package/dist/types/specialist/forensic-renderer.d.ts +34 -0
  104. package/dist/types/specialist/forensic-renderer.d.ts.map +1 -0
  105. package/dist/types/specialist/git-diff-evidence.d.ts +28 -0
  106. package/dist/types/specialist/git-diff-evidence.d.ts.map +1 -0
  107. package/dist/types/specialist/global-config.d.ts +389 -0
  108. package/dist/types/specialist/global-config.d.ts.map +1 -0
  109. package/dist/types/specialist/launch.d.ts +1 -0
  110. package/dist/types/specialist/launch.d.ts.map +1 -1
  111. package/dist/types/specialist/live-aggregates.d.ts +46 -0
  112. package/dist/types/specialist/live-aggregates.d.ts.map +1 -0
  113. package/dist/types/specialist/loader.d.ts +50 -1
  114. package/dist/types/specialist/loader.d.ts.map +1 -1
  115. package/dist/types/specialist/model-chain.d.ts +7 -0
  116. package/dist/types/specialist/model-chain.d.ts.map +1 -0
  117. package/dist/types/specialist/model-probes.d.ts +28 -0
  118. package/dist/types/specialist/model-probes.d.ts.map +1 -0
  119. package/dist/types/specialist/node-contract.d.ts +18 -18
  120. package/dist/types/specialist/node-supervisor.d.ts.map +1 -1
  121. package/dist/types/specialist/observability-db.d.ts +1 -1
  122. package/dist/types/specialist/observability-db.d.ts.map +1 -1
  123. package/dist/types/specialist/observability-sqlite.d.ts +25 -0
  124. package/dist/types/specialist/observability-sqlite.d.ts.map +1 -1
  125. package/dist/types/specialist/preset-resolver.d.ts +56 -0
  126. package/dist/types/specialist/preset-resolver.d.ts.map +1 -0
  127. package/dist/types/specialist/prometheus-projection.d.ts +25 -0
  128. package/dist/types/specialist/prometheus-projection.d.ts.map +1 -0
  129. package/dist/types/specialist/runner.d.ts +26 -1
  130. package/dist/types/specialist/runner.d.ts.map +1 -1
  131. package/dist/types/specialist/schema.d.ts +163 -54
  132. package/dist/types/specialist/schema.d.ts.map +1 -1
  133. package/dist/types/specialist/script-runner.d.ts +5 -1
  134. package/dist/types/specialist/script-runner.d.ts.map +1 -1
  135. package/dist/types/specialist/snapshot-diff.d.ts +8 -0
  136. package/dist/types/specialist/snapshot-diff.d.ts.map +1 -0
  137. package/dist/types/specialist/source-queue.d.ts +13 -0
  138. package/dist/types/specialist/source-queue.d.ts.map +1 -0
  139. package/dist/types/specialist/supervisor.d.ts +15 -1
  140. package/dist/types/specialist/supervisor.d.ts.map +1 -1
  141. package/dist/types/specialist/timeline-events.d.ts +68 -1
  142. package/dist/types/specialist/timeline-events.d.ts.map +1 -1
  143. package/dist/types/tools/specialist/resume_specialist.tool.d.ts +4 -4
  144. package/dist/types/tools/specialist/specialist_status.tool.d.ts +1 -1
  145. package/dist/types/tools/specialist/steer_specialist.tool.d.ts +4 -4
  146. package/dist/types/tools/specialist/use_specialist.tool.d.ts +16 -16
  147. package/docs/ARCHITECTURE.md +1176 -0
  148. package/docs/TODO.md +9 -0
  149. package/docs/architecture.md +11 -0
  150. package/docs/archive/2026-03-13-bd-decision-context-template-plan.md +96 -0
  151. package/docs/archive/AGENT-HANDOFF.md +351 -0
  152. package/docs/archive/PARITY-ANALYSIS.md +296 -0
  153. package/docs/archive/SPECIALISTS_REFACTOR.md.md +30 -0
  154. package/docs/archive/cc-programmatic.md +216 -0
  155. package/docs/archive/claude-agent-sdk.md +594 -0
  156. package/docs/archive/decision-specialist-directory.md +41 -0
  157. package/docs/archive/discoveries.md +148 -0
  158. package/docs/archive/executor-benchmark-protocol.md +198 -0
  159. package/docs/archive/future-features.md +66 -0
  160. package/docs/archive/gzrx-completion-critique.md +183 -0
  161. package/docs/archive/gzrx-research-notes.md +401 -0
  162. package/docs/archive/gzrx-tool-catalog.md +760 -0
  163. package/docs/archive/iron-review-hardening-qa-chain-substrate.md +322 -0
  164. package/docs/archive/iron-review-hardening.html +1004 -0
  165. package/docs/archive/issuetracking.md +312 -0
  166. package/docs/archive/qa-v3.0.2.md +220 -0
  167. package/docs/archive/restructure.md +231 -0
  168. package/docs/archive/script-specialists.md +1254 -0
  169. package/docs/archive/spec-v3.md +792 -0
  170. package/docs/archive/specialist-stats.md +127 -0
  171. package/docs/archive/specialists-friction-audit.md +1347 -0
  172. package/docs/archive/specialists-runtime-critique.md +170 -0
  173. package/docs/archive/specialists-service-evaluation.md +713 -0
  174. package/docs/archive/specialists-substrate-alignment.md +255 -0
  175. package/docs/archive/substrate-review.md +1288 -0
  176. package/docs/archive/test-writer-specialist.md +254 -0
  177. package/docs/archive/using-specialists-v3-improvements-2026-05-09.md +600 -0
  178. package/docs/archive/xtrm-specialists-analysis.md +314 -0
  179. package/docs/authoring.md +701 -0
  180. package/docs/background-jobs.md +203 -0
  181. package/docs/bare-specialists.md +83 -0
  182. package/docs/benchmarks/executor-benchmark-runner.md +66 -0
  183. package/docs/bootstrap.md +161 -0
  184. package/docs/cli-reference.md +1645 -0
  185. package/docs/deploying-alongside.md +155 -0
  186. package/docs/design/README.md +36 -0
  187. package/docs/design/darth-feedor-migration.md +290 -0
  188. package/docs/design/roadmap/README.md +32 -0
  189. package/docs/design/roadmap/chain-templates/README.md +146 -0
  190. package/docs/design/roadmap/chain-templates/code-quick.formula.json +27 -0
  191. package/docs/design/roadmap/chain-templates/code-standard.formula.json +126 -0
  192. package/docs/design/roadmap/chain-templates/code-with-advisors.formula.json +128 -0
  193. package/docs/design/roadmap/chain-templates/code-with-tests.formula.json +76 -0
  194. package/docs/design/roadmap/chain-templates/debug.formula.json +128 -0
  195. package/docs/design/roadmap/chain-templates/doc-sync.formula.json +28 -0
  196. package/docs/design/roadmap/chain-templates/memory-hygiene.formula.json +27 -0
  197. package/docs/design/roadmap/chain-templates/planning.formula.json +27 -0
  198. package/docs/design/roadmap/chain-templates/premortem.formula.json +26 -0
  199. package/docs/design/roadmap/chain-templates/release-prep.formula.json +36 -0
  200. package/docs/design/roadmap/chain-templates/research-only.formula.json +28 -0
  201. package/docs/design/roadmap/chain-templates/restitch.formula.json +125 -0
  202. package/docs/design/roadmap/chain-templates/security-deep.formula.json +161 -0
  203. package/docs/design/roadmap/chain-templates/test-only.formula.json +52 -0
  204. package/docs/design/roadmap/chain-templates/triage.formula.json +35 -0
  205. package/docs/design/roadmap/history/handoff-from-substrate-design.md +87 -0
  206. package/docs/design/roadmap/history/substrate-reconciliation.md +105 -0
  207. package/docs/design/roadmap/specialists-roadmap.md +1193 -0
  208. package/docs/design/sp-console-subscribe-via-materializer.md +231 -0
  209. package/docs/design/sp-console-tui-mock-v2.html +293 -0
  210. package/docs/design/sp-console-tui-mock.html +120 -0
  211. package/docs/design/sp-console-tui.md +340 -0
  212. package/docs/design/specialist-agentops-suite.md +323 -0
  213. package/docs/design/substrate/channels.md +14 -0
  214. package/docs/design/substrate/devops-platform-engineering-prd.md +446 -0
  215. package/docs/design/substrate/html-design-example.md +339 -0
  216. package/docs/design/xtrm-tiers-architecture.svg +132 -0
  217. package/docs/devops/dependency-verdict-materialization.md +46 -0
  218. package/docs/epic-readiness.md +75 -0
  219. package/docs/examples/mercury-atomic-summarizer.specialist.json +26 -0
  220. package/docs/examples/smoke-echo-text-expected-keys.specialist.json +25 -0
  221. package/docs/examples/smoke-echo.specialist.json +25 -0
  222. package/docs/features.md +1577 -0
  223. package/docs/hooks.md +81 -0
  224. package/docs/installation.md +142 -0
  225. package/docs/manifest.md +184 -0
  226. package/docs/mcp-servers.md +73 -0
  227. package/docs/mcp-tools.md +71 -0
  228. package/docs/nodes.md +231 -0
  229. package/docs/observability-metrics.md +152 -0
  230. package/docs/operator/sp-console-v2-walkthrough.md +410 -0
  231. package/docs/overrides-guide.md +306 -0
  232. package/docs/pi-rpc-boundary.md +118 -0
  233. package/docs/pi-session.md +195 -0
  234. package/docs/release.md +22 -0
  235. package/docs/skills.md +132 -0
  236. package/docs/specialists/handoff-schema.md +181 -0
  237. package/docs/specialists-catalog.md +99 -0
  238. package/docs/specialists-service-install.md +226 -0
  239. package/docs/specialists-service.md +363 -0
  240. package/docs/surface-ownership.md +138 -0
  241. package/docs/upgrade-notes/kan-90-global-user-config.md +114 -0
  242. package/docs/upgrade-notes/kan-91-expanded-overrides.md +261 -0
  243. package/docs/workflow.md +114 -0
  244. package/docs/worktree.md +71 -0
  245. package/docs/worktrees.md +309 -0
  246. package/package.json +6 -3
@@ -0,0 +1,1254 @@
1
+ # Script-Specialists Architecture Report
2
+
3
+ **Date:** 2026-04-24
4
+ **Scope:** Current legacy "script-specialists" design used by services and scripts in this repo
5
+ **Status:** Active in production-facing Python services, but conceptually superseded by the newer `.specialists/*.specialist.json` orchestration system
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ This repository currently contains **two different specialist systems**:
12
+
13
+ 1. **Legacy script-specialists system** — YAML-defined prompt/config artifacts used directly by Python services and scripts.
14
+ 2. **Newer orchestration specialists system** — JSON-defined agent/runtime specialists under `.specialists/` with hooks, jobs, nodes, and background execution.
15
+
16
+ This report describes the **legacy script-specialists system**, because that is what the ingestion and squawk services still run today.
17
+
18
+ At a high level, the script-specialists design is:
19
+
20
+ - a **YAML prompt/config registry** in `specialists/`
21
+ - a **Pydantic-backed loader** in `shared/specialist_system/`
22
+ - several **Python service consumers** that load a named specialist at startup
23
+ - a centralized **qwen-service** HTTP gateway (`llm_gateway/`) that executes the actual LLM request
24
+
25
+ The system is best understood as a **configuration-driven prompt layer for scripts/services**, not as a complete specialist runtime. The specialist YAML provides metadata, prompt templates, and nominal execution settings, but only part of that configuration is enforced at runtime.
26
+
27
+ ---
28
+
29
+ ## Naming and Scope Clarification
30
+
31
+ ### What "script-specialists" means here
32
+
33
+ In this report, **script-specialists** means the older system built around:
34
+
35
+ - `specialists/**/*.specialist.yaml`
36
+ - `shared/specialist_system/schema.py`
37
+ - `shared/specialist_system/loader.py`
38
+
39
+ It is called "script-specialists" because it is consumed directly by application code and service scripts.
40
+
41
+ ### What it is *not*
42
+
43
+ It is **not** the newer orchestrated agent system found in:
44
+
45
+ - `.specialists/default/*.specialist.json`
46
+ - `.specialists/default/nodes/*.node.json`
47
+ - `.claude/hooks/specialists-session-start.mjs`
48
+ - `.claude/hooks/specialists-complete.mjs`
49
+
50
+ That newer system has jobs, background execution, keep-alive sessions, nodes, reviewers, worktrees, and hook-driven UX. The script-specialists system has none of that.
51
+
52
+ ---
53
+
54
+ ## Repository Map
55
+
56
+ ### Core legacy script-specialists files
57
+
58
+ - `specialists/ingestion/mercury-atomic-summarizer.specialist.yaml`
59
+ - `specialists/ingestion/official-document-analyzer.specialist.yaml`
60
+ - `specialists/ingestion/squawk-rolling-context.specialist.yaml`
61
+ - `specialists/ingestion/squawk-event-curator.specialist.yaml`
62
+ - `specialists/ingestion/squawk-session-analyst.specialist.yaml`
63
+ - `shared/specialist_system/schema.py`
64
+ - `shared/specialist_system/loader.py`
65
+ - `shared/specialist_system/__init__.py`
66
+
67
+ ### Runtime consumers
68
+
69
+ - `ingestion/summarizer.py`
70
+ - `ingestion/official_docs.py`
71
+ - `squawks/rolling_context.py`
72
+
73
+ ### LLM transport / execution layer
74
+
75
+ - `shared/qwen_client.py`
76
+ - `llm_gateway/src/llm_gateway/main.py`
77
+ - `llm_gateway/src/llm_gateway/wrapper.py`
78
+ - `llm_gateway/src/llm_gateway/manager.py`
79
+ - `llm_gateway/infra/docker-compose.yml`
80
+
81
+ ### Infra wiring
82
+
83
+ - `ingestion/infra/docker-compose.yml`
84
+
85
+ ### Tests and implementation notes
86
+
87
+ - `specialists/SPECIALIST_SYSTEM_IMPLEMENTATION.md`
88
+ - `specialists/test/test_specialist_system.py`
89
+ - `tests/test_qwen_client.py`
90
+ - `tests/test_rolling_context_specialists.py`
91
+ - `llm_gateway/tests/test_wrapper.py`
92
+ - `.serena/memories/specialist-system_ssot.md`
93
+
94
+ ---
95
+
96
+ ## High-Level Architecture
97
+
98
+ ```mermaid
99
+ flowchart TD
100
+ Y[Specialist YAML files<br/>specialists/**/*.specialist.yaml] --> L[SpecialistLoader<br/>shared/specialist_system/loader.py]
101
+ S[Schema / Pydantic models<br/>shared/specialist_system/schema.py] --> L
102
+
103
+ L --> A1[QwenSummarizer<br/>ingestion/summarizer.py]
104
+ L --> A2[OfficialDocumentsImporter<br/>ingestion/official_docs.py]
105
+ L --> A3[RollingContextAgent<br/>squawks/rolling_context.py]
106
+
107
+ A1 --> QC[shared/qwen_client.py]
108
+ A3 --> QC
109
+ A2 --> HTTP[direct HTTP POST]
110
+
111
+ QC --> QS[qwen-service / llm_gateway<br/>POST /generate]
112
+ HTTP --> QS
113
+
114
+ QS --> W[QwenWrapper<br/>CLI invocation + retries]
115
+ W --> M[AccountManager<br/>credential rotation]
116
+ W --> CLI[qwen CLI]
117
+
118
+ M --> QDIR[~/.qwen<br/>oauth_creds.json + accounts/*]
119
+
120
+ A1 --> DB1[(articles table)]
121
+ A2 --> DB1
122
+ A3 --> DB2[(squawk_rolling_context)]
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Design Goals of the Legacy System
128
+
129
+ The legacy system was built to move prompt logic out of code and into editable config files.
130
+
131
+ Primary intended benefits:
132
+
133
+ - prompt changes without code edits
134
+ - prompt changes without rebuilding images
135
+ - discoverable specialists via filesystem scanning
136
+ - startup validation with Pydantic
137
+ - reusable prompt templates across multiple services
138
+ - lighter-weight experimentation than hardcoding prompts in Python
139
+
140
+ Operationally, the workflow is:
141
+
142
+ 1. define a specialist YAML file
143
+ 2. mount `specialists/` into a container
144
+ 3. service loads the specialist by name at startup
145
+ 4. service renders prompt variables into `task_template`
146
+ 5. service sends the rendered prompt to `qwen-service`
147
+ 6. service parses/validates the result and persists it
148
+
149
+ ---
150
+
151
+ ## Specialist File Format
152
+
153
+ All legacy specialists are rooted under a top-level `specialist:` key.
154
+
155
+ Example structure:
156
+
157
+ ```yaml
158
+ specialist:
159
+ metadata:
160
+ name: mercury-atomic-summarizer
161
+ version: 1.1.0
162
+ description: "..."
163
+ category: ingestion/summarization
164
+ created: 2026-02-08T00:00:00Z
165
+ updated: 2026-02-11T02:00:00Z
166
+ author: jagger
167
+
168
+ validation:
169
+ files_to_watch:
170
+ - ingestion/summarizer.py
171
+ references:
172
+ - type: code
173
+ path: ingestion/summarizer.py
174
+ symbol: QwenSummarizer.generate_summary
175
+ purpose: "Integration point"
176
+ stale_threshold_days: 30
177
+
178
+ execution:
179
+ model: qwen-coder
180
+ temperature: 0.3
181
+ max_tokens: 2000
182
+ response_format: json
183
+ fallback_model: gemini-2.0-flash-thinking
184
+
185
+ prompt:
186
+ system: |
187
+ ...
188
+ task_template: |
189
+ ... $title ... $content ...
190
+ normalize_template: |
191
+ ... optional second-stage template ...
192
+ output_schema:
193
+ type: object
194
+ required: [...]
195
+ properties: ...
196
+ ```
197
+
198
+ ### Field groups
199
+
200
+ #### `metadata`
201
+ Descriptive information used for identification and traceability.
202
+
203
+ #### `validation`
204
+ Operational metadata for drift/staleness awareness:
205
+
206
+ - `files_to_watch`
207
+ - `references`
208
+ - `stale_threshold_days`
209
+
210
+ #### `execution`
211
+ Nominal runtime settings:
212
+
213
+ - `model`
214
+ - `temperature`
215
+ - `max_tokens`
216
+ - `response_format`
217
+ - `fallback_model`
218
+
219
+ #### `prompt`
220
+ The actual behavioral contract:
221
+
222
+ - `system`
223
+ - `task_template`
224
+ - `normalize_template` (optional)
225
+ - `output_schema`
226
+ - `examples`
227
+
228
+ ---
229
+
230
+ ## Schema Layer
231
+
232
+ File:
233
+
234
+ - `shared/specialist_system/schema.py`
235
+
236
+ This is the authoritative typed schema for the legacy system.
237
+
238
+ ### Main models
239
+
240
+ - `SpecialistConfig`
241
+ - `SpecialistMetadata`
242
+ - `ValidationConfig`
243
+ - `ExecutionConfig`
244
+ - `PromptConfig`
245
+ - `FileReference`
246
+ - `SpecialistCategory`
247
+
248
+ ### Important constraints enforced at load time
249
+
250
+ Examples of actual schema constraints:
251
+
252
+ - `metadata.name` must match `^[a-z0-9-]+$`
253
+ - `metadata.version` must match semantic version pattern
254
+ - `description` has length bounds
255
+ - `prompt.task_template` must be non-empty and at least 10 chars
256
+ - `execution.temperature` is bounded
257
+ - `execution.max_tokens` is bounded
258
+ - `validation.stale_threshold_days` is bounded
259
+ - `metadata.updated >= metadata.created`
260
+
261
+ ### Category model
262
+
263
+ The enum in `schema.py` is still narrow and oriented around the original ingestion/analysis use case:
264
+
265
+ - `ingestion/summarization`
266
+ - `ingestion/processing`
267
+ - `monitoring/health`
268
+ - `monitoring/diagnostics`
269
+ - `analysis/macro`
270
+ - `analysis/technical`
271
+
272
+ That reflects the age of the system: it was designed first for service prompts, not for general-purpose agent orchestration.
273
+
274
+ ---
275
+
276
+ ## Loader Layer
277
+
278
+ File:
279
+
280
+ - `shared/specialist_system/loader.py`
281
+
282
+ `SpecialistLoader` is the central runtime for the legacy system.
283
+
284
+ ### Responsibilities
285
+
286
+ 1. discover YAML files recursively
287
+ 2. parse YAML
288
+ 3. validate specialist configs via Pydantic
289
+ 4. cache loaded specialists in memory
290
+ 5. render prompt templates using variables
291
+ 6. perform lightweight runtime output validation
292
+ 7. warn about stale/missing watched files
293
+
294
+ ### Startup discovery
295
+
296
+ On initialization:
297
+
298
+ - `SpecialistLoader()` defaults to `Path("specialists")`
299
+ - `_scan_specialists()` recursively scans for `*.specialist.yaml`
300
+ - each file is loaded via `_load_yaml_file()`
301
+ - valid specialists are cached by `metadata.name`
302
+
303
+ ### Cache model
304
+
305
+ The cache is an in-memory dict:
306
+
307
+ - key = specialist name
308
+ - value = validated `SpecialistConfig`
309
+
310
+ No persistent index exists. Discovery is filesystem-based.
311
+
312
+ ### Loading behavior
313
+
314
+ `load(name)`:
315
+
316
+ - looks up the cached config
317
+ - runs `_check_health()`
318
+ - returns the `SpecialistConfig`
319
+
320
+ ### Health checks
321
+
322
+ `_check_health()` currently does basic checks only:
323
+
324
+ - warn if specialist age exceeds `stale_threshold_days`
325
+ - warn if a watched file path does not exist
326
+
327
+ It does **not** currently implement deeper semantic drift detection.
328
+
329
+ ### Prompt rendering
330
+
331
+ `render_prompt()`:
332
+
333
+ - prepends `prompt.system` if present
334
+ - renders `prompt.task_template` using `string.Template`
335
+ - raises `KeyError` if a required template variable is missing
336
+
337
+ This means all prompt variables are strict string-template substitutions like:
338
+
339
+ - `$title`
340
+ - `$content`
341
+ - `$sender`
342
+ - `$controlled_tags`
343
+
344
+ ### Runtime output validation
345
+
346
+ `validate_output()` is intentionally lightweight.
347
+
348
+ What it actually does today:
349
+
350
+ 1. if there is no `output_schema`, returns `True`
351
+ 2. if response format is not `json`, skips strict checking
352
+ 3. strips `<think>...</think>` blocks
353
+ 4. extracts the outermost JSON object from the output text
354
+ 5. parses JSON
355
+ 6. checks only presence of fields listed in `output_schema.required`
356
+
357
+ What it does **not** fully enforce:
358
+
359
+ - nested schema types
360
+ - enum validity
361
+ - array cardinality
362
+ - string length limits
363
+ - `properties` shape correctness
364
+
365
+ So the loader gives **strong config validation** but only **shallow runtime payload validation**.
366
+
367
+ ---
368
+
369
+ ## Runtime Consumers
370
+
371
+ ## 1. `ingestion/summarizer.py`
372
+
373
+ Class:
374
+
375
+ - `QwenSummarizer`
376
+
377
+ Specialist used:
378
+
379
+ - `mercury-atomic-summarizer`
380
+
381
+ ### Role
382
+
383
+ This service processes pending articles and generates structured summaries.
384
+
385
+ ### Startup flow
386
+
387
+ At initialization it:
388
+
389
+ 1. constructs `QwenClient()`
390
+ 2. constructs `SpecialistLoader()`
391
+ 3. loads `mercury-atomic-summarizer`
392
+ 4. logs success or fails hard on `SpecialistLoadError`
393
+
394
+ ### Prompt construction
395
+
396
+ For each article, `generate_summary()`:
397
+
398
+ - truncates content to 40,000 chars
399
+ - optionally injects extracted table markdown
400
+ - injects source-specific context
401
+ - injects controlled tags vocabulary
402
+ - renders the specialist prompt
403
+
404
+ Variables passed include:
405
+
406
+ - `sender`
407
+ - `source_type`
408
+ - `title`
409
+ - `content`
410
+ - `truncation_notice`
411
+ - `tables_section`
412
+ - `is_truncated`
413
+ - `controlled_tags`
414
+
415
+ ### LLM call path
416
+
417
+ It uses:
418
+
419
+ - `shared.qwen_client.QwenClient.generate(prompt)`
420
+
421
+ ### Result handling
422
+
423
+ After response:
424
+
425
+ - extracts JSON by first `{` and last `}`
426
+ - calls `validate_output()`
427
+ - saves even if schema validation warns
428
+ - normalizes tags before writing to `articles.summary`
429
+
430
+ ### Architectural note
431
+
432
+ This is the cleanest expression of the script-specialists pattern: YAML defines the prompt contract; Python provides domain variables and persistence.
433
+
434
+ ---
435
+
436
+ ## 2. `ingestion/official_docs.py`
437
+
438
+ Class:
439
+
440
+ - `OfficialDocumentsImporter`
441
+
442
+ Specialist used:
443
+
444
+ - `official-document-analyzer`
445
+
446
+ ### Role
447
+
448
+ This service ingests official government documents from Gmail and produces policy-analysis summaries.
449
+
450
+ ### Startup flow
451
+
452
+ At initialization it:
453
+
454
+ 1. resolves `QWEN_SERVICE_URL`
455
+ 2. constructs `SpecialistLoader()`
456
+ 3. loads `official-document-analyzer`
457
+ 4. stores the specialist for later prompt rendering
458
+
459
+ ### Prompt construction
460
+
461
+ `generate_summary()` renders prompt variables such as:
462
+
463
+ - `sender`
464
+ - `title`
465
+ - `content`
466
+ - `truncation_notice`
467
+ - `is_truncated`
468
+
469
+ ### LLM call path
470
+
471
+ Unlike `QwenSummarizer`, this module performs **direct HTTP POST** to qwen-service.
472
+
473
+ It posts:
474
+
475
+ ```json
476
+ {
477
+ "prompt": "...",
478
+ "model": "...",
479
+ "temperature": 0.1,
480
+ "max_tokens": 2500
481
+ }
482
+ ```
483
+
484
+ ### Architectural note
485
+
486
+ This consumer reveals an important mismatch:
487
+
488
+ - the specialist execution block is read and forwarded
489
+ - but the current qwen-service request model only formally defines `prompt` and `timeout`
490
+
491
+ So the intent is richer than the actually enforced contract.
492
+
493
+ ---
494
+
495
+ ## 3. `squawks/rolling_context.py`
496
+
497
+ Class:
498
+
499
+ - `RollingContextAgent`
500
+
501
+ Specialists used:
502
+
503
+ - `squawk-rolling-context`
504
+ - `squawk-event-curator`
505
+ - `squawk-session-analyst`
506
+
507
+ ### Role
508
+
509
+ This is the most evolved consumer of the legacy system. It uses **multiple specialists in a staged pipeline**.
510
+
511
+ ### Startup flow
512
+
513
+ At initialization it:
514
+
515
+ 1. constructs `SpecialistLoader()`
516
+ 2. loads extractor specialist
517
+ 3. loads curator specialist
518
+ 4. loads analyst specialist
519
+ 5. derives `llm_model` from analyst execution config
520
+
521
+ ### Pipeline stages
522
+
523
+ #### Stage 1 — Extraction
524
+ Method:
525
+
526
+ - `_run_extraction()`
527
+
528
+ Uses:
529
+
530
+ - `squawk-rolling-context.prompt.task_template`
531
+
532
+ Behavior:
533
+
534
+ - scans raw squawks from the last 30 minutes
535
+ - asks the LLM to emit `new_events`
536
+ - retries once on invalid output
537
+ - resolves authoritative timestamps from source squawk indices
538
+
539
+ #### Stage 2 — Event curation
540
+ Method:
541
+
542
+ - `_run_event_curation()`
543
+
544
+ Uses:
545
+
546
+ - `squawk-event-curator.prompt.task_template`
547
+
548
+ Behavior:
549
+
550
+ - compares new events against existing memory
551
+ - asks the LLM to consolidate / enrich / suppress duplicates
552
+ - returns:
553
+ - `curated_events`
554
+ - `change_summary`
555
+ - `material_change_hint`
556
+ - falls back to extracted events on curator failure/emptiness
557
+
558
+ #### Stage 3 — Session synthesis
559
+ Method:
560
+
561
+ - `_run_synthesis()`
562
+
563
+ Uses:
564
+
565
+ - `squawk-session-analyst.prompt.normalize_template`
566
+
567
+ Behavior:
568
+
569
+ - builds a richer synthesis prompt from:
570
+ - curated events
571
+ - change summary
572
+ - previous-day summary
573
+ - LSEG digest context
574
+ - economic calendar context
575
+ - market snapshot context
576
+ - trusted article context
577
+ - asks the LLM for:
578
+ - `thesis`
579
+ - `overview`
580
+ - `what_changed`
581
+ - `contradictions`
582
+ - `watch_items`
583
+ - `mechanisms`
584
+ - `key_data`
585
+ - `session_themes`
586
+ - optional `previous_day_summary`
587
+ - rejects weak candidates that fail topical grounding heuristics
588
+ - computes degraded input metadata and confidence
589
+
590
+ ### Why this consumer matters
591
+
592
+ This is where the legacy design stretched beyond its original shape.
593
+
594
+ The script-specialists system started as:
595
+
596
+ - one YAML specialist
597
+ - one script
598
+ - one prompt
599
+
600
+ But `rolling_context.py` now uses it as a **multi-stage LLM orchestration framework**, even though the loader/runtime itself was never upgraded into a full orchestration system.
601
+
602
+ ---
603
+
604
+ ## qwen-service Integration
605
+
606
+ The script-specialists design does not execute models directly. It relies on a shared qwen HTTP gateway.
607
+
608
+ ## Shared client
609
+
610
+ File:
611
+
612
+ - `shared/qwen_client.py`
613
+
614
+ ### Responsibilities
615
+
616
+ - resolve `QWEN_SERVICE_URL`
617
+ - send prompt to `/generate`
618
+ - expose `health_check()`
619
+ - emit Prometheus metrics
620
+ - normalize connection failures into a simple result dict
621
+
622
+ ### Effective request contract
623
+
624
+ `QwenClient.generate(prompt, timeout=...)` sends:
625
+
626
+ ```json
627
+ {
628
+ "prompt": "...",
629
+ "timeout": 60
630
+ }
631
+ ```
632
+
633
+ This is the main path used by:
634
+
635
+ - `ingestion/summarizer.py`
636
+ - `squawks/utils.py`
637
+ - `ext_mcp/server.py`
638
+ - effectively most non-direct callers
639
+
640
+ ---
641
+
642
+ ## qwen-service server
643
+
644
+ Files:
645
+
646
+ - `llm_gateway/src/llm_gateway/main.py`
647
+ - `llm_gateway/src/llm_gateway/wrapper.py`
648
+ - `llm_gateway/src/llm_gateway/manager.py`
649
+
650
+ Container:
651
+
652
+ - `qwen-service`
653
+
654
+ ### API surface
655
+
656
+ #### `GET /health`
657
+ Returns:
658
+
659
+ - `status`
660
+ - `current_account`
661
+ - `total_switches`
662
+
663
+ #### `POST /generate`
664
+ Consumes a request model with:
665
+
666
+ - `prompt`
667
+ - `timeout`
668
+
669
+ Returns:
670
+
671
+ - `success`
672
+ - `output`
673
+ - `error`
674
+ - `error_type`
675
+ - `attempts`
676
+ - `accounts_tried`
677
+
678
+ #### Additional endpoints
679
+
680
+ - `POST /switch-next`
681
+ - `GET /accounts`
682
+ - `POST /accounts/{account_id}/reset`
683
+ - `GET /metrics`
684
+
685
+ ### Concurrency and resilience
686
+
687
+ `main.py` enforces:
688
+
689
+ - semaphore with concurrency limit = 2
690
+ - circuit breaker after repeated all-account failures
691
+ - HTTP 503 while breaker is open
692
+
693
+ ---
694
+
695
+ ## qwen CLI wrapper and account rotation
696
+
697
+ ### Wrapper
698
+
699
+ File:
700
+
701
+ - `llm_gateway/src/llm_gateway/wrapper.py`
702
+
703
+ The wrapper shells out to the installed CLI:
704
+
705
+ ```bash
706
+ qwen <prompt> --output-format text --auth-type qwen-oauth --model qwen3-coder-plus --yolo
707
+ ```
708
+
709
+ It classifies failures into:
710
+
711
+ - quota
712
+ - auth
713
+ - safety
714
+ - timeout
715
+ - network/unknown
716
+
717
+ ### Rotation manager
718
+
719
+ File:
720
+
721
+ - `llm_gateway/src/llm_gateway/manager.py`
722
+
723
+ Responsibilities:
724
+
725
+ - discover account files under `~/.qwen/accounts/`
726
+ - physically swap active credentials into `~/.qwen/oauth_creds.json`
727
+ - persist state in `~/.qwen/state.yaml`
728
+ - write rotation events to `~/.qwen/rotation.log`
729
+ - avoid races with file lock
730
+
731
+ ### Storage assumptions
732
+
733
+ The design assumes the following layout:
734
+
735
+ - `~/.qwen/oauth_creds.json` — active credential
736
+ - `~/.qwen/accounts/oauth_creds_<n>.json` — account pool
737
+ - `~/.qwen/state.yaml` — rotation state
738
+ - `/tmp/qwen_rotation.lock` — lock file used by account manager
739
+
740
+ ### Why this matters for script-specialists
741
+
742
+ Every script-specialist consumer ultimately depends on this wrapper behavior. If the Qwen CLI changes:
743
+
744
+ - flags
745
+ - output patterns
746
+ - auth file layout
747
+ - refresh behavior
748
+ - model naming
749
+
750
+ then the legacy specialist stack breaks even if the YAML files remain valid.
751
+
752
+ ---
753
+
754
+ ## Container / Infra Wiring
755
+
756
+ File:
757
+
758
+ - `ingestion/infra/docker-compose.yml`
759
+
760
+ ### Volume mount contract
761
+
762
+ The legacy specialist registry is mounted into consuming containers as:
763
+
764
+ ```yaml
765
+ - ../../specialists:/app/specialists:ro
766
+ ```
767
+
768
+ This appears on:
769
+
770
+ - `ext-official-documents`
771
+ - `ext-summarizer`
772
+ - `ext-squawk-summarizer`
773
+ - some adjacent services
774
+
775
+ ### qwen-service contract
776
+
777
+ Consuming services rely on:
778
+
779
+ ```yaml
780
+ - QWEN_SERVICE_URL=http://qwen-service:8000
781
+ ```
782
+
783
+ ### Operational pattern
784
+
785
+ The legacy system is therefore **volume-driven** and **restart-applied**:
786
+
787
+ 1. edit YAML on host
788
+ 2. container sees file via read-only mount
789
+ 3. restart service/container
790
+ 4. service reloads specialist at startup
791
+
792
+ This is often described as "hot reload", but it is not live in-process auto-reload.
793
+
794
+ ---
795
+
796
+ ## Detailed End-to-End Flows
797
+
798
+ ## Flow A — Article summarization
799
+
800
+ ```mermaid
801
+ sequenceDiagram
802
+ participant DB as articles table
803
+ participant S as ingestion/summarizer.py
804
+ participant L as SpecialistLoader
805
+ participant Y as mercury-atomic-summarizer YAML
806
+ participant Q as shared.qwen_client
807
+ participant G as qwen-service
808
+ participant C as qwen CLI
809
+
810
+ S->>L: load("mercury-atomic-summarizer")
811
+ L->>Y: parse + validate
812
+ S->>DB: fetch pending articles
813
+ S->>L: render_prompt(sender,title,content,...)
814
+ S->>Q: generate(prompt)
815
+ Q->>G: POST /generate
816
+ G->>C: run qwen CLI
817
+ C-->>G: output
818
+ G-->>Q: JSON result
819
+ Q-->>S: {success, output, error_type}
820
+ S->>L: validate_output(cleaned_json)
821
+ S->>DB: save summary JSONB
822
+ ```
823
+
824
+ ## Flow B — Official document analysis
825
+
826
+ ```mermaid
827
+ sequenceDiagram
828
+ participant M as Gmail messages
829
+ participant O as ingestion/official_docs.py
830
+ participant L as SpecialistLoader
831
+ participant Y as official-document-analyzer YAML
832
+ participant G as qwen-service
833
+ participant DB as articles table
834
+
835
+ O->>L: load("official-document-analyzer")
836
+ L->>Y: parse + validate
837
+ O->>M: fetch and parse emails
838
+ O->>L: render_prompt(sender,title,content,...)
839
+ O->>G: POST /generate (direct HTTP)
840
+ G-->>O: JSON result
841
+ O->>L: validate_output(output)
842
+ O->>DB: save article and summary
843
+ ```
844
+
845
+ ## Flow C — Rolling context multi-stage pipeline
846
+
847
+ ```mermaid
848
+ sequenceDiagram
849
+ participant RC as RollingContextAgent
850
+ participant L as SpecialistLoader
851
+ participant E as squawk-rolling-context YAML
852
+ participant C as squawk-event-curator YAML
853
+ participant A as squawk-session-analyst YAML
854
+ participant G as qwen-service
855
+ participant DB as squawk_rolling_context
856
+
857
+ RC->>L: load extractor, curator, analyst
858
+ RC->>DB: fetch recent squawks + last context
859
+ RC->>L: extractor task_template render
860
+ RC->>G: extraction prompt
861
+ G-->>RC: new_events JSON
862
+ RC->>L: validate_output(extractor)
863
+ RC->>L: curator task_template render
864
+ RC->>G: curation prompt
865
+ G-->>RC: curated_events/change_summary
866
+ RC->>L: validate_output(curator)
867
+ RC->>L: analyst normalize_template render
868
+ RC->>G: synthesis prompt
869
+ G-->>RC: thesis/overview/... JSON
870
+ RC->>L: validate_output(analyst)
871
+ RC->>DB: save processed context row
872
+ ```
873
+
874
+ ---
875
+
876
+ ## Strengths of the Legacy Design
877
+
878
+ ## 1. Clear separation of prompt logic from application logic
879
+
880
+ Service code owns:
881
+
882
+ - data retrieval
883
+ - truncation
884
+ - variable assembly
885
+ - persistence
886
+
887
+ Specialist YAML owns:
888
+
889
+ - system prompt
890
+ - task instructions
891
+ - output contract
892
+
893
+ ## 2. Fast iteration on prompts
894
+
895
+ Because `specialists/` is mounted into containers, prompt changes do not require code changes.
896
+
897
+ ## 3. Startup-time safety via Pydantic
898
+
899
+ Malformed YAML fails early.
900
+
901
+ ## 4. Good fit for domain-specific scripted tasks
902
+
903
+ The pattern works well for:
904
+
905
+ - article summarization
906
+ - policy document analysis
907
+ - structured extraction
908
+ - deterministic script pipelines that need prompt externalization
909
+
910
+ ## 5. Rolling context proved the concept can scale to multi-stage prompting
911
+
912
+ Even though the runtime is simple, the staged use in `rolling_context.py` demonstrates that a specialist registry can support richer chains.
913
+
914
+ ---
915
+
916
+ ## Real Design Limits and Mismatches
917
+
918
+ ## 1. `execution` is mostly declarative, not operative
919
+
920
+ This is the biggest architectural mismatch.
921
+
922
+ The YAML exposes:
923
+
924
+ - `model`
925
+ - `temperature`
926
+ - `max_tokens`
927
+ - `fallback_model`
928
+
929
+ But in the main runtime path:
930
+
931
+ - `shared.qwen_client.QwenClient.generate()` only sends `prompt` and `timeout`
932
+
933
+ That means the specialist execution block is largely **not enforced** for the main consumers.
934
+
935
+ ### Consequence
936
+
937
+ The system *looks* like a full execution config layer, but operationally it is mostly a prompt/config registry.
938
+
939
+ ## 2. Direct and shared call paths diverge
940
+
941
+ There are two LLM transport patterns:
942
+
943
+ - shared client (`QwenClient`)
944
+ - direct `requests.post()`
945
+
946
+ That means behavior is not fully centralized.
947
+
948
+ ## 3. Runtime output validation is shallow
949
+
950
+ The loader checks required fields, but not the full JSON schema contract.
951
+
952
+ ### Consequence
953
+
954
+ Specialists can declare rich schemas, but runtime enforcement is weaker than the YAML suggests.
955
+
956
+ ## 4. Hot reload is restart-based, not live
957
+
958
+ The implementation supports:
959
+
960
+ - edit YAML
961
+ - restart process/container
962
+ - reload at startup
963
+
964
+ It does not provide live watches or in-process reload triggers.
965
+
966
+ ## 5. The design is tightly coupled to qwen-service internals
967
+
968
+ The entire stack assumes:
969
+
970
+ - qwen CLI exists
971
+ - CLI flags remain stable
972
+ - CLI output patterns are classifiable by substring checks
973
+ - OAuth files live in the expected shape
974
+ - model names remain stable
975
+
976
+ When Qwen changes behavior, script-specialists break at the transport layer even if the specialist configs are fine.
977
+
978
+ ## 6. The schema/doc story has drifted ahead of the actual implementation
979
+
980
+ `.serena/memories/specialist-system_ssot.md` describes a richer pipeline:
981
+
982
+ - normalize phase
983
+ - field-drift correction
984
+ - word-count checks
985
+ - more advanced validation semantics
986
+
987
+ But `shared/specialist_system/loader.py` is much simpler.
988
+
989
+ ### Consequence
990
+
991
+ The conceptual docs describe a more mature system than the actual loader/runtime currently implements.
992
+
993
+ ## 7. The repo now contains two overlapping specialist concepts
994
+
995
+ Legacy:
996
+
997
+ - `specialists/*.specialist.yaml`
998
+
999
+ New:
1000
+
1001
+ - `.specialists/*.specialist.json`
1002
+
1003
+ There is also UX overlap: hooks and docs increasingly describe the newer system, while runtime services still depend on the older one.
1004
+
1005
+ ---
1006
+
1007
+ ## Testing and Operational Evidence
1008
+
1009
+ ## Specialist system tests
1010
+
1011
+ File:
1012
+
1013
+ - `specialists/test/test_specialist_system.py`
1014
+
1015
+ Confirms the legacy loader can:
1016
+
1017
+ - load specialists
1018
+ - render prompts
1019
+ - validate basic output
1020
+ - list specialists
1021
+
1022
+ ## Rolling-context specialist tests
1023
+
1024
+ File:
1025
+
1026
+ - `tests/test_rolling_context_specialists.py`
1027
+
1028
+ This is important because it shows the intended boundary behavior of the legacy multi-specialist pipeline:
1029
+
1030
+ - multiple specialists load together
1031
+ - invalid curator output falls back safely
1032
+ - extraction retries once on invalid output
1033
+ - synthesis candidate validation enforces topical grounding
1034
+ - source-coverage and degraded input metadata are computed
1035
+
1036
+ ## qwen client tests
1037
+
1038
+ File:
1039
+
1040
+ - `tests/test_qwen_client.py`
1041
+
1042
+ Confirms:
1043
+
1044
+ - URL configuration
1045
+ - HTTP request shape
1046
+ - timeout behavior
1047
+ - health check behavior
1048
+ - Prometheus metric emission
1049
+
1050
+ ## qwen wrapper tests
1051
+
1052
+ File:
1053
+
1054
+ - `llm_gateway/tests/test_wrapper.py`
1055
+
1056
+ Confirms:
1057
+
1058
+ - quota/auth/safety error classification
1059
+ - rotation logic
1060
+ - retry behavior
1061
+ - auth-failure clearing
1062
+
1063
+ ---
1064
+
1065
+ ## Architectural Interpretation
1066
+
1067
+ The legacy script-specialists design should be interpreted as a **four-layer system**:
1068
+
1069
+ ### Layer 1 — Config registry
1070
+ Filesystem YAML specialists.
1071
+
1072
+ ### Layer 2 — Local runtime adapter
1073
+ `SpecialistLoader` parses, validates, renders, and lightly validates outputs.
1074
+
1075
+ ### Layer 3 — Service-specific orchestration
1076
+ Each Python service decides:
1077
+
1078
+ - what variables to inject
1079
+ - when to call the LLM
1080
+ - how to parse results
1081
+ - how to handle fallbacks
1082
+ - how to persist output
1083
+
1084
+ ### Layer 4 — Shared LLM gateway
1085
+ `qwen-service` abstracts CLI execution and credential rotation.
1086
+
1087
+ This means the legacy system is **not** a standalone runtime platform. It is a **thin config layer embedded into service code**.
1088
+
1089
+ ---
1090
+
1091
+ ## Contrast With the Newer `.specialists` System
1092
+
1093
+ The newer system under `.specialists/` introduces concepts absent from the script-specialists design:
1094
+
1095
+ - specialist jobs
1096
+ - background runs
1097
+ - keep-alive interactions
1098
+ - worktree isolation
1099
+ - nodes and coordinators
1100
+ - hook-driven notifications
1101
+ - reusable reviewer/executor patterns
1102
+ - JSON specialist definitions aligned to an agent platform
1103
+
1104
+ By contrast, legacy script-specialists provide only:
1105
+
1106
+ - config file discovery
1107
+ - template rendering
1108
+ - shallow schema checking
1109
+
1110
+ ### Practical implication
1111
+
1112
+ A migration from script-specialists to the new system is **not** just a file-format rewrite. It is a shift from:
1113
+
1114
+ - prompt templates consumed by services
1115
+
1116
+ to:
1117
+
1118
+ - a richer specialist runtime/orchestration platform
1119
+
1120
+ That migration requires decisions about:
1121
+
1122
+ - how services invoke specialists
1123
+ - whether specialists remain in-process/config-driven or become external runtime entities
1124
+ - how execution config is actually enforced
1125
+ - whether qwen-service remains the transport layer or is replaced
1126
+
1127
+ ---
1128
+
1129
+ ## Key Findings for Refactor Planning
1130
+
1131
+ ## Finding 1
1132
+ The legacy system is still structurally important.
1133
+
1134
+ It is not dead code. It is active in:
1135
+
1136
+ - `ingestion/summarizer.py`
1137
+ - `ingestion/official_docs.py`
1138
+ - `squawks/rolling_context.py`
1139
+
1140
+ ## Finding 2
1141
+ The biggest hidden debt is the **illusion of execution control**.
1142
+
1143
+ Specialists declare execution parameters that are not consistently honored.
1144
+
1145
+ ## Finding 3
1146
+ The main fragility is now **qwen-service coupling**, not YAML itself.
1147
+
1148
+ The YAML loader is simple and stable. The unstable piece is the Qwen transport/execution substrate.
1149
+
1150
+ ## Finding 4
1151
+ Rolling context is the hardest migration case.
1152
+
1153
+ It already behaves like a multi-stage orchestration pipeline while still using the simple legacy loader.
1154
+
1155
+ ## Finding 5
1156
+ The repository has a **conceptual split-brain** around the word "specialists".
1157
+
1158
+ Any refactor should explicitly resolve the distinction between:
1159
+
1160
+ - runtime script/service specialists
1161
+ - agent/orchestration specialists
1162
+
1163
+ ---
1164
+
1165
+ ## Recommended Mental Model
1166
+
1167
+ If you need one sentence to explain the current script-specialists design:
1168
+
1169
+ > The current script-specialists system is a YAML-backed prompt/config registry for Python services, loaded via a lightweight Pydantic/Template runtime, with actual LLM execution delegated to qwen-service.
1170
+
1171
+ And if you need one sentence about its main limitation:
1172
+
1173
+ > It looks like a full specialist execution framework, but in reality it is mostly a prompt registry layered on top of service code and a fragile qwen-service transport.
1174
+
1175
+ ---
1176
+
1177
+ ## Appendix A — Active Legacy Specialists
1178
+
1179
+ ### `mercury-atomic-summarizer`
1180
+ Used by article summarization pipeline.
1181
+
1182
+ ### `official-document-analyzer`
1183
+ Used by official government document importer.
1184
+
1185
+ ### `squawk-rolling-context`
1186
+ Extractor stage for rolling context.
1187
+
1188
+ ### `squawk-event-curator`
1189
+ Event curation stage for rolling context.
1190
+
1191
+ ### `squawk-session-analyst`
1192
+ Session synthesis stage for rolling context.
1193
+
1194
+ ---
1195
+
1196
+ ## Appendix B — Current Consumer Matrix
1197
+
1198
+ | Consumer | Specialist(s) | Call path | Output target |
1199
+ |---|---|---|---|
1200
+ | `ingestion/summarizer.py` | `mercury-atomic-summarizer` | `shared.qwen_client.QwenClient` | `articles.summary` |
1201
+ | `ingestion/official_docs.py` | `official-document-analyzer` | direct HTTP to qwen-service | article summary / DB |
1202
+ | `squawks/rolling_context.py` | `squawk-rolling-context`, `squawk-event-curator`, `squawk-session-analyst` | direct HTTP helper to qwen-service | `squawk_rolling_context.processed_data` |
1203
+
1204
+ ---
1205
+
1206
+ ## Appendix C — Current Runtime Reality vs Declared Model
1207
+
1208
+ | Area | Declared by design | Actual current behavior |
1209
+ |---|---|---|
1210
+ | Specialist config | full structured runtime config | mostly prompt + metadata + nominal execution hints |
1211
+ | Execution settings | model/temperature/max_tokens specialist-specific | mostly ignored on main client path |
1212
+ | Output schema validation | JSON-schema-like contract | required-fields-only check in practice |
1213
+ | Hot reload | implied quick prompt iteration | edit + container restart |
1214
+ | Orchestration | specialist-defined behavior | still owned mostly by Python service code |
1215
+ | LLM backend independence | specialist abstracted from model transport | tightly coupled to qwen-service/qwen CLI assumptions |
1216
+
1217
+ ---
1218
+
1219
+ ## Appendix D — Files Most Relevant to Any Migration
1220
+
1221
+ ### Must-read
1222
+
1223
+ - `shared/specialist_system/loader.py`
1224
+ - `shared/specialist_system/schema.py`
1225
+ - `shared/qwen_client.py`
1226
+ - `ingestion/summarizer.py`
1227
+ - `ingestion/official_docs.py`
1228
+ - `squawks/rolling_context.py`
1229
+ - `llm_gateway/src/llm_gateway/main.py`
1230
+ - `llm_gateway/src/llm_gateway/wrapper.py`
1231
+ - `llm_gateway/src/llm_gateway/manager.py`
1232
+ - `ingestion/infra/docker-compose.yml`
1233
+
1234
+ ### Useful context
1235
+
1236
+ - `specialists/SPECIALIST_SYSTEM_IMPLEMENTATION.md`
1237
+ - `docs/guides/qwen-service-integration-guide.md`
1238
+ - `tests/test_rolling_context_specialists.py`
1239
+ - `.serena/memories/specialist-system_ssot.md`
1240
+
1241
+ ---
1242
+
1243
+ ## Closing Assessment
1244
+
1245
+ The script-specialists design was a strong and pragmatic step: it externalized prompt logic, enabled fast iteration, and proved especially useful in ingestion and rolling-context services. But the system has now outgrown its original shape.
1246
+
1247
+ Today it sits in an in-between state:
1248
+
1249
+ - more structured than hardcoded prompts
1250
+ - less capable than the newer specialist runtime
1251
+ - increasingly constrained by qwen-service assumptions
1252
+ - partially mismatched between declared configuration and actual execution behavior
1253
+
1254
+ That makes this a good moment to replace or adapt it — especially because the brittle part is no longer the YAML concept itself, but the old execution substrate and the conceptual split with the newer `.specialists` platform.