agent-toolkit-cli 1.11.0__py3-none-win_amd64.whl

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 (438) hide show
  1. agent_toolkit/__init__.py +4 -0
  2. agent_toolkit/__main__.py +5 -0
  3. agent_toolkit/_paths.py +145 -0
  4. agent_toolkit/bin/.gitkeep +0 -0
  5. agent_toolkit/bin/agent-toolkit.exe +0 -0
  6. agent_toolkit/cli/__init__.py +0 -0
  7. agent_toolkit/cli/__main__.py +5 -0
  8. agent_toolkit/cli/build.py +278 -0
  9. agent_toolkit/cli/completion.py +297 -0
  10. agent_toolkit/cli/context_budget.py +455 -0
  11. agent_toolkit/cli/devcompanion.py +923 -0
  12. agent_toolkit/cli/devcompanion_queue.py +235 -0
  13. agent_toolkit/cli/diff.py +176 -0
  14. agent_toolkit/cli/doctor.py +1052 -0
  15. agent_toolkit/cli/insights.py +771 -0
  16. agent_toolkit/cli/install.py +706 -0
  17. agent_toolkit/cli/main.py +171 -0
  18. agent_toolkit/cli/mcp.py +537 -0
  19. agent_toolkit/cli/memory.py +739 -0
  20. agent_toolkit/cli/plugin.py +224 -0
  21. agent_toolkit/cli/project.py +459 -0
  22. agent_toolkit/cli/release.py +178 -0
  23. agent_toolkit/cli/skills.py +461 -0
  24. agent_toolkit/cli/uninstall.py +166 -0
  25. agent_toolkit/cli/update.py +298 -0
  26. agent_toolkit/cli/workspace.py +1713 -0
  27. agent_toolkit/compiler/hook_registry.py +110 -0
  28. agent_toolkit/compiler/loader.py +338 -0
  29. agent_toolkit/compiler/mcp_registry.py +87 -0
  30. agent_toolkit/compiler/model.py +182 -0
  31. agent_toolkit/compiler/provenance.py +140 -0
  32. agent_toolkit/compiler/registry_emit.py +263 -0
  33. agent_toolkit/compiler/target_registry.py +122 -0
  34. agent_toolkit/compiler/targets/__init__.py +1 -0
  35. agent_toolkit/compiler/targets/agent_plugins.py +160 -0
  36. agent_toolkit/compiler/targets/base.py +229 -0
  37. agent_toolkit/compiler/targets/claude_code.py +241 -0
  38. agent_toolkit/compiler/targets/codex.py +261 -0
  39. agent_toolkit/compiler/targets/copilot.py +275 -0
  40. agent_toolkit/compiler/targets/cursor.py +207 -0
  41. agent_toolkit/compiler/targets/gemini_cli.py +213 -0
  42. agent_toolkit/compiler/targets/muse_code.py +113 -0
  43. agent_toolkit/compiler/targets/opencode.py +204 -0
  44. agent_toolkit/compiler/targets/pi.py +263 -0
  45. agent_toolkit/compiler/targets/windsurf.py +267 -0
  46. agent_toolkit/compiler/tool_mapping.py +83 -0
  47. agent_toolkit/data/.gitignore +4 -0
  48. agent_toolkit/data/__init__.py +1 -0
  49. agent_toolkit/data/agents/agentic-security-reviewer/AGENT.md +60 -0
  50. agent_toolkit/data/agents/architect/AGENT.md +30 -0
  51. agent_toolkit/data/agents/assistant/AGENT.md +59 -0
  52. agent_toolkit/data/agents/build-error-resolver/AGENT.md +30 -0
  53. agent_toolkit/data/agents/client-workflow-bootstrap/AGENT.md +60 -0
  54. agent_toolkit/data/agents/code-reviewer/AGENT.md +49 -0
  55. agent_toolkit/data/agents/database-reviewer/AGENT.md +44 -0
  56. agent_toolkit/data/agents/docs-lookup/AGENT.md +28 -0
  57. agent_toolkit/data/agents/e2e-runner/AGENT.md +38 -0
  58. agent_toolkit/data/agents/performance-optimizer/AGENT.md +52 -0
  59. agent_toolkit/data/agents/planner/AGENT.md +41 -0
  60. agent_toolkit/data/agents/refactor-cleaner/AGENT.md +43 -0
  61. agent_toolkit/data/agents/reference-lookup/AGENT.md +33 -0
  62. agent_toolkit/data/agents/security-reviewer/AGENT.md +47 -0
  63. agent_toolkit/data/agents/tdd-guide/AGENT.md +58 -0
  64. agent_toolkit/data/agents/tech-assistant/AGENT.md +11 -0
  65. agent_toolkit/data/agents/typescript-reviewer/AGENT.md +61 -0
  66. agent_toolkit/data/capabilities/hooks/README.md +6 -0
  67. agent_toolkit/data/capabilities/hooks/pre-commit-validate.yaml +26 -0
  68. agent_toolkit/data/capabilities/hooks/scripts/pre-commit-validate.sh +41 -0
  69. agent_toolkit/data/capabilities/hooks/scripts/session-start-context.sh +11 -0
  70. agent_toolkit/data/capabilities/hooks/session-start-context.yaml +23 -0
  71. agent_toolkit/data/capabilities/targets/registry.yaml +90 -0
  72. agent_toolkit/data/capabilities/upstream.lock +118 -0
  73. agent_toolkit/data/catalogs/agent-catalog.yaml +81 -0
  74. agent_toolkit/data/catalogs/loop-catalog.yaml +55 -0
  75. agent_toolkit/data/catalogs/skill-catalog.yaml +520 -0
  76. agent_toolkit/data/catalogs/skills-layout.json +391 -0
  77. agent_toolkit/data/distributions/products.yaml +190 -0
  78. agent_toolkit/data/distributions/targets/claude-code.yaml +47 -0
  79. agent_toolkit/data/distributions/targets/cursor.yaml +42 -0
  80. agent_toolkit/data/distributions/targets/opencode.yaml +55 -0
  81. agent_toolkit/data/loops/changelog-drafter/loop.yaml +40 -0
  82. agent_toolkit/data/loops/ci-sweeper/loop.yaml +53 -0
  83. agent_toolkit/data/loops/daily-triage/loop.yaml +47 -0
  84. agent_toolkit/data/loops/dep-sweeper/loop.yaml +46 -0
  85. agent_toolkit/data/loops/issue-triage/loop.yaml +40 -0
  86. agent_toolkit/data/loops/oss-daily-briefing/loop.yaml +65 -0
  87. agent_toolkit/data/loops/oss-pr-monitor/loop.yaml +86 -0
  88. agent_toolkit/data/loops/oss-triage/loop.yaml +67 -0
  89. agent_toolkit/data/loops/post-merge-cleanup/loop.yaml +44 -0
  90. agent_toolkit/data/loops/pr-babysitter/loop.yaml +46 -0
  91. agent_toolkit/data/mcp/registry/chrome-devtools.yaml +61 -0
  92. agent_toolkit/data/mcp/registry/clickup.yaml +48 -0
  93. agent_toolkit/data/mcp/registry/figma.yaml +44 -0
  94. agent_toolkit/data/mcp/registry/github.yaml +52 -0
  95. agent_toolkit/data/mcp/registry/linear.yaml +47 -0
  96. agent_toolkit/data/mcp/registry/notion.yaml +48 -0
  97. agent_toolkit/data/mcp/registry/slack.yaml +46 -0
  98. agent_toolkit/data/mcp/templates/chrome-devtools/README.md +57 -0
  99. agent_toolkit/data/mcp/templates/chrome-devtools/config.template.json +6 -0
  100. agent_toolkit/data/mcp/templates/clickup/README.md +45 -0
  101. agent_toolkit/data/mcp/templates/clickup/config.template.json +8 -0
  102. agent_toolkit/data/mcp/templates/clickup/wrapper.sh +23 -0
  103. agent_toolkit/data/mcp/templates/figma/README.md +54 -0
  104. agent_toolkit/data/mcp/templates/figma/config.template.json +9 -0
  105. agent_toolkit/data/mcp/templates/github/README.md +16 -0
  106. agent_toolkit/data/mcp/templates/github/config.template.json +15 -0
  107. agent_toolkit/data/mcp/templates/github/wrapper.sh +6 -0
  108. agent_toolkit/data/mcp/templates/linear/README.md +49 -0
  109. agent_toolkit/data/mcp/templates/linear/config.template.json +10 -0
  110. agent_toolkit/data/mcp/templates/notion/README.md +7 -0
  111. agent_toolkit/data/mcp/templates/notion/config.template.json +8 -0
  112. agent_toolkit/data/mcp/templates/notion/wrapper.sh +23 -0
  113. agent_toolkit/data/mcp/templates/slack/README.md +8 -0
  114. agent_toolkit/data/mcp/templates/slack/config.template.json +9 -0
  115. agent_toolkit/data/mcp/templates/slack/wrapper.sh +23 -0
  116. agent_toolkit/data/packs/README.md +66 -0
  117. agent_toolkit/data/packs/agentic-security/README.md +19 -0
  118. agent_toolkit/data/packs/agentic-security/config.yaml +25 -0
  119. agent_toolkit/data/packs/architecture/README.md +22 -0
  120. agent_toolkit/data/packs/architecture/config.yaml +27 -0
  121. agent_toolkit/data/packs/code-quality/README.md +19 -0
  122. agent_toolkit/data/packs/code-quality/config.yaml +21 -0
  123. agent_toolkit/data/packs/delivery-discipline/README.md +19 -0
  124. agent_toolkit/data/packs/delivery-discipline/config.yaml +42 -0
  125. agent_toolkit/data/packs/design-engineering/README.md +19 -0
  126. agent_toolkit/data/packs/design-engineering/config.yaml +41 -0
  127. agent_toolkit/data/packs/engineering-workflow/README.md +21 -0
  128. agent_toolkit/data/packs/engineering-workflow/config.yaml +57 -0
  129. agent_toolkit/data/packs/oss-maintenance/README.md +245 -0
  130. agent_toolkit/data/packs/oss-maintenance/config.yaml +75 -0
  131. agent_toolkit/data/profiles/claude-code/CLAUDE.md +110 -0
  132. agent_toolkit/data/profiles/claude-code/agents/assistant.md +59 -0
  133. agent_toolkit/data/profiles/claude-code/agents/build-error-resolver.md +30 -0
  134. agent_toolkit/data/profiles/claude-code/agents/client-workflow-bootstrap.md +60 -0
  135. agent_toolkit/data/profiles/claude-code/agents/contribution-planner.md +39 -0
  136. agent_toolkit/data/profiles/claude-code/agents/database-reviewer.md +44 -0
  137. agent_toolkit/data/profiles/claude-code/agents/docs-lookup.md +28 -0
  138. agent_toolkit/data/profiles/claude-code/agents/e2e-runner.md +38 -0
  139. agent_toolkit/data/profiles/claude-code/agents/performance-optimizer.md +52 -0
  140. agent_toolkit/data/profiles/claude-code/agents/planner.md +41 -0
  141. agent_toolkit/data/profiles/claude-code/agents/refactor-cleaner.md +43 -0
  142. agent_toolkit/data/profiles/claude-code/agents/reference-lookup.md +33 -0
  143. agent_toolkit/data/profiles/claude-code/agents/security-reviewer.md +47 -0
  144. agent_toolkit/data/profiles/claude-code/agents/tdd-guide.md +58 -0
  145. agent_toolkit/data/profiles/claude-code/agents/typescript-reviewer.md +61 -0
  146. agent_toolkit/data/profiles/claude-code/settings.json +86 -0
  147. agent_toolkit/data/profiles/copilot/copilot-instructions.md +15 -0
  148. agent_toolkit/data/profiles/cursor/README.md +33 -0
  149. agent_toolkit/data/profiles/cursor/rules/architect.mdc +23 -0
  150. agent_toolkit/data/profiles/cursor/rules/assistant.mdc +61 -0
  151. agent_toolkit/data/profiles/cursor/rules/build-error-resolver.mdc +20 -0
  152. agent_toolkit/data/profiles/cursor/rules/code-reviewer.mdc +21 -0
  153. agent_toolkit/data/profiles/cursor/rules/database-reviewer.mdc +29 -0
  154. agent_toolkit/data/profiles/cursor/rules/docs-lookup.mdc +15 -0
  155. agent_toolkit/data/profiles/cursor/rules/e2e-runner.mdc +30 -0
  156. agent_toolkit/data/profiles/cursor/rules/performance-optimizer.mdc +27 -0
  157. agent_toolkit/data/profiles/cursor/rules/planner.mdc +28 -0
  158. agent_toolkit/data/profiles/cursor/rules/refactor-cleaner.mdc +26 -0
  159. agent_toolkit/data/profiles/cursor/rules/reference-lookup.mdc +20 -0
  160. agent_toolkit/data/profiles/cursor/rules/security-reviewer.mdc +20 -0
  161. agent_toolkit/data/profiles/cursor/rules/tdd-guide.mdc +26 -0
  162. agent_toolkit/data/profiles/cursor/rules/typescript-reviewer.mdc +28 -0
  163. agent_toolkit/data/profiles/muse-code/README.md +35 -0
  164. agent_toolkit/data/profiles/opencode/README.md +44 -0
  165. agent_toolkit/data/profiles/opencode/agents/architect.md +30 -0
  166. agent_toolkit/data/profiles/opencode/agents/assistant.md +96 -0
  167. agent_toolkit/data/profiles/opencode/agents/build-error-resolver.md +31 -0
  168. agent_toolkit/data/profiles/opencode/agents/client-workflow-bootstrap.md +66 -0
  169. agent_toolkit/data/profiles/opencode/agents/code-reviewer.md +47 -0
  170. agent_toolkit/data/profiles/opencode/agents/contribution-planner.md +44 -0
  171. agent_toolkit/data/profiles/opencode/agents/database-reviewer.md +43 -0
  172. agent_toolkit/data/profiles/opencode/agents/docs-lookup.md +28 -0
  173. agent_toolkit/data/profiles/opencode/agents/e2e-runner.md +33 -0
  174. agent_toolkit/data/profiles/opencode/agents/performance-optimizer.md +34 -0
  175. agent_toolkit/data/profiles/opencode/agents/planner.md +27 -0
  176. agent_toolkit/data/profiles/opencode/agents/refactor-cleaner.md +27 -0
  177. agent_toolkit/data/profiles/opencode/agents/reference-lookup.md +27 -0
  178. agent_toolkit/data/profiles/opencode/agents/security-reviewer.md +27 -0
  179. agent_toolkit/data/profiles/opencode/agents/tdd-guide.md +27 -0
  180. agent_toolkit/data/profiles/opencode/agents/typescript-reviewer.md +30 -0
  181. agent_toolkit/data/profiles/opencode/opencode.json +3 -0
  182. agent_toolkit/data/profiles/pi/skills/architect/skill.md +5 -0
  183. agent_toolkit/data/profiles/pi/skills/assistant/skill.md +3 -0
  184. agent_toolkit/data/profiles/pi/skills/code-reviewer/skill.md +5 -0
  185. agent_toolkit/data/profiles/pi/skills/planner/skill.md +3 -0
  186. agent_toolkit/data/profiles/pi/skills/security-reviewer/skill.md +3 -0
  187. agent_toolkit/data/profiles/windsurf/memories/global_rules.md +114 -0
  188. agent_toolkit/data/profiles/windsurf/rules/architect.mdc +23 -0
  189. agent_toolkit/data/profiles/windsurf/rules/assistant.mdc +61 -0
  190. agent_toolkit/data/profiles/windsurf/rules/build-error-resolver.mdc +20 -0
  191. agent_toolkit/data/profiles/windsurf/rules/code-reviewer.mdc +21 -0
  192. agent_toolkit/data/profiles/windsurf/rules/database-reviewer.mdc +29 -0
  193. agent_toolkit/data/profiles/windsurf/rules/docs-lookup.mdc +15 -0
  194. agent_toolkit/data/profiles/windsurf/rules/e2e-runner.mdc +30 -0
  195. agent_toolkit/data/profiles/windsurf/rules/performance-optimizer.mdc +27 -0
  196. agent_toolkit/data/profiles/windsurf/rules/planner.mdc +28 -0
  197. agent_toolkit/data/profiles/windsurf/rules/refactor-cleaner.mdc +26 -0
  198. agent_toolkit/data/profiles/windsurf/rules/reference-lookup.mdc +20 -0
  199. agent_toolkit/data/profiles/windsurf/rules/security-reviewer.mdc +20 -0
  200. agent_toolkit/data/profiles/windsurf/rules/tdd-guide.mdc +26 -0
  201. agent_toolkit/data/profiles/windsurf/rules/typescript-reviewer.mdc +28 -0
  202. agent_toolkit/data/skills/accessibility/review/SKILL.md +116 -0
  203. agent_toolkit/data/skills/accessibility/review/references/a11y-checklist.md +25 -0
  204. agent_toolkit/data/skills/accessibility/review/references/a11y-findings-template.md +56 -0
  205. agent_toolkit/data/skills/accessibility/review/references/research.md +47 -0
  206. agent_toolkit/data/skills/agentic-security/mcp-audit/SKILL.md +116 -0
  207. agent_toolkit/data/skills/agentic-security/mcp-audit/references/mcp-audit-template.md +51 -0
  208. agent_toolkit/data/skills/agentic-security/owasp-agentic-review/SKILL.md +73 -0
  209. agent_toolkit/data/skills/agentic-security/owasp-agentic-review/references/owasp-agentic-template.md +32 -0
  210. agent_toolkit/data/skills/agentic-security/supply-chain-audit/SKILL.md +142 -0
  211. agent_toolkit/data/skills/agentic-security/threat-modeling/SKILL.md +100 -0
  212. agent_toolkit/data/skills/agentic-security/threat-modeling/references/threat-model-template.md +55 -0
  213. agent_toolkit/data/skills/architecture/c4-model/SKILL.md +49 -0
  214. agent_toolkit/data/skills/cloud/aws-well-architected-review/SKILL.md +37 -0
  215. agent_toolkit/data/skills/cloud/cloud-design-patterns/SKILL.md +38 -0
  216. agent_toolkit/data/skills/core/assistant/SKILL.md +216 -0
  217. agent_toolkit/data/skills/core/assistant/references/AGENTS_TEMPLATE.md +0 -0
  218. agent_toolkit/data/skills/core/assistant/references/ORCHESTRATION.md +0 -0
  219. agent_toolkit/data/skills/core/assistant/references/REPO_INSPECTION.md +0 -0
  220. agent_toolkit/data/skills/core/dev-companion/SKILL.md +65 -0
  221. agent_toolkit/data/skills/core/dev-companion/references/LOOP_GUARDRAILS.md +0 -0
  222. agent_toolkit/data/skills/core/onboarding/SKILL.md +122 -0
  223. agent_toolkit/data/skills/core/output-handshake/SKILL.md +26 -0
  224. agent_toolkit/data/skills/core/pr-fallback/SKILL.md +35 -0
  225. agent_toolkit/data/skills/core/pr-fallback/references/pr-body-default.md +0 -0
  226. agent_toolkit/data/skills/core/project/SKILL.md +89 -0
  227. agent_toolkit/data/skills/core/workspace/SKILL.md +103 -0
  228. agent_toolkit/data/skills/core/workspace-knowledge-sync/SKILL.md +140 -0
  229. agent_toolkit/data/skills/data/dbt-validation/SKILL.md +41 -0
  230. agent_toolkit/data/skills/data/snowflake-validation/SKILL.md +38 -0
  231. agent_toolkit/data/skills/delivery/adr/SKILL.md +56 -0
  232. agent_toolkit/data/skills/delivery/adr/references/default-template.md +35 -0
  233. agent_toolkit/data/skills/delivery/adr/references/example-001-graphql-adoption.md +66 -0
  234. agent_toolkit/data/skills/delivery/agreement/SKILL.md +24 -0
  235. agent_toolkit/data/skills/delivery/agreement/references/default-template.md +17 -0
  236. agent_toolkit/data/skills/delivery/agreement/references/example-api-versioning.md +29 -0
  237. agent_toolkit/data/skills/delivery/bug/SKILL.md +26 -0
  238. agent_toolkit/data/skills/delivery/bug/references/default-template.md +26 -0
  239. agent_toolkit/data/skills/delivery/bug/references/example-search-filter-bug.md +58 -0
  240. agent_toolkit/data/skills/delivery/decision-log/SKILL.md +28 -0
  241. agent_toolkit/data/skills/delivery/decision-log/references/default-template.md +17 -0
  242. agent_toolkit/data/skills/delivery/decision-log/references/example-repository-pattern.md +27 -0
  243. agent_toolkit/data/skills/delivery/development-workflow/SKILL.md +34 -0
  244. agent_toolkit/data/skills/delivery/development-workflow/references/default-workflow-checklist.md +44 -0
  245. agent_toolkit/data/skills/delivery/epic/SKILL.md +22 -0
  246. agent_toolkit/data/skills/delivery/epic/references/default-template.md +26 -0
  247. agent_toolkit/data/skills/delivery/epic/references/example-unified-dashboard.md +40 -0
  248. agent_toolkit/data/skills/delivery/incident/SKILL.md +24 -0
  249. agent_toolkit/data/skills/delivery/incident/references/default-template.md +29 -0
  250. agent_toolkit/data/skills/delivery/incident/references/example-payment-outage.md +62 -0
  251. agent_toolkit/data/skills/delivery/management-unit-assessment/SKILL.md +104 -0
  252. agent_toolkit/data/skills/delivery/management-unit-assessment/references/default-template.md +24 -0
  253. agent_toolkit/data/skills/delivery/management-unit-assessment/references/example-team-assessment.md +126 -0
  254. agent_toolkit/data/skills/delivery/meeting-minutes/SKILL.md +25 -0
  255. agent_toolkit/data/skills/delivery/meeting-minutes/references/default-template.md +22 -0
  256. agent_toolkit/data/skills/delivery/meeting-minutes/references/example-weekly-sync.md +72 -0
  257. agent_toolkit/data/skills/delivery/planning/SKILL.md +31 -0
  258. agent_toolkit/data/skills/delivery/planning/references/default-template.md +25 -0
  259. agent_toolkit/data/skills/delivery/planning/references/example-sprint-planning.md +62 -0
  260. agent_toolkit/data/skills/delivery/prd/SKILL.md +46 -0
  261. agent_toolkit/data/skills/delivery/prd/references/default-template.md +31 -0
  262. agent_toolkit/data/skills/delivery/prd/references/example-unified-api.md +71 -0
  263. agent_toolkit/data/skills/delivery/project-assessment/SKILL.md +90 -0
  264. agent_toolkit/data/skills/delivery/project-assessment/references/default-template.md +26 -0
  265. agent_toolkit/data/skills/delivery/project-assessment/references/example-platform-assessment.md +122 -0
  266. agent_toolkit/data/skills/delivery/project-assessment-evidence/SKILL.md +88 -0
  267. agent_toolkit/data/skills/delivery/project-assessment-evidence/references/default-template.md +24 -0
  268. agent_toolkit/data/skills/delivery/project-assessment-evidence/references/example-evidence-map.md +46 -0
  269. agent_toolkit/data/skills/delivery/spike/SKILL.md +24 -0
  270. agent_toolkit/data/skills/delivery/spike/references/default-template.md +29 -0
  271. agent_toolkit/data/skills/delivery/spike/references/example-graphql-federation.md +79 -0
  272. agent_toolkit/data/skills/delivery/task/SKILL.md +21 -0
  273. agent_toolkit/data/skills/delivery/task/references/default-template.md +21 -0
  274. agent_toolkit/data/skills/delivery/task/references/example-nav-system.md +33 -0
  275. agent_toolkit/data/skills/delivery/technical-unit-assessment/SKILL.md +58 -0
  276. agent_toolkit/data/skills/delivery/technical-unit-assessment/references/default-template.md +26 -0
  277. agent_toolkit/data/skills/delivery/technical-unit-assessment/references/example-frontend-assessment.md +112 -0
  278. agent_toolkit/data/skills/delivery/technical-unit-assessment/references/indicator-groups.md +65 -0
  279. agent_toolkit/data/skills/delivery/trd/SKILL.md +49 -0
  280. agent_toolkit/data/skills/delivery/trd/references/default-template.md +31 -0
  281. agent_toolkit/data/skills/delivery/trd/references/example-api-migration.md +122 -0
  282. agent_toolkit/data/skills/delivery/user-story/SKILL.md +21 -0
  283. agent_toolkit/data/skills/delivery/user-story/references/default-template.md +21 -0
  284. agent_toolkit/data/skills/delivery/user-story/references/example-advanced-filtering.md +37 -0
  285. agent_toolkit/data/skills/delivery/work-item/SKILL.md +31 -0
  286. agent_toolkit/data/skills/delivery/work-item/references/default-template.md +21 -0
  287. agent_toolkit/data/skills/delivery/work-item/references/example-routing-dashboard.md +23 -0
  288. agent_toolkit/data/skills/delivery/workflow-client-bootstrap/SKILL.md +148 -0
  289. agent_toolkit/data/skills/delivery/workflow-client-bootstrap/questions.yaml +165 -0
  290. agent_toolkit/data/skills/delivery/workflow-generic-project/SKILL.md +79 -0
  291. agent_toolkit/data/skills/design/design-assessment/SKILL.md +150 -0
  292. agent_toolkit/data/skills/design/design-assessment/references/design-scorecard-template.md +78 -0
  293. agent_toolkit/data/skills/design/design-improvement/SKILL.md +167 -0
  294. agent_toolkit/data/skills/design/design-improvement/references/improvement-plan-template.md +113 -0
  295. agent_toolkit/data/skills/design/figma/LICENSE.txt +2 -0
  296. agent_toolkit/data/skills/design/figma/NOTICE.txt +25 -0
  297. agent_toolkit/data/skills/design/figma/SKILL.md +98 -0
  298. agent_toolkit/data/skills/design/figma/references/figma-mcp-config.md +82 -0
  299. agent_toolkit/data/skills/design/figma/references/figma-tools-and-prompts.md +34 -0
  300. agent_toolkit/data/skills/design/figma-code-connect-components/LICENSE.txt +2 -0
  301. agent_toolkit/data/skills/design/figma-code-connect-components/NOTICE.txt +18 -0
  302. agent_toolkit/data/skills/design/figma-code-connect-components/SKILL.md +354 -0
  303. agent_toolkit/data/skills/design/figma-code-connect-components/references/mapping-checklist.md +7 -0
  304. agent_toolkit/data/skills/design/figma-code-connect-components/scripts/normalize_node_id.py +25 -0
  305. agent_toolkit/data/skills/design/figma-create-design-system-rules/LICENSE.txt +2 -0
  306. agent_toolkit/data/skills/design/figma-create-design-system-rules/NOTICE.txt +19 -0
  307. agent_toolkit/data/skills/design/figma-create-design-system-rules/SKILL.md +554 -0
  308. agent_toolkit/data/skills/design/figma-create-design-system-rules/references/rule-template.md +15 -0
  309. agent_toolkit/data/skills/design/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -0
  310. agent_toolkit/data/skills/design/figma-create-new-file/LICENSE.txt +2 -0
  311. agent_toolkit/data/skills/design/figma-create-new-file/NOTICE.txt +17 -0
  312. agent_toolkit/data/skills/design/figma-create-new-file/SKILL.md +72 -0
  313. agent_toolkit/data/skills/design/figma-implement-design/LICENSE.txt +2 -0
  314. agent_toolkit/data/skills/design/figma-implement-design/NOTICE.txt +19 -0
  315. agent_toolkit/data/skills/design/figma-implement-design/SKILL.md +268 -0
  316. agent_toolkit/data/skills/design/frontend-design/LICENSE.txt +177 -0
  317. agent_toolkit/data/skills/design/frontend-design/SKILL.md +82 -0
  318. agent_toolkit/data/skills/design/frontend-design/UPSTREAM.md +14 -0
  319. agent_toolkit/data/skills/design/frontend-design-review/LICENSE +21 -0
  320. agent_toolkit/data/skills/design/frontend-design-review/SKILL.md +194 -0
  321. agent_toolkit/data/skills/design/frontend-design-review/references/pattern-examples.md +21 -0
  322. agent_toolkit/data/skills/design/frontend-design-review/references/quick-checklist.md +38 -0
  323. agent_toolkit/data/skills/design/frontend-design-review/references/review-output-format.md +68 -0
  324. agent_toolkit/data/skills/design/frontend-design-review/references/review-type-modifiers.md +31 -0
  325. agent_toolkit/data/skills/design/web-design-guidelines/SKILL.md +78 -0
  326. agent_toolkit/data/skills/design/web-design-guidelines/references/LICENSE +21 -0
  327. agent_toolkit/data/skills/design/web-design-guidelines/references/web-interface-guidelines.md +180 -0
  328. agent_toolkit/data/skills/forge/gh-address-comments/LICENSE.txt +202 -0
  329. agent_toolkit/data/skills/forge/gh-address-comments/NOTICE.txt +20 -0
  330. agent_toolkit/data/skills/forge/gh-address-comments/SKILL.md +72 -0
  331. agent_toolkit/data/skills/forge/gh-address-comments/scripts/fetch_comments.py +239 -0
  332. agent_toolkit/data/skills/forge/gh-contribution-planner/SKILL.md +160 -0
  333. agent_toolkit/data/skills/forge/gh-contribution-planner/scripts/inspect_contributions.py +818 -0
  334. agent_toolkit/data/skills/forge/gh-fix-ci/LICENSE.txt +201 -0
  335. agent_toolkit/data/skills/forge/gh-fix-ci/NOTICE.txt +20 -0
  336. agent_toolkit/data/skills/forge/gh-fix-ci/SKILL.md +74 -0
  337. agent_toolkit/data/skills/forge/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
  338. agent_toolkit/data/skills/forge/github-cli-workflow/SKILL.md +49 -0
  339. agent_toolkit/data/skills/forge/gitlab-cli-workflow/SKILL.md +44 -0
  340. agent_toolkit/data/skills/forge/workflow-client-bootstrap/SKILL.md +14 -0
  341. agent_toolkit/data/skills/forge/workflow-generic-project/SKILL.md +14 -0
  342. agent_toolkit/data/skills/forge/worktree/SKILL.md +113 -0
  343. agent_toolkit/data/skills/integrations/clickup-cli/SKILL.md +78 -0
  344. agent_toolkit/data/skills/integrations/clickup-cli/references/docs-management.md +57 -0
  345. agent_toolkit/data/skills/integrations/clickup-cli/references/task-management.md +131 -0
  346. agent_toolkit/data/skills/integrations/clickup-cli/references/time-tracking.md +38 -0
  347. agent_toolkit/data/skills/integrations/linear/LICENSE.txt +202 -0
  348. agent_toolkit/data/skills/integrations/linear/NOTICE.txt +23 -0
  349. agent_toolkit/data/skills/integrations/linear/SKILL.md +134 -0
  350. agent_toolkit/data/skills/integrations/mcp/SKILL.md +88 -0
  351. agent_toolkit/data/skills/integrations/slack-assistant/SKILL.md +138 -0
  352. agent_toolkit/data/skills/integrations/slack-cli/SKILL.md +109 -0
  353. agent_toolkit/data/skills/integrations/slack-cli/references/INSTALLATION.md +42 -0
  354. agent_toolkit/data/skills/loops/loop-runner/SKILL.md +92 -0
  355. agent_toolkit/data/skills/ops/docs-generator/SKILL.md +120 -0
  356. agent_toolkit/data/skills/ops/llm-cost-advisor/SKILL.md +87 -0
  357. agent_toolkit/data/skills/ops/swarm/SKILL.md +108 -0
  358. agent_toolkit/data/skills/ops/swarm-handoff/SKILL.md +112 -0
  359. agent_toolkit/data/skills/ops/swarm-observer/SKILL.md +102 -0
  360. agent_toolkit/data/skills/ops/triage/SKILL.md +119 -0
  361. agent_toolkit/data/skills/quality/codeql/SKILL.md +106 -0
  362. agent_toolkit/data/skills/quality/codeql/references/codeql-queries.md +43 -0
  363. agent_toolkit/data/skills/quality/megalinter/SKILL.md +162 -0
  364. agent_toolkit/data/skills/quality/megalinter/references/megalinter-images.md +36 -0
  365. agent_toolkit/data/skills/quality/megalinter/references/megalinter-license.md +41 -0
  366. agent_toolkit/data/skills/quality/megalinter/references/megalinter-targets.md +66 -0
  367. agent_toolkit/data/skills/tooling/chrome-devtools/SKILL.md +146 -0
  368. agent_toolkit/data/skills/tooling/herdr/SKILL.md +109 -0
  369. agent_toolkit/data/skills/tooling/inventory/SKILL.md +81 -0
  370. agent_toolkit/data/skills/tooling/jupyter-notebook/LICENSE.txt +201 -0
  371. agent_toolkit/data/skills/tooling/jupyter-notebook/NOTICE.txt +27 -0
  372. agent_toolkit/data/skills/tooling/jupyter-notebook/SKILL.md +145 -0
  373. agent_toolkit/data/skills/tooling/jupyter-notebook/assets/experiment-template.ipynb +117 -0
  374. agent_toolkit/data/skills/tooling/jupyter-notebook/assets/tutorial-template.ipynb +115 -0
  375. agent_toolkit/data/skills/tooling/jupyter-notebook/references/experiment-patterns.md +10 -0
  376. agent_toolkit/data/skills/tooling/jupyter-notebook/references/notebook-structure.md +17 -0
  377. agent_toolkit/data/skills/tooling/jupyter-notebook/references/quality-checklist.md +11 -0
  378. agent_toolkit/data/skills/tooling/jupyter-notebook/references/tutorial-patterns.md +9 -0
  379. agent_toolkit/data/skills/tooling/jupyter-notebook/scripts/new_notebook.py +132 -0
  380. agent_toolkit/data/skills/tooling/mermaid/SKILL.md +36 -0
  381. agent_toolkit/data/skills/tooling/playwright-cli/LICENSE.txt +201 -0
  382. agent_toolkit/data/skills/tooling/playwright-cli/NOTICE.txt +29 -0
  383. agent_toolkit/data/skills/tooling/playwright-cli/SKILL.md +154 -0
  384. agent_toolkit/data/skills/tooling/playwright-cli/references/cli.md +116 -0
  385. agent_toolkit/data/skills/tooling/playwright-cli/references/workflows.md +98 -0
  386. agent_toolkit/data/skills/tooling/playwright-cli/scripts/executable_playwright_cli.sh +25 -0
  387. agent_toolkit/data_cache.py +79 -0
  388. agent_toolkit/data_sync.py +144 -0
  389. agent_toolkit/installer/__init__.py +0 -0
  390. agent_toolkit/installer/merge.py +59 -0
  391. agent_toolkit/installer/receipt.py +89 -0
  392. agent_toolkit/installer/sources.py +92 -0
  393. agent_toolkit/installer/tracking.py +63 -0
  394. agent_toolkit/launcher.py +69 -0
  395. agent_toolkit/loop/__init__.py +0 -0
  396. agent_toolkit/loop/budget.py +107 -0
  397. agent_toolkit/loop/gh_gate.py +923 -0
  398. agent_toolkit/loop/loop-gh-gate +923 -0
  399. agent_toolkit/loop/pack.py +65 -0
  400. agent_toolkit/loop/runner.py +2722 -0
  401. agent_toolkit/runner/__init__.py +0 -0
  402. agent_toolkit/runner/dispatcher.py +163 -0
  403. agent_toolkit/runner/policy.py +356 -0
  404. agent_toolkit/runner/providers/__init__.py +21 -0
  405. agent_toolkit/runner/providers/anthropic_provider.py +109 -0
  406. agent_toolkit/runner/providers/base.py +53 -0
  407. agent_toolkit/runner/providers/ollama_provider.py +108 -0
  408. agent_toolkit/runner/providers/openai_provider.py +103 -0
  409. agent_toolkit/runner/providers/opencode_provider.py +127 -0
  410. agent_toolkit/swarm/__init__.py +5 -0
  411. agent_toolkit/swarm/approvals.py +121 -0
  412. agent_toolkit/swarm/backends/__init__.py +596 -0
  413. agent_toolkit/swarm/budget.py +83 -0
  414. agent_toolkit/swarm/cli.py +2448 -0
  415. agent_toolkit/swarm/config.py +351 -0
  416. agent_toolkit/swarm/handoff.py +174 -0
  417. agent_toolkit/swarm/models.py +230 -0
  418. agent_toolkit/swarm/prompts.py +177 -0
  419. agent_toolkit/swarm/recipes.py +304 -0
  420. agent_toolkit/swarm/runner.py +267 -0
  421. agent_toolkit/swarm/state.py +93 -0
  422. agent_toolkit/swarm/store.py +148 -0
  423. agent_toolkit/swarm/worktree.py +105 -0
  424. agent_toolkit/templates/workspace/.gitignore +19 -0
  425. agent_toolkit/templates/workspace/AGENTS.md +82 -0
  426. agent_toolkit/templates/workspace/knowledge/README.md +22 -0
  427. agent_toolkit/templates/workspace/knowledge/learnings/general.md +3 -0
  428. agent_toolkit/templates/workspace/knowledge/todos/pending.md +7 -0
  429. agent_toolkit/templates/workspace/packs/README.md +24 -0
  430. agent_toolkit/templates/workspace/personas/architect.md +12 -0
  431. agent_toolkit/templates/workspace/personas/implementer.md +12 -0
  432. agent_toolkit/templates/workspace/personas/researcher.md +12 -0
  433. agent_toolkit/templates/workspace/personas/reviewer.md +12 -0
  434. agent_toolkit_cli-1.11.0.dist-info/METADATA +363 -0
  435. agent_toolkit_cli-1.11.0.dist-info/RECORD +438 -0
  436. agent_toolkit_cli-1.11.0.dist-info/WHEEL +4 -0
  437. agent_toolkit_cli-1.11.0.dist-info/entry_points.txt +4 -0
  438. agent_toolkit_cli-1.11.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1052 @@
