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,596 @@
1
+ """UI backend contract and implementations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import shutil
8
+ import subprocess
9
+ from pathlib import Path
10
+ from typing import Any, Protocol
11
+
12
+
13
+ class SwarmUIBackend(Protocol):
14
+ name: str
15
+
16
+ def doctor(self) -> dict[str, Any]: ...
17
+ def create_run_surface(self, run_dir: Path, run_id: str, recipe: str) -> dict[str, Any]: ...
18
+ def create_role_surface(self, run_dir: Path, run_id: str, role: str) -> dict[str, Any]: ...
19
+ def start_agent(
20
+ self, run_dir: Path, run_id: str, role: str, cmd: list[str]
21
+ ) -> dict[str, Any]: ...
22
+ def prompt_agent(self, run_id: str, role: str, prompt: str) -> dict[str, Any]: ...
23
+ def wait_agent(
24
+ self, run_id: str, role: str, until: str = "idle", timeout: int = 300
25
+ ) -> dict[str, Any]: ...
26
+ def read_agent_output(self, run_id: str, role: str) -> str: ...
27
+ def focus_agent(self, run_id: str, role: str) -> None: ...
28
+ def attach(self, run_id: str) -> None: ...
29
+ def stop_agent(self, run_id: str, role: str) -> dict[str, Any]: ...
30
+ def cleanup(self, run_dir: Path, run_id: str) -> dict[str, Any]: ...
31
+
32
+
33
+ # --- Herdr backend ---
34
+
35
+
36
+ class HerdrBackend:
37
+ name = "herdr"
38
+
39
+ def doctor(self) -> dict[str, Any]:
40
+ herdr = shutil.which("herdr")
41
+ if not herdr:
42
+ return {
43
+ "available": False,
44
+ "reason": "herdr binary not found",
45
+ "install": "https://herdr.dev/docs/install/",
46
+ }
47
+ try:
48
+ res = subprocess.run(["herdr", "--version"], capture_output=True, text=True, timeout=5)
49
+ ver = res.stdout.strip() or res.stderr.strip()
50
+ # Check integration
51
+ integ = subprocess.run(
52
+ ["herdr", "integration", "list", "--json"],
53
+ capture_output=True,
54
+ text=True,
55
+ timeout=5,
56
+ )
57
+ integrations = {}
58
+ if integ.returncode == 0:
59
+ try:
60
+ integrations = json.loads(integ.stdout)
61
+ except Exception:
62
+ integrations = {"raw": integ.stdout[:500]}
63
+ return {"available": True, "version": ver, "integrations": integrations}
64
+ except Exception as e:
65
+ return {"available": False, "reason": str(e)}
66
+
67
+ def _run_json(self, args: list[str], timeout: int = 10) -> dict[str, Any]:
68
+ try:
69
+ # Try with --json first, fallback without if herdr rejects it (e.g., workspace create)
70
+ for extra in (["--json"], []):
71
+ res = subprocess.run(
72
+ ["herdr"] + args + extra, capture_output=True, text=True, timeout=timeout
73
+ )
74
+ # If herdr complains about unknown --json, try without
75
+ if "unknown option: --json" in (res.stderr or "") or "unknown option: --json" in (
76
+ res.stdout or ""
77
+ ):
78
+ continue
79
+ try:
80
+ return (
81
+ json.loads(res.stdout)
82
+ if res.stdout.strip()
83
+ else {"raw": res.stdout, "stderr": res.stderr, "code": res.returncode}
84
+ )
85
+ except Exception:
86
+ # If not JSON but success, return raw
87
+ if res.returncode == 0 and res.stdout.strip():
88
+ try:
89
+ return json.loads(res.stdout)
90
+ except Exception:
91
+ return {"raw": res.stdout, "stderr": res.stderr, "code": res.returncode}
92
+ return {"raw": res.stdout, "stderr": res.stderr, "code": res.returncode}
93
+ return {"raw": "", "stderr": "unknown option --json handling failed", "code": 1}
94
+ except FileNotFoundError:
95
+ return {"error": "herdr not found"}
96
+ except Exception as e:
97
+ return {"error": str(e)}
98
+
99
+ def _herdr_workspace_id(self, run_dir: Path, run_id: str) -> str | None:
100
+ # Try to read stored workspace_id, else find by label
101
+ try:
102
+ store = run_dir / ".herdr_workspace_id"
103
+ if store.is_file():
104
+ wid = store.read_text(encoding="utf-8").strip()
105
+ if wid:
106
+ return wid
107
+ except Exception:
108
+ pass
109
+ # Find by label swarm-<run_id>
110
+ try:
111
+ res = subprocess.run(
112
+ ["herdr", "workspace", "list"], capture_output=True, text=True, timeout=5
113
+ )
114
+ import json as _json
115
+
116
+ data = _json.loads(res.stdout)
117
+ for w in data.get("result", {}).get("workspaces", []):
118
+ if w.get("label") == f"swarm-{run_id}":
119
+ return w.get("workspace_id")
120
+ except Exception:
121
+ pass
122
+ return None
123
+
124
+ def _herdr_pane_for_role(self, run_dir: Path, run_id: str, role: str) -> str | None:
125
+ wid = self._herdr_workspace_id(run_dir, run_id)
126
+ if not wid:
127
+ return None
128
+ try:
129
+ res = subprocess.run(
130
+ ["herdr", "tab", "list", "--workspace", wid],
131
+ capture_output=True,
132
+ text=True,
133
+ timeout=5,
134
+ )
135
+ import json as _json
136
+
137
+ data = _json.loads(res.stdout)
138
+ for tab in data.get("result", {}).get("tabs", []):
139
+ if tab.get("label") == role:
140
+ # Get pane for this tab
141
+ res2 = subprocess.run(
142
+ ["herdr", "pane", "list", "--workspace", wid],
143
+ capture_output=True,
144
+ text=True,
145
+ timeout=5,
146
+ )
147
+ data2 = _json.loads(res2.stdout)
148
+ for pane in data2.get("result", {}).get("panes", []):
149
+ if pane.get("tab_id") == tab.get("tab_id"):
150
+ return pane.get("pane_id")
151
+ # Fallback to root_pane if tab list gives it
152
+ return (
153
+ tab.get("root_pane", {}).get("pane_id")
154
+ if isinstance(tab.get("root_pane"), dict)
155
+ else None
156
+ )
157
+ except Exception:
158
+ pass
159
+ return None
160
+
161
+ def create_run_surface(self, run_dir: Path, run_id: str, recipe: str) -> dict[str, Any]:
162
+ if not shutil.which("herdr"):
163
+ return {"backend": "herdr", "status": "unavailable", "run_id": run_id}
164
+ # Repo is .agent-toolkit/swarm/runs/<id> -> repo = run_dir.parent.parent.parent
165
+ try:
166
+ repo = run_dir.parent.parent.parent
167
+ if not (repo / ".git").exists():
168
+ repo = run_dir
169
+ except Exception:
170
+ repo = run_dir
171
+ res = self._run_json(
172
+ [
173
+ "workspace",
174
+ "create",
175
+ "--cwd",
176
+ str(repo),
177
+ "--label",
178
+ f"swarm-{run_id}",
179
+ "--no-focus",
180
+ ]
181
+ )
182
+ # Store workspace_id for later
183
+ try:
184
+ wid = res.get("result", {}).get("workspace", {}).get("workspace_id") or res.get(
185
+ "result", {}
186
+ ).get("workspace_id")
187
+ if wid:
188
+ (run_dir / ".herdr_workspace_id").write_text(wid, encoding="utf-8")
189
+ else:
190
+ # Try to find by label
191
+ wid2 = self._herdr_workspace_id(run_dir, run_id)
192
+ if wid2:
193
+ (run_dir / ".herdr_workspace_id").write_text(wid2, encoding="utf-8")
194
+ except Exception:
195
+ pass
196
+ return res
197
+
198
+ def create_role_surface(self, run_dir: Path, run_id: str, role: str) -> dict[str, Any]:
199
+ if not shutil.which("herdr"):
200
+ return {"backend": "herdr", "status": "unavailable"}
201
+ wid = self._herdr_workspace_id(run_dir, run_id)
202
+ if not wid:
203
+ # Workspace not yet created, cannot create tab
204
+ return {"backend": "herdr", "status": "no_workspace", "role": role}
205
+ # Check if tab already exists
206
+ try:
207
+ res = subprocess.run(
208
+ ["herdr", "tab", "list", "--workspace", wid],
209
+ capture_output=True,
210
+ text=True,
211
+ timeout=5,
212
+ )
213
+ import json as _json
214
+
215
+ data = _json.loads(res.stdout)
216
+ for tab in data.get("result", {}).get("tabs", []):
217
+ if tab.get("label") == role:
218
+ return {
219
+ "backend": "herdr",
220
+ "status": "exists",
221
+ "role": role,
222
+ "tab_id": tab.get("tab_id"),
223
+ }
224
+ except Exception:
225
+ pass
226
+ # Create tab for role
227
+ # Use worktree path if exists else run_dir
228
+ try:
229
+ # Try to get worktree path from state if available
230
+ from .store import read_state
231
+
232
+ state = read_state(run_dir) or {}
233
+ wt_path = None
234
+ for wt in state.get("worktrees", []):
235
+ if wt.get("role") == role:
236
+ wt_path = wt.get("path")
237
+ break
238
+ cwd = wt_path if wt_path and Path(wt_path).exists() else str(run_dir)
239
+ except Exception:
240
+ cwd = str(run_dir)
241
+ res = self._run_json(
242
+ ["tab", "create", "--workspace", wid, "--label", role, "--cwd", cwd, "--no-focus"]
243
+ )
244
+ return {"backend": "herdr", "status": "created", "role": role, "result": res}
245
+
246
+ def start_agent(self, run_dir: Path, run_id: str, role: str, cmd: list[str]) -> dict[str, Any]:
247
+ if not shutil.which("herdr"):
248
+ return {"error": "herdr not available"}
249
+ # For herdr, we run the bash command via pane run, not agent start (more universal, matches tmux)
250
+ # Find pane for role
251
+ pane_id = self._herdr_pane_for_role(run_dir, run_id, role)
252
+ if not pane_id:
253
+ # Fallback: try workspace root pane
254
+ wid = self._herdr_workspace_id(run_dir, run_id)
255
+ if wid:
256
+ try:
257
+ res = subprocess.run(
258
+ ["herdr", "pane", "list", "--workspace", wid],
259
+ capture_output=True,
260
+ text=True,
261
+ timeout=5,
262
+ )
263
+ import json as _json
264
+
265
+ data = _json.loads(res.stdout)
266
+ panes = data.get("result", {}).get("panes", [])
267
+ if panes:
268
+ pane_id = panes[0].get("pane_id")
269
+ except Exception:
270
+ pass
271
+ if not pane_id:
272
+ return {"error": f"no pane for role {role}"}
273
+ # Build shell command string like tmux does
274
+ import shlex as _shlex
275
+
276
+ shell_cmd = " ".join(_shlex.quote(c) for c in cmd)
277
+ # Use pane run to execute bash -lc '...'
278
+ try:
279
+ res = subprocess.run(
280
+ ["herdr", "pane", "run", pane_id, shell_cmd],
281
+ capture_output=True,
282
+ text=True,
283
+ timeout=10,
284
+ )
285
+ return {
286
+ "backend": "herdr",
287
+ "status": "started",
288
+ "pane_id": pane_id,
289
+ "stdout": res.stdout[:500],
290
+ "stderr": res.stderr[:500],
291
+ "code": res.returncode,
292
+ }
293
+ except Exception as e:
294
+ return {"error": str(e)}
295
+
296
+ def prompt_agent(self, run_id: str, role: str, prompt: str) -> dict[str, Any]:
297
+ name = f"swarm-{run_id}-{role}"
298
+ return self._run_json(["agent", "prompt", name, prompt, "--wait"])
299
+
300
+ def wait_agent(
301
+ self, run_id: str, role: str, until: str = "idle", timeout: int = 300
302
+ ) -> dict[str, Any]:
303
+ name = f"swarm-{run_id}-{role}"
304
+ return self._run_json(["agent", "wait", name, "--until", until])
305
+
306
+ def read_agent_output(self, run_id: str, role: str) -> str:
307
+ name = f"swarm-{run_id}-{role}"
308
+ res = self._run_json(["agent", "read", name, "--source", "recent"])
309
+ return json.dumps(res)
310
+
311
+ def focus_agent(self, run_id: str, role: str) -> None:
312
+ pass
313
+
314
+ def attach(self, run_id: str) -> None:
315
+ # Find workspace_id by label and focus it (herdr has no 'open')
316
+ wid = None
317
+ try:
318
+ import json as _json
319
+ import subprocess as _sp
320
+
321
+ res = _sp.run(["herdr", "workspace", "list"], capture_output=True, text=True, timeout=5)
322
+ data = _json.loads(res.stdout)
323
+ for w in data.get("result", {}).get("workspaces", []):
324
+ if w.get("label") == f"swarm-{run_id}":
325
+ wid = w.get("workspace_id")
326
+ break
327
+ except Exception:
328
+ pass
329
+ if wid:
330
+ print(f"[herdr] focusing workspace swarm-{run_id} ({wid})")
331
+ try:
332
+ import subprocess as _sp2
333
+
334
+ _sp2.run(["herdr", "workspace", "focus", wid], capture_output=False, timeout=5)
335
+ except Exception as e:
336
+ print(
337
+ f"[herdr] focus failed: {e} — run `herdr workspace list` and `herdr workspace focus {wid}`"
338
+ )
339
+ else:
340
+ print(
341
+ f"[herdr] attach swarm-{run_id}: workspace not found — run `herdr workspace list`"
342
+ )
343
+
344
+ def stop_agent(self, run_id: str, role: str) -> dict[str, Any]:
345
+ name = f"swarm-{run_id}-{role}"
346
+ return self._run_json(["agent", "stop", name])
347
+
348
+ def cleanup(self, run_dir: Path, run_id: str) -> dict[str, Any]:
349
+ return {"backend": "herdr", "status": "cleaned"}
350
+
351
+
352
+ # --- Tmux backend ---
353
+
354
+
355
+ class TmuxBackend:
356
+ name = "tmux"
357
+
358
+ def doctor(self) -> dict[str, Any]:
359
+ tmux = shutil.which("tmux")
360
+ if not tmux:
361
+ return {
362
+ "available": False,
363
+ "reason": "tmux not found",
364
+ "install": "apt/brew/pacman: tmux",
365
+ }
366
+ try:
367
+ res = subprocess.run(["tmux", "-V"], capture_output=True, text=True, timeout=5)
368
+ return {"available": True, "version": res.stdout.strip()}
369
+ except Exception as e:
370
+ return {"available": False, "reason": str(e)}
371
+
372
+ def _socket_for(self, run_id: str) -> str:
373
+ return f"agent-toolkit-swarm-{run_id}"
374
+
375
+ def create_run_surface(self, run_dir: Path, run_id: str, recipe: str) -> dict[str, Any]:
376
+ if not shutil.which("tmux"):
377
+ return {"backend": "tmux", "status": "unavailable"}
378
+ sock = self._socket_for(run_id)
379
+ session = f"swarm-{run_id}"
380
+ try:
381
+ subprocess.run(
382
+ ["tmux", "-L", sock, "new-session", "-d", "-s", session, "-c", str(run_dir)],
383
+ capture_output=True,
384
+ timeout=5,
385
+ )
386
+ return {"backend": "tmux", "socket": sock, "session": session, "status": "created"}
387
+ except Exception as e:
388
+ return {"backend": "tmux", "error": str(e)}
389
+
390
+ def create_role_surface(self, run_dir: Path, run_id: str, role: str) -> dict[str, Any]:
391
+ sock = self._socket_for(run_id)
392
+ session = f"swarm-{run_id}"
393
+ window = f"{role}"
394
+ try:
395
+ subprocess.run(
396
+ [
397
+ "tmux",
398
+ "-L",
399
+ sock,
400
+ "new-window",
401
+ "-t",
402
+ f"{session}",
403
+ "-n",
404
+ window,
405
+ "-c",
406
+ str(run_dir),
407
+ ],
408
+ capture_output=True,
409
+ timeout=5,
410
+ )
411
+ return {"backend": "tmux", "socket": sock, "session": session, "window": window}
412
+ except Exception as e:
413
+ return {"backend": "tmux", "error": str(e)}
414
+
415
+ def start_agent(self, run_dir: Path, run_id: str, role: str, cmd: list[str]) -> dict[str, Any]:
416
+ if not shutil.which("tmux"):
417
+ return {"error": "tmux not available"}
418
+ sock = self._socket_for(run_id)
419
+ # Use array cmd safely via send-keys with shell quoting
420
+ import shlex
421
+
422
+ shell_cmd = " ".join(shlex.quote(c) for c in cmd)
423
+ try:
424
+ subprocess.run(
425
+ [
426
+ "tmux",
427
+ "-L",
428
+ sock,
429
+ "send-keys",
430
+ "-t",
431
+ f"swarm-{run_id}:{role}",
432
+ shell_cmd,
433
+ "Enter",
434
+ ],
435
+ capture_output=True,
436
+ timeout=5,
437
+ )
438
+ return {"backend": "tmux", "status": "started", "cmd": cmd}
439
+ except Exception as e:
440
+ return {"error": str(e)}
441
+
442
+ def prompt_agent(self, run_id: str, role: str, prompt: str) -> dict[str, Any]:
443
+ sock = self._socket_for(run_id)
444
+ target = f"swarm-{run_id}:{role}"
445
+ # Use buffer paste for large multiline prompts (more robust than send-keys -l)
446
+ import tempfile
447
+ import time as _time
448
+
449
+ try:
450
+ # Give agent TUI a moment to initialize
451
+ _time.sleep(1.5)
452
+ with tempfile.NamedTemporaryFile(
453
+ mode="w", suffix=".txt", delete=False, encoding="utf-8"
454
+ ) as tf:
455
+ tf.write(prompt)
456
+ tf_path = tf.name
457
+ try:
458
+ subprocess.run(
459
+ ["tmux", "-L", sock, "load-buffer", "-b", f"swarm-prompt-{role}", tf_path],
460
+ capture_output=True,
461
+ timeout=5,
462
+ )
463
+ subprocess.run(
464
+ [
465
+ "tmux",
466
+ "-L",
467
+ sock,
468
+ "paste-buffer",
469
+ "-b",
470
+ f"swarm-prompt-{role}",
471
+ "-t",
472
+ target,
473
+ ],
474
+ capture_output=True,
475
+ timeout=5,
476
+ )
477
+ # Small delay then Enter to submit
478
+ _time.sleep(0.3)
479
+ subprocess.run(
480
+ ["tmux", "-L", sock, "send-keys", "-t", target, "Enter"],
481
+ capture_output=True,
482
+ timeout=5,
483
+ )
484
+ return {"backend": "tmux", "status": "prompted", "role": role, "bytes": len(prompt)}
485
+ finally:
486
+ try:
487
+ import os as _os
488
+
489
+ _os.unlink(tf_path)
490
+ except Exception:
491
+ pass
492
+ try:
493
+ subprocess.run(
494
+ ["tmux", "-L", sock, "delete-buffer", "-b", f"swarm-prompt-{role}"],
495
+ capture_output=True,
496
+ timeout=5,
497
+ )
498
+ except Exception:
499
+ pass
500
+ except Exception as e:
501
+ return {"error": str(e)}
502
+
503
+ def wait_agent(
504
+ self, run_id: str, role: str, until: str = "idle", timeout: int = 300
505
+ ) -> dict[str, Any]:
506
+ return {"backend": "tmux", "status": "wait-not-implemented"}
507
+
508
+ def read_agent_output(self, run_id: str, role: str) -> str:
509
+ sock = self._socket_for(run_id)
510
+ try:
511
+ res = subprocess.run(
512
+ ["tmux", "-L", sock, "capture-pane", "-p", "-t", f"swarm-{run_id}:{role}"],
513
+ capture_output=True,
514
+ text=True,
515
+ timeout=5,
516
+ )
517
+ return res.stdout
518
+ except Exception as e:
519
+ return f"error: {e}"
520
+
521
+ def focus_agent(self, run_id: str, role: str) -> None:
522
+ pass
523
+
524
+ def attach(self, run_id: str) -> None:
525
+ sock = self._socket_for(run_id)
526
+ print(f"[tmux] attach: tmux -L {sock} attach -t swarm-{run_id}")
527
+
528
+ def stop_agent(self, run_id: str, role: str) -> dict[str, Any]:
529
+ sock = self._socket_for(run_id)
530
+ try:
531
+ subprocess.run(
532
+ ["tmux", "-L", sock, "kill-window", "-t", f"swarm-{run_id}:{role}"],
533
+ capture_output=True,
534
+ timeout=5,
535
+ )
536
+ return {"status": "stopped"}
537
+ except Exception as e:
538
+ return {"error": str(e)}
539
+
540
+ def cleanup(self, run_dir: Path, run_id: str) -> dict[str, Any]:
541
+ sock = self._socket_for(run_id)
542
+ session = f"swarm-{run_id}"
543
+ actions: list[str] = []
544
+ try:
545
+ subprocess.run(
546
+ ["tmux", "-L", sock, "kill-session", "-t", session],
547
+ capture_output=True,
548
+ timeout=5,
549
+ )
550
+ actions.append("kill-session")
551
+ except Exception as e:
552
+ return {"error": str(e)}
553
+ # kill-server releases the per-run tmux server. If the server already
554
+ # exited (e.g. last session closed, tmux crashed, test timeout), this is
555
+ # a no-op but ensures no server process lingers.
556
+ try:
557
+ subprocess.run(
558
+ ["tmux", "-L", sock, "kill-server"],
559
+ capture_output=True,
560
+ timeout=5,
561
+ )
562
+ actions.append("kill-server")
563
+ except Exception:
564
+ pass
565
+ # tmux leaves the socket file behind when the server dies without a
566
+ # clean shutdown (common under pytest timeouts). Remove the orphan so
567
+ # /tmp/tmux-<uid>/ does not accumulate socket files across runs.
568
+ try:
569
+ for base in ("/tmp", os.environ.get("TMPDIR", "/tmp")):
570
+ cand = Path(base) / f"tmux-{os.getuid()}" / sock
571
+ if cand.is_socket():
572
+ try:
573
+ cand.unlink()
574
+ actions.append(f"rm-socket:{cand}")
575
+ except FileNotFoundError:
576
+ pass
577
+ except Exception:
578
+ pass
579
+ return {"backend": "tmux", "status": "cleaned", "actions": actions}
580
+
581
+
582
+ def get_backend(name: str):
583
+ if name == "herdr":
584
+ return HerdrBackend()
585
+ if name == "tmux":
586
+ return TmuxBackend()
587
+ if name == "auto":
588
+ # Prefer herdr if available, else tmux
589
+ hb = HerdrBackend()
590
+ if hb.doctor().get("available"):
591
+ return hb
592
+ tb = TmuxBackend()
593
+ if tb.doctor().get("available"):
594
+ return tb
595
+ return hb # fallback for error reporting
596
+ return HerdrBackend()
@@ -0,0 +1,83 @@
1
+ """Budget enforcement — reuse loop budget ideas, add swarm specifics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ DEFAULTS = {
10
+ "max_total_tokens": 900000,
11
+ "max_cost_usd": 4.00,
12
+ "max_wall_seconds": 7200,
13
+ "max_concurrency": 2,
14
+ "max_role_round_trips": 2,
15
+ }
16
+
17
+
18
+ def resolve_budget(
19
+ spec_budget: dict[str, Any] | None, cli_overrides: dict[str, Any] | None = None
20
+ ) -> dict[str, Any]:
21
+ merged = dict(DEFAULTS)
22
+ if spec_budget:
23
+ merged.update({k: v for k, v in spec_budget.items() if v is not None})
24
+ if cli_overrides:
25
+ merged.update({k: v for k, v in cli_overrides.items() if v is not None})
26
+ # Clamp concurrency
27
+ try:
28
+ merged["max_concurrency"] = max(1, min(6, int(merged.get("max_concurrency", 2))))
29
+ except Exception:
30
+ merged["max_concurrency"] = 2
31
+ return merged
32
+
33
+
34
+ def check_limits(budget: dict[str, Any], usage: dict[str, Any]) -> list[str]:
35
+ violated: list[str] = []
36
+ total_tokens = usage.get("total_tokens", 0) or 0
37
+ cost = usage.get("cost_usd", 0) or 0
38
+ wall = usage.get("wall_seconds", 0) or 0
39
+ if budget.get("max_total_tokens") is not None and total_tokens >= int(
40
+ budget["max_total_tokens"]
41
+ ):
42
+ violated.append("max_total_tokens")
43
+ if budget.get("max_cost_usd") is not None and cost >= float(budget["max_cost_usd"]):
44
+ violated.append("max_cost_usd")
45
+ if budget.get("max_wall_seconds") is not None and wall >= int(budget["max_wall_seconds"]):
46
+ violated.append("max_wall_seconds")
47
+ return violated
48
+
49
+
50
+ def per_role_limit(budget: dict[str, Any], role: str) -> int | None:
51
+ per = budget.get("per_role") or {}
52
+ entry = per.get(role) if isinstance(per, dict) else None
53
+ if isinstance(entry, dict):
54
+ v = entry.get("max_tokens")
55
+ if v is not None:
56
+ try:
57
+ return int(v)
58
+ except Exception:
59
+ return None
60
+ return None
61
+
62
+
63
+ def load_budget(run_dir: Path) -> dict[str, Any]:
64
+ p = run_dir / "budget.json"
65
+ if p.is_file():
66
+ try:
67
+ return json.loads(p.read_text(encoding="utf-8"))
68
+ except Exception:
69
+ return {}
70
+ return {}
71
+
72
+
73
+ def save_budget(run_dir: Path, budget: dict[str, Any], usage: dict[str, Any]) -> None:
74
+ from .store import atomic_write_json
75
+
76
+ data = {"budget": budget, "usage": usage}
77
+ atomic_write_json(run_dir / "budget.json", data)
78
+
79
+
80
+ def estimate_cost(tokens: int, price_per_mtok: float | None) -> float | None:
81
+ if price_per_mtok is None:
82
+ return None
83
+ return tokens / 1_000_000 * price_per_mtok