1
+ """
2
+ doctor — Check system health, AI tool availability, and Swarm prerequisites.
3
+
4
+ Usage:
5
+ agent-toolkit doctor [options]
6
+
7
+ Options:
8
+ --json Output results as JSON
9
+ --fix Attempt to auto-fix issues (installs missing profiles)
10
+ --provenance Show full provenance report (SHA/commit immutability, expiry >90d)
11
+ --help Show this help message
12
+
13
+ Exit codes:
14
+ 0 — no errors detected
15
+ 1 — one or more errors detected
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ import os
22
+ import pathlib
23
+ import platform
24
+ import shutil
25
+ import subprocess
26
+ import sys
27
+ import urllib.request
28
+ from pathlib import Path
29
+
30
+ from agent_toolkit._paths import toolkit_root
31
+
32
+ # Windows: force UTF-8 output so emoji chars (✓ ✗ ⚠) don't crash
33
+ if sys.platform == "win32":
34
+ try:
35
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[attr-defined]
36
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace") # type: ignore[attr-defined]
37
+ except Exception:
38
+ pass
39
+
40
+
41
+ # ---------------------------------------------------------------------------
42
+ # Result model
43
+ # ---------------------------------------------------------------------------
44
+
45
+
46
+ class CheckResult:
47
+ """A single health-check item."""
48
+
49
+ STATUS_OK = "ok"
50
+ STATUS_WARN = "warn"
51
+ STATUS_ERR = "error"
52
+
53
+ def __init__(self, category: str, name: str, status: str, detail: str = "") -> None:
54
+ self.category = category
55
+ self.name = name
56
+ self.status = status
57
+ self.detail = detail
58
+
59
+ @property
60
+ def icon(self) -> str:
61
+ return {"ok": "✓", "warn": "⚠", "error": "✗"}.get(self.status, "?")
62
+
63
+ def to_dict(self) -> dict:
64
+ return {
65
+ "category": self.category,
66
+ "name": self.name,
67
+ "status": self.status,
68
+ "detail": self.detail,
69
+ }
70
+
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Individual checks
74
+ # ---------------------------------------------------------------------------
75
+
76
+
77
+ def _check_python_version() -> CheckResult:
78
+ vi = sys.version_info
79
+ version_str = f"{vi.major}.{vi.minor}.{vi.micro}"
80
+ if (vi.major, vi.minor) >= (3, 10):
81
+ return CheckResult("system", "python >= 3.10", CheckResult.STATUS_OK, version_str)
82
+ return CheckResult(
83
+ "system", "python >= 3.10", CheckResult.STATUS_ERR, f"Found {version_str} — need 3.10+"
84
+ )
85
+
86
+
87
+ def _check_command(category: str, name: str, cmd: str) -> CheckResult:
88
+ path = shutil.which(cmd)
89
+ if path:
90
+ # Try to get version
91
+ try:
92
+ result = subprocess.run([cmd, "--version"], capture_output=True, text=True, timeout=5)
93
+ version = (result.stdout or result.stderr or "").strip().splitlines()[0]
94
+ except Exception:
95
+ version = path
96
+ return CheckResult(category, name, CheckResult.STATUS_OK, version)
97
+ return CheckResult(category, name, CheckResult.STATUS_ERR, f"'{cmd}' not found in PATH")
98
+
99
+
100
+ def _check_gh_auth() -> CheckResult:
101
+ if shutil.which("gh") is None:
102
+ return CheckResult("system", "gh auth", CheckResult.STATUS_ERR, "'gh' not found in PATH")
103
+ try:
104
+ result = subprocess.run(
105
+ ["gh", "auth", "status"], capture_output=True, text=True, timeout=10
106
+ )
107
+ if result.returncode == 0:
108
+ return CheckResult("system", "gh auth", CheckResult.STATUS_OK, "authenticated")
109
+ return CheckResult(
110
+ "system",
111
+ "gh auth",
112
+ CheckResult.STATUS_WARN,
113
+ "gh installed but not authenticated — run: gh auth login",
114
+ )
115
+ except Exception as exc:
116
+ return CheckResult("system", "gh auth", CheckResult.STATUS_WARN, str(exc))
117
+
118
+
119
+ def _check_ai_tool(name: str, cmd: str) -> CheckResult:
120
+ path = shutil.which(cmd)
121
+ if path:
122
+ return CheckResult("ai_tools", name, CheckResult.STATUS_OK, path)
123
+ return CheckResult(
124
+ "ai_tools", name, CheckResult.STATUS_WARN, f"'{cmd}' not found — tool may not be installed"
125
+ )
126
+
127
+
128
+ def _profile_installed(category: str, name: str, path: Path) -> CheckResult:
129
+ if path.exists():
130
+ return CheckResult(category, name, CheckResult.STATUS_OK, str(path))
131
+ return CheckResult(category, name, CheckResult.STATUS_WARN, f"Not installed: {path}")
132
+
133
+
134
+ def _check_profiles() -> list[CheckResult]:
135
+ """Check whether profiles are installed for each detected tool."""
136
+ results: list[CheckResult] = []
137
+ home = Path.home()
138
+
139
+ # claude-code
140
+ if shutil.which("claude") or (home / ".claude").is_dir():
141
+ results.append(
142
+ _profile_installed("profiles", "claude-code CLAUDE.md", home / ".claude" / "CLAUDE.md")
143
+ )
144
+ # settings.json is user-owned and must not be managed by the installer.
145
+ results.append(
146
+ _profile_installed("profiles", "claude-code agents/", home / ".claude" / "agents")
147
+ )
148
+
149
+ # cursor
150
+ if shutil.which("cursor") or (home / ".cursor").is_dir():
151
+ results.append(_profile_installed("profiles", "cursor rules/", home / ".cursor" / "rules"))
152
+
153
+ # opencode
154
+ if shutil.which("opencode") or (home / ".config" / "opencode").is_dir():
155
+ results.append(
156
+ _profile_installed(
157
+ "profiles", "opencode agents/", home / ".config" / "opencode" / "agents"
158
+ )
159
+ )
160
+ results.append(
161
+ _profile_installed(
162
+ "profiles",
163
+ "opencode opencode.json",
164
+ home / ".config" / "opencode" / "opencode.json",
165
+ )
166
+ )
167
+
168
+ # windsurf
169
+ windsurf_dir: Path | None = None
170
+ if (home / ".codeium" / "windsurf").is_dir():
171
+ windsurf_dir = home / ".codeium" / "windsurf"
172
+ elif (home / ".windsurf").is_dir():
173
+ windsurf_dir = home / ".windsurf"
174
+ elif shutil.which("windsurf"):
175
+ windsurf_dir = home / ".codeium" / "windsurf"
176
+
177
+ if windsurf_dir is not None:
178
+ results.append(_profile_installed("profiles", "windsurf rules/", windsurf_dir / "rules"))
179
+ results.append(
180
+ _profile_installed("profiles", "windsurf memories/", windsurf_dir / "memories")
181
+ )
182
+
183
+ # pi
184
+ if shutil.which("pi") or (home / ".pi").is_dir():
185
+ results.append(
186
+ _profile_installed("profiles", "pi skills/", home / ".pi" / "agent" / "skills")
187
+ )
188
+
189
+ # muse (Meta) — ~/.config/muse/skills and project .agents/skills
190
+ if shutil.which("muse") or (home / ".config" / "muse").is_dir() or (home / ".agents").is_dir():
191
+ results.append(
192
+ _profile_installed(
193
+ "profiles", "muse skills (user)", home / ".config" / "muse" / "skills"
194
+ )
195
+ )
196
+ # project scope: .agents/skills in CWD or workspace root
197
+ # check CWD .agents/skills and toolkit-relative if available
198
+ cwd_agents = Path.cwd() / ".agents" / "skills"
199
+ if cwd_agents.is_dir() or (home / ".agents").is_dir():
200
+ # use CWD if present, else home fallback for display
201
+ agents_path = cwd_agents if cwd_agents.is_dir() else home / ".agents" / "skills"
202
+ results.append(_profile_installed("profiles", "muse skills (project)", agents_path))
203
+ else:
204
+ results.append(
205
+ CheckResult(
206
+ "profiles",
207
+ "muse skills (project)",
208
+ CheckResult.STATUS_WARN,
209
+ "Not found: .agents/skills (project scope — optional)",
210
+ )
211
+ )
212
+
213
+ return results
214
+
215
+
216
+ def _check_loop_runtime(toolkit_dir: Path | None) -> list[CheckResult]:
217
+ results: list[CheckResult] = []
218
+
219
+ # Check if `agent-toolkit loop` resolves (basic import test)
220
+ try:
221
+ subprocess.run(
222
+ [sys.executable, "-m", "agent_toolkit.cli", "loop", "--help"],
223
+ capture_output=True,
224
+ timeout=10,
225
+ )
226
+ results.append(
227
+ CheckResult(
228
+ "loops",
229
+ "loop subcommand",
230
+ CheckResult.STATUS_OK,
231
+ "agent-toolkit loop --help succeeded",
232
+ )
233
+ )
234
+ except Exception as exc:
235
+ results.append(
236
+ CheckResult(
237
+ "loops",
238
+ "loop subcommand",
239
+ CheckResult.STATUS_WARN,
240
+ f"Could not run loop command: {exc}",
241
+ )
242
+ )
243
+
244
+ # Check loops/ templates
245
+ if toolkit_dir:
246
+ loops_dir = toolkit_dir / "loops"
247
+ if loops_dir.is_dir():
248
+ count = sum(1 for d in loops_dir.iterdir() if d.is_dir())
249
+ results.append(
250
+ CheckResult(
251
+ "loops",
252
+ "loop templates",
253
+ CheckResult.STATUS_OK,
254
+ f"{count} template(s) found in {loops_dir}",
255
+ )
256
+ )
257
+ else:
258
+ results.append(
259
+ CheckResult(
260
+ "loops",
261
+ "loop templates",
262
+ CheckResult.STATUS_WARN,
263
+ f"loops/ directory not found at {loops_dir}",
264
+ )
265
+ )
266
+ else:
267
+ results.append(
268
+ CheckResult(
269
+ "loops",
270
+ "loop templates",
271
+ CheckResult.STATUS_WARN,
272
+ "Toolkit directory not found — cannot check loop templates",
273
+ )
274
+ )
275
+
276
+ return results
277
+
278
+
279
+ def _check_llm_providers() -> list[CheckResult]:
280
+ results: list[CheckResult] = []
281
+
282
+ # API keys
283
+ for var in ("ANTHROPIC_API_KEY", "OPENAI_API_KEY"):
284
+ val = os.environ.get(var, "")
285
+ if val:
286
+ masked = val[:8] + "..." if len(val) > 8 else "***"
287
+ results.append(CheckResult("llm", var, CheckResult.STATUS_OK, f"set ({masked})"))
288
+ else:
289
+ results.append(CheckResult("llm", var, CheckResult.STATUS_WARN, "not set"))
290
+
291
+ # Ollama
292
+ try:
293
+ req = urllib.request.Request("http://localhost:11434", method="HEAD")
294
+ req.add_header("User-Agent", "agent-toolkit-doctor/1")
295
+ with urllib.request.urlopen(req, timeout=3):
296
+ pass
297
+ results.append(
298
+ CheckResult("llm", "ollama", CheckResult.STATUS_OK, "running at localhost:11434")
299
+ )
300
+ except Exception:
301
+ results.append(
302
+ CheckResult(
303
+ "llm", "ollama", CheckResult.STATUS_WARN, "not reachable at localhost:11434"
304
+ )
305
+ )
306
+
307
+ # opencode socket (Linux/macOS only — os.getuid() doesn't exist on Windows)
308
+ try:
309
+ uid = os.getuid() # type: ignore[attr-defined]
310
+ except AttributeError:
311
+ uid = 0
312
+ xdg_runtime = os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{uid}")
313
+ socket_paths = [
314
+ Path(xdg_runtime) / "opencode.sock",
315
+ Path.home() / ".config" / "opencode" / "opencode.sock",
316
+ ]
317
+ for sp in socket_paths:
318
+ if sp.exists():
319
+ results.append(CheckResult("llm", "opencode socket", CheckResult.STATUS_OK, str(sp)))
320
+ break
321
+ else:
322
+ results.append(
323
+ CheckResult(
324
+ "llm",
325
+ "opencode socket",
326
+ CheckResult.STATUS_WARN,
327
+ "socket not found (opencode may not be running)",
328
+ )
329
+ )
330
+
331
+ return results
332
+
333
+
334
+ def _check_mcp() -> list[CheckResult]:
335
+ results: list[CheckResult] = []
336
+ config_path = Path.home() / ".config" / "agent-toolkit" / "mcp-config.json"
337
+
338
+ if not config_path.exists():
339
+ results.append(
340
+ CheckResult(
341
+ "mcp",
342
+ "mcp-config.json",
343
+ CheckResult.STATUS_WARN,
344
+ f"Not found: {config_path} (run: agent-toolkit mcp setup <provider>)",
345
+ )
346
+ )
347
+ return results
348
+
349
+ try:
350
+ data = json.loads(config_path.read_text())
351
+ providers = data.get("providers", {})
352
+ if not providers:
353
+ results.append(
354
+ CheckResult(
355
+ "mcp",
356
+ "mcp providers",
357
+ CheckResult.STATUS_WARN,
358
+ "Config exists but no providers configured",
359
+ )
360
+ )
361
+ return results
362
+ for name, cfg in providers.items():
363
+ enabled = cfg.get("enabled", False)
364
+ validated = cfg.get("validated_at", "never")
365
+ status = CheckResult.STATUS_OK if enabled else CheckResult.STATUS_WARN
366
+ results.append(
367
+ CheckResult(
368
+ "mcp",
369
+ f"provider:{name}",
370
+ status,
371
+ f"enabled={enabled}, validated_at={validated}",
372
+ )
373
+ )
374
+ except (json.JSONDecodeError, OSError) as exc:
375
+ results.append(
376
+ CheckResult(
377
+ "mcp", "mcp-config.json", CheckResult.STATUS_ERR, f"Cannot read config: {exc}"
378
+ )
379
+ )
380
+
381
+ return results
382
+
383
+
384
+ def _check_scheduled_loops() -> list[CheckResult]:
385
+ results: list[CheckResult] = []
386
+ system = platform.system()
387
+
388
+ if system == "Linux":
389
+ timer_dir = Path.home() / ".config" / "systemd" / "user"
390
+ if timer_dir.is_dir():
391
+ timers = list(timer_dir.glob("agent-toolkit-*.timer"))
392
+ if timers:
393
+ for t in sorted(timers):
394
+ results.append(CheckResult("scheduled", t.name, CheckResult.STATUS_OK, str(t)))
395
+ else:
396
+ results.append(
397
+ CheckResult(
398
+ "scheduled",
399
+ "systemd timers",
400
+ CheckResult.STATUS_WARN,
401
+ "No agent-toolkit-*.timer files found",
402
+ )
403
+ )
404
+ else:
405
+ results.append(
406
+ CheckResult(
407
+ "scheduled",
408
+ "systemd user dir",
409
+ CheckResult.STATUS_WARN,
410
+ f"Not found: {timer_dir}",
411
+ )
412
+ )
413
+ elif system == "Darwin":
414
+ launchd_dir = Path.home() / "Library" / "LaunchAgents"
415
+ if launchd_dir.is_dir():
416
+ plists = list(launchd_dir.glob("com.agent-toolkit.*.plist"))
417
+ if plists:
418
+ for p in sorted(plists):
419
+ results.append(CheckResult("scheduled", p.name, CheckResult.STATUS_OK, str(p)))
420
+ else:
421
+ results.append(
422
+ CheckResult(
423
+ "scheduled",
424
+ "launchd plists",
425
+ CheckResult.STATUS_WARN,
426
+ "No com.agent-toolkit.*.plist files found",
427
+ )
428
+ )
429
+ else:
430
+ results.append(
431
+ CheckResult(
432
+ "scheduled",
433
+ "LaunchAgents dir",
434
+ CheckResult.STATUS_WARN,
435
+ f"Not found: {launchd_dir}",
436
+ )
437
+ )
438
+ else:
439
+ results.append(
440
+ CheckResult(
441
+ "scheduled",
442
+ "scheduled loops",
443
+ CheckResult.STATUS_WARN,
444
+ f"Unsupported platform: {system}",
445
+ )
446
+ )
447
+
448
+ return results
449
+
450
+
451
+ def _check_swarm() -> list[CheckResult]:
452
+ results: list[CheckResult] = []
453
+
454
+ tmux_path = shutil.which("tmux")
455
+ if tmux_path:
456
+ try:
457
+ result = subprocess.run(["tmux", "-V"], capture_output=True, text=True, timeout=5)
458
+ version = result.stdout.strip()
459
+ results.append(CheckResult("swarm", "tmux", CheckResult.STATUS_OK, version))
460
+ except Exception:
461
+ results.append(CheckResult("swarm", "tmux", CheckResult.STATUS_OK, str(tmux_path)))
462
+ else:
463
+ results.append(
464
+ CheckResult(
465
+ "swarm",
466
+ "tmux",
467
+ CheckResult.STATUS_WARN,
468
+ "not found — install with: brew install tmux / apt install tmux",
469
+ )
470
+ )
471
+
472
+ herdr_path = shutil.which("herdr")
473
+ if herdr_path:
474
+ try:
475
+ result = subprocess.run(
476
+ ["herdr", "--version"], capture_output=True, text=True, timeout=5
477
+ )
478
+ version = result.stdout.strip() or result.stderr.strip()
479
+ results.append(CheckResult("swarm", "herdr", CheckResult.STATUS_OK, version))
480
+ except Exception:
481
+ results.append(CheckResult("swarm", "herdr", CheckResult.STATUS_OK, str(herdr_path)))
482
+ else:
483
+ results.append(
484
+ CheckResult(
485
+ "swarm",
486
+ "herdr",
487
+ CheckResult.STATUS_WARN,
488
+ "not found — install from https://herdr.dev/docs/install/",
489
+ )
490
+ )
491
+
492
+ try:
493
+ plan_result = subprocess.run(
494
+ [
495
+ sys.executable,
496
+ "-m",
497
+ "agent_toolkit",
498
+ "swarm",
499
+ "plan",
500
+ "--runner",
501
+ "skeleton",
502
+ "--ui",
503
+ "tmux",
504
+ "doctor check",
505
+ ],
506
+ capture_output=True,
507
+ text=True,
508
+ timeout=15,
509
+ )
510
+ if plan_result.returncode == 0:
511
+ results.append(
512
+ CheckResult(
513
+ "swarm",
514
+ "swarm plan (offline)",
515
+ CheckResult.STATUS_OK,
516
+ "skeleton runner plan succeeded",
517
+ )
518
+ )
519
+ else:
520
+ stderr = (plan_result.stderr or "").strip().splitlines()
521
+ detail = stderr[-1] if stderr else f"plan exited {plan_result.returncode}"
522
+ results.append(
523
+ CheckResult(
524
+ "swarm",
525
+ "swarm plan (offline)",
526
+ CheckResult.STATUS_WARN,
527
+ detail,
528
+ )
529
+ )
530
+ except Exception as exc:
531
+ results.append(
532
+ CheckResult(
533
+ "swarm",
534
+ "swarm plan (offline)",
535
+ CheckResult.STATUS_WARN,
536
+ f"could not run plan: {exc}",
537
+ )
538
+ )
539
+
540
+ return results
541
+
542
+
543
+ # ---------------------------------------------------------------------------
544
+ # Formatting
545
+ # ---------------------------------------------------------------------------
546
+
547
+
548
+ def _print_section(title: str) -> None:
549
+ print(f"\n── {title} ──")
550
+
551
+
552
+ def _check_provenance(toolkit_dir: Path | None = None) -> list[CheckResult]:
553
+ """Provenance checks per §52: SHA/commit immutability, expiry/staleness >90d, UNKNOWN/mutable ref."""
554
+ results: list[CheckResult] = []
555
+ # Try multiple roots: toolkit_root() (data), its parent (repo), cwd, and file's repo root
556
+ candidates = []
557
+ tr = toolkit_dir or toolkit_root()
558
+ candidates.append(tr / "capabilities" / "upstream.lock")
559
+ candidates.append(tr.parent / "capabilities" / "upstream.lock")
560
+ candidates.append(Path.cwd() / "capabilities" / "upstream.lock")
561
+ # also try toolkit_root().parents[2] if data is deep
562
+ for anc in tr.parents:
563
+ candidates.append(anc / "capabilities" / "upstream.lock")
564
+ # Also try repo root via _paths toolkit_root parent chain
565
+ import pathlib as _P
566
+
567
+ for anc in _P.Path(__file__).resolve().parents:
568
+ candidates.append(anc / "capabilities" / "upstream.lock")
569
+ if (anc / "capabilities" / "upstream.lock").exists():
570
+ break
571
+ lock_path = next((c for c in candidates if c.exists()), candidates[0])
572
+ if not lock_path.exists():
573
+ results.append(
574
+ CheckResult(
575
+ "provenance",
576
+ "upstream.lock exists",
577
+ CheckResult.STATUS_ERR,
578
+ f"Missing: {lock_path}",
579
+ )
580
+ )
581
+ return results
582
+ try:
583
+ try:
584
+ import yaml as _yaml
585
+
586
+ has_yaml = True
587
+ except ImportError:
588
+ _yaml = None
589
+ has_yaml = False
590
+ import json as _json
591
+
592
+ raw = lock_path.read_text()
593
+ if has_yaml:
594
+ try:
595
+ data = _yaml.safe_load(raw) or {}
596
+ except Exception:
597
+ data = _json.loads(raw)
598
+ else:
599
+ # yaml not available in this env (e.g., minimal install) — try json, else warn
600
+ try:
601
+ data = _json.loads(raw)
602
+ except Exception:
603
+ results.append(
604
+ CheckResult(
605
+ "provenance",
606
+ "upstream.lock parse",
607
+ CheckResult.STATUS_WARN,
608
+ "yaml not installed — install pyyaml to validate provenance (pip install pyyaml)",
609
+ )
610
+ )
611
+ return results
612
+ # check version and upstreams
613
+ if data.get("version") != 1:
614
+ results.append(
615
+ CheckResult(
616
+ "provenance",
617
+ "lock version",
618
+ CheckResult.STATUS_WARN,
619
+ f"version={data.get('version')} expected 1",
620
+ )
621
+ )
622
+ else:
623
+ results.append(
624
+ CheckResult("provenance", "lock version", CheckResult.STATUS_OK, "version 1")
625
+ )
626
+ caps = data.get("capabilities", data.get("upstreams", []))
627
+ if not caps:
628
+ # fallback: count files
629
+ results.append(
630
+ CheckResult(
631
+ "provenance",
632
+ "lock has entries",
633
+ CheckResult.STATUS_WARN,
634
+ "no capabilities/upstreams",
635
+ )
636
+ )
637
+ else:
638
+ results.append(
639
+ CheckResult(
640
+ "provenance", "lock entries", CheckResult.STATUS_OK, f"{len(caps)} entries"
641
+ )
642
+ )
643
+ # Check each source for SHA40 and staleness >90d
644
+ import datetime as _dt
645
+
646
+ now = _dt.datetime.now(_dt.timezone.utc)
647
+ for cap in caps if isinstance(caps, list) else []:
648
+ # caps may be dict with sources
649
+ sources = cap.get("sources", []) if isinstance(cap, dict) else []
650
+ for src in sources:
651
+ ref = src.get("ref", "")
652
+ commit = src.get("commit", "")
653
+ # mutable ref check: tag without commit or branch name
654
+ if ref and not commit:
655
+ results.append(
656
+ CheckResult(
657
+ "provenance",
658
+ f"provenance:{cap.get('id', '?')}:{src.get('id', '?')} immutable",
659
+ CheckResult.STATUS_ERR,
660
+ f"ref={ref} without commit — mutable",
661
+ )
662
+ )
663
+ elif commit and len(commit) != 40:
664
+ results.append(
665
+ CheckResult(
666
+ "provenance",
667
+ f"provenance:{cap.get('id', '?')} SHA",
668
+ CheckResult.STATUS_ERR,
669
+ f"commit {commit[:8]} not SHA40",
670
+ )
671
+ )
672
+ # staleness: check last_checked or reviewed_at
673
+ for date_key in ("last_checked", "reviewed_at", "last_activity"):
674
+ val = src.get(date_key) or cap.get(date_key)
675
+ if val:
676
+ try:
677
+ dt = _dt.datetime.fromisoformat(val.replace("Z", "+00:00"))
678
+ age = (now - dt).days
679
+ if age > 90:
680
+ results.append(
681
+ CheckResult(
682
+ "provenance",
683
+ f"provenance:{cap.get('id', '?')} freshness",
684
+ CheckResult.STATUS_WARN,
685
+ f"{date_key} {age}d ago (>90d) — consider update",
686
+ )
687
+ )
688
+ break
689
+ except Exception:
690
+ pass
691
+ # Also check SKILL.md declarations have origin
692
+ # (light — ensure file exists)
693
+ results.append(
694
+ CheckResult(
695
+ "provenance",
696
+ "provenance: doctor --provenance",
697
+ CheckResult.STATUS_OK,
698
+ "run with --provenance for full SHA/commit + expiry report",
699
+ )
700
+ )
701
+ except Exception as exc:
702
+ results.append(
703
+ CheckResult("provenance", "upstream.lock parse", CheckResult.STATUS_ERR, str(exc))
704
+ )
705
+ return results
706
+
707
+
708
+ def _check_products_and_packs(toolkit_dir: Path | None = None) -> list[CheckResult]:
709
+ """Pack consistency + product catalog per #387."""
710
+ results: list[CheckResult] = []
711
+ # Locate repo root (not data dir) for distributions, skills, packs
712
+ candidates = []
713
+ tr = toolkit_dir or toolkit_root()
714
+ candidates.append(tr)
715
+ candidates.append(tr.parent)
716
+ candidates.append(Path.cwd())
717
+ for anc in tr.parents:
718
+ candidates.append(anc)
719
+ for anc in pathlib.Path(__file__).resolve().parents:
720
+ candidates.append(anc)
721
+ root = next((c for c in candidates if (c / "distributions" / "products.yaml").exists()), tr)
722
+ prod_path = root / "distributions" / "products.yaml"
723
+ if not prod_path.exists():
724
+ results.append(
725
+ CheckResult("packs", "products.yaml exists", CheckResult.STATUS_ERR, str(prod_path))
726
+ )
727
+ else:
728
+ results.append(
729
+ CheckResult("packs", "products.yaml exists", CheckResult.STATUS_OK, str(prod_path))
730
+ )
731
+ # check complete covers all skills via catalog
732
+ try:
733
+ try:
734
+ import yaml as _yaml
735
+ except ImportError:
736
+ results.append(
737
+ CheckResult(
738
+ "packs",
739
+ "products.yaml parse",
740
+ CheckResult.STATUS_WARN,
741
+ "yaml not installed — install pyyaml to validate packs",
742
+ )
743
+ )
744
+ return results
745
+ prod_data = _yaml.safe_load(prod_path.read_text())
746
+ complete = next(
747
+ (
748
+ p
749
+ for p in prod_data.get("products", [])
750
+ if p.get("id") == "agent-toolkit-complete"
751
+ ),
752
+ None,
753
+ )
754
+ if complete:
755
+ included = set(complete.get("includes", {}).get("skills", []))
756
+ # count skills on disk
757
+ skills = list((root / "skills").rglob("SKILL.md"))
758
+ skill_ids = {
759
+ f"{p.parts[-3]}/{p.parts[-2]}" if len(p.parts) >= 3 else p.parent.name
760
+ for p in skills
761
+ }
762
+ # also handle skills/*/* flat?
763
+ missing = skill_ids - included
764
+ if missing:
765
+ results.append(
766
+ CheckResult(
767
+ "packs",
768
+ "complete covers all skills",
769
+ CheckResult.STATUS_ERR,
770
+ f"missing {sorted(missing)[:5]}",
771
+ )
772
+ )
773
+ else:
774
+ results.append(
775
+ CheckResult(
776
+ "packs",
777
+ "complete covers all skills",
778
+ CheckResult.STATUS_OK,
779
+ f"{len(included)} skills",
780
+ )
781
+ )
782
+ except Exception as exc:
783
+ results.append(
784
+ CheckResult("packs", "products.yaml parse", CheckResult.STATUS_WARN, str(exc))
785
+ )
786
+ # packs/* config.yaml
787
+ packs_dir = root / "packs"
788
+ if packs_dir.is_dir():
789
+ for pack_dir in sorted(packs_dir.iterdir()):
790
+ if pack_dir.is_dir():
791
+ cfg = pack_dir / "config.yaml"
792
+ if not cfg.exists():
793
+ results.append(
794
+ CheckResult(
795
+ "packs",
796
+ f"pack:{pack_dir.name} config",
797
+ CheckResult.STATUS_WARN,
798
+ "missing config.yaml",
799
+ )
800
+ )
801
+ else:
802
+ results.append(
803
+ CheckResult(
804
+ "packs", f"pack:{pack_dir.name} config", CheckResult.STATUS_OK, str(cfg)
805
+ )
806
+ )
807
+ # loops check
808
+ try:
809
+ try:
810
+ import yaml as _yaml2
811
+ except ImportError:
812
+ continue
813
+ cfg_data = _yaml2.safe_load(cfg.read_text()) or {}
814
+ for loop_name in cfg_data.get("loops", {}).keys():
815
+ if not (root / "loops" / loop_name).is_dir():
816
+ results.append(
817
+ CheckResult(
818
+ "packs",
819
+ f"pack:{pack_dir.name} loop:{loop_name}",
820
+ CheckResult.STATUS_WARN,
821
+ "loop dir missing",
822
+ )
823
+ )
824
+ except Exception:
825
+ pass
826
+ return results
827
+
828
+
829
+ def _check_mcp_registry(toolkit_dir: Path | None = None) -> list[CheckResult]:
830
+ """MCP registry vs installed runtime per #387."""
831
+ results: list[CheckResult] = []
832
+ root = toolkit_dir or toolkit_root()
833
+ reg_dir = root / "mcp" / "registry"
834
+ if not reg_dir.is_dir():
835
+ results.append(
836
+ CheckResult("mcp", "mcp/registry dir", CheckResult.STATUS_WARN, str(reg_dir))
837
+ )
838
+ return results
839
+ yaml_files = list(reg_dir.glob("*.yaml"))
840
+ results.append(
841
+ CheckResult(
842
+ "mcp", "mcp/registry count", CheckResult.STATUS_OK, f"{len(yaml_files)} providers"
843
+ )
844
+ )
845
+ for yf in sorted(yaml_files):
846
+ try:
847
+ try:
848
+ import yaml as _yaml3
849
+ except ImportError:
850
+ results.append(
851
+ CheckResult(
852
+ "mcp",
853
+ "mcp/registry count",
854
+ CheckResult.STATUS_WARN,
855
+ "yaml not installed — install pyyaml to validate mcp",
856
+ )
857
+ )
858
+ break
859
+ data = _yaml3.safe_load(yf.read_text()) or {}
860
+ # require id, tools or implementation
861
+ if not data.get("id"):
862
+ results.append(
863
+ CheckResult("mcp", f"mcp:{yf.stem} id", CheckResult.STATUS_ERR, "missing id")
864
+ )
865
+ # check healthcheck or transport
866
+ if "transport" not in data and "implementation" not in data:
867
+ results.append(
868
+ CheckResult(
869
+ "mcp",
870
+ f"mcp:{yf.stem} transport",
871
+ CheckResult.STATUS_WARN,
872
+ "no transport/implementation",
873
+ )
874
+ )
875
+ except Exception as exc:
876
+ results.append(
877
+ CheckResult("mcp", f"mcp:{yf.stem} parse", CheckResult.STATUS_ERR, str(exc))
878
+ )
879
+ return results
880
+
881
+
882
+ def _print_result(r: CheckResult) -> None:
883
+ detail = f" ({r.detail})" if r.detail else ""
884
+ print(f" {r.icon} {r.name}{detail}")
885
+
886
+
887
+ # ---------------------------------------------------------------------------
888
+ # Argument parsing
889
+ # ---------------------------------------------------------------------------
890
+
891
+ _PARSE_HELP = object()
892
+ _PARSE_ERROR = object()
893
+
894
+
895
+ def _parse_args(args: list[str]):
896
+ """Return (json_output, fix), _PARSE_HELP, or _PARSE_ERROR."""
897
+ json_output = False
898
+ fix = False
899
+
900
+ for arg in args:
901
+ if arg in ("-h", "--help"):
902
+ print(__doc__)
903
+ return _PARSE_HELP
904
+ elif arg == "--json":
905
+ json_output = True
906
+ elif arg == "--fix":
907
+ fix = True
908
+ elif arg == "--provenance":
909
+ print(
910
+ " ℹ --provenance: full SHA/commit + expiry report (provenance checks are always run; use --json for machine-readable)",
911
+ file=sys.stderr,
912
+ )
913
+ # explicit flag — no separate mode, just acknowledge
914
+ pass
915
+ else:
916
+ print(
917
+ f" ✗ Unknown option: {arg} (run 'agent-toolkit doctor --help')", file=sys.stderr
918
+ )
919
+ return _PARSE_ERROR
920
+
921
+ return json_output, fix
922
+
923
+
924
+ # ---------------------------------------------------------------------------
925
+ # Main entry point
926
+ # ---------------------------------------------------------------------------
927
+
928
+
929
+ def cmd_doctor(args: list[str]) -> int:
930
+ """Run health checks for the agent-toolkit installation.
931
+
932
+ Returns 0 if no errors, 1 if any check errors, 2 on usage/parse errors.
933
+ """
934
+ result = _parse_args(args)
935
+ if result is _PARSE_HELP:
936
+ return 0
937
+ if result is _PARSE_ERROR:
938
+ return 2
939
+
940
+ json_output, fix = result
941
+ toolkit_dir = toolkit_root()
942
+
943
+ # Run all checks
944
+ all_results: list[CheckResult] = []
945
+
946
+ # 1. System baseline
947
+ all_results.append(_check_python_version())
948
+ all_results.append(_check_command("system", "git", "git"))
949
+ all_results.append(_check_command("system", "gh (GitHub CLI)", "gh"))
950
+ all_results.append(_check_gh_auth())
951
+
952
+ # 2. AI tools
953
+ for tool_name, cmd in [
954
+ ("claude", "claude"),
955
+ ("cursor", "cursor"),
956
+ ("opencode", "opencode"),
957
+ ("windsurf", "windsurf"),
958
+ ("muse", "muse"),
959
+ ]:
960
+ all_results.append(_check_ai_tool(tool_name, cmd))
961
+
962
+ # 3. Profiles
963
+ all_results.extend(_check_profiles())
964
+
965
+ # 4. Loop runtime
966
+ all_results.extend(_check_loop_runtime(toolkit_dir))
967
+
968
+ # 5. LLM providers
969
+ all_results.extend(_check_llm_providers())
970
+
971
+ # 6. MCP
972
+ all_results.extend(_check_mcp())
973
+
974
+ # 7. Scheduled loops
975
+ all_results.extend(_check_scheduled_loops())
976
+
977
+ # 8. Swarm tooling
978
+ all_results.extend(_check_swarm())
979
+
980
+ # 9. Provenance (per §52: inventory warnings, doctor --provenance validating SHA/commit immutability, expiry >90d)
981
+ all_results.extend(_check_provenance(toolkit_dir))
982
+
983
+ # 10. Products / Packs (per #387: pack consistency, complete coverage)
984
+ all_results.extend(_check_products_and_packs(toolkit_dir))
985
+
986
+ # 11. MCP registry (per #387: mcp/registry vs installed runtime)
987
+ all_results.extend(_check_mcp_registry(toolkit_dir))
988
+
989
+ # Output
990
+ if json_output:
991
+ print(json.dumps({"checks": [r.to_dict() for r in all_results]}, indent=2))
992
+ else:
993
+ print()
994
+ print("agent-toolkit doctor")
995
+
996
+ categories_seen: list[str] = []
997
+ category_labels = {
998
+ "system": "System baseline",
999
+ "ai_tools": "AI tools",
1000
+ "profiles": "Profiles",
1001
+ "loops": "Loop runtime",
1002
+ "llm": "LLM providers",
1003
+ "mcp": "MCP",
1004
+ "scheduled": "Scheduled loops",
1005
+ "swarm": "Swarm tooling",
1006
+ "provenance": "Provenance (SHA/commit, expiry)",
1007
+ "packs": "Products / Packs",
1008
+ }
1009
+ for r in all_results:
1010
+ if r.category not in categories_seen:
1011
+ categories_seen.append(r.category)
1012
+ label = category_labels.get(r.category, r.category)
1013
+ _print_section(label)
1014
+ _print_result(r)
1015
+
1016
+ # Summary
1017
+ n_ok = sum(1 for r in all_results if r.status == CheckResult.STATUS_OK)
1018
+ n_warn = sum(1 for r in all_results if r.status == CheckResult.STATUS_WARN)
1019
+ n_err = sum(1 for r in all_results if r.status == CheckResult.STATUS_ERR)
1020
+
1021
+ print()
1022
+ print("── Summary ──")
1023
+ print(f" ✓ {n_ok} ok ⚠ {n_warn} warnings ✗ {n_err} errors")
1024
+ print()
1025
+
1026
+ # --fix: call install for warnings/errors related to profiles
1027
+ install_rc = 0
1028
+ if fix:
1029
+ has_profile_issues = any(
1030
+ r.category == "profiles" and r.status != CheckResult.STATUS_OK for r in all_results
1031
+ )
1032
+ if has_profile_issues:
1033
+ if not json_output:
1034
+ print("── Auto-fix: running install ──")
1035
+ from agent_toolkit.cli.install import cmd_install
1036
+
1037
+ if json_output:
1038
+ import contextlib
1039
+ import io
1040
+
1041
+ # Keep stdout JSON-pure: swallow install chatter.
1042
+ with contextlib.redirect_stdout(io.StringIO()):
1043
+ install_rc = cmd_install([])
1044
+ else:
1045
+ install_rc = cmd_install([])
1046
+
1047
+ errors = [r for r in all_results if r.status == CheckResult.STATUS_ERR]
1048
+ if errors:
1049
+ return 1
1050
+ if install_rc:
1051
+ return install_rc
1052
+ return 0