devcouncil 0.3.1 → 0.4.1

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 (366) hide show
  1. package/README.md +92 -33
  2. package/package.json +6 -2
  3. package/packages/codeintel-grammars/hatch_build.py +43 -0
  4. package/packages/codeintel-grammars/pyproject.toml +16 -0
  5. package/packages/codeintel-grammars/src/devcouncil_codeintel_grammars/__init__.py +93 -0
  6. package/pyproject.toml +99 -4
  7. package/src/devcouncil/app/config.py +512 -20
  8. package/src/devcouncil/app/events.py +4 -23
  9. package/src/devcouncil/app/orchestrator.py +5 -0
  10. package/src/devcouncil/app/run_context.py +3 -3
  11. package/src/devcouncil/assets/__init__.py +4 -1
  12. package/src/devcouncil/assets/vendor/force-graph.min.js +5 -0
  13. package/src/devcouncil/campaign/__init__.py +71 -0
  14. package/src/devcouncil/campaign/bloom.py +137 -0
  15. package/src/devcouncil/campaign/dashboard.py +123 -0
  16. package/src/devcouncil/campaign/mailbox.py +305 -0
  17. package/src/devcouncil/campaign/notify.py +91 -0
  18. package/src/devcouncil/campaign/orchestrator.py +592 -0
  19. package/src/devcouncil/campaign/prompts/coordinator.md +29 -0
  20. package/src/devcouncil/campaign/prompts/director.md +21 -0
  21. package/src/devcouncil/campaign/prompts/protocol.md +46 -0
  22. package/src/devcouncil/campaign/prompts/reviewer.md +24 -0
  23. package/src/devcouncil/campaign/prompts/worker.md +24 -0
  24. package/src/devcouncil/campaign/roles.py +202 -0
  25. package/src/devcouncil/campaign/watcher.py +153 -0
  26. package/src/devcouncil/cli/commands/agents.py +24 -17
  27. package/src/devcouncil/cli/commands/artifacts.py +36 -27
  28. package/src/devcouncil/cli/commands/ast.py +12 -3
  29. package/src/devcouncil/cli/commands/baseline.py +21 -12
  30. package/src/devcouncil/cli/commands/boot.py +218 -0
  31. package/src/devcouncil/cli/commands/campaign.py +302 -0
  32. package/src/devcouncil/cli/commands/check.py +225 -12
  33. package/src/devcouncil/cli/commands/config.py +221 -74
  34. package/src/devcouncil/cli/commands/cost.py +137 -28
  35. package/src/devcouncil/cli/commands/dashboard.py +12 -4
  36. package/src/devcouncil/cli/commands/debug_cmd.py +249 -0
  37. package/src/devcouncil/cli/commands/design.py +27 -17
  38. package/src/devcouncil/cli/commands/doctor.py +790 -8
  39. package/src/devcouncil/cli/commands/evidence.py +41 -20
  40. package/src/devcouncil/cli/commands/export.py +73 -0
  41. package/src/devcouncil/cli/commands/gaps.py +175 -0
  42. package/src/devcouncil/cli/commands/gated_write.py +76 -0
  43. package/src/devcouncil/cli/commands/go.py +220 -68
  44. package/src/devcouncil/cli/commands/graph_cmd.py +1192 -0
  45. package/src/devcouncil/cli/commands/handoff.py +45 -34
  46. package/src/devcouncil/cli/commands/hook.py +630 -85
  47. package/src/devcouncil/cli/commands/init.py +89 -30
  48. package/src/devcouncil/cli/commands/integrate.py +296 -1385
  49. package/src/devcouncil/cli/commands/lease.py +120 -0
  50. package/src/devcouncil/cli/commands/logs.py +12 -5
  51. package/src/devcouncil/cli/commands/lsp.py +40 -5
  52. package/src/devcouncil/cli/commands/map.py +317 -74
  53. package/src/devcouncil/cli/commands/mcp_server.py +12 -2
  54. package/src/devcouncil/cli/commands/okf.py +44 -6
  55. package/src/devcouncil/cli/commands/plan.py +184 -69
  56. package/src/devcouncil/cli/commands/prompt.py +26 -17
  57. package/src/devcouncil/cli/commands/provenance.py +79 -0
  58. package/src/devcouncil/cli/commands/repair.py +60 -49
  59. package/src/devcouncil/cli/commands/report.py +148 -40
  60. package/src/devcouncil/cli/commands/requirements.py +104 -0
  61. package/src/devcouncil/cli/commands/reset_demo_state.py +13 -4
  62. package/src/devcouncil/cli/commands/rollback.py +46 -35
  63. package/src/devcouncil/cli/commands/run.py +173 -8
  64. package/src/devcouncil/cli/commands/runs.py +298 -68
  65. package/src/devcouncil/cli/commands/scaffold.py +33 -12
  66. package/src/devcouncil/cli/commands/semantic.py +29 -14
  67. package/src/devcouncil/cli/commands/setup.py +103 -93
  68. package/src/devcouncil/cli/commands/shell.py +51 -42
  69. package/src/devcouncil/cli/commands/show.py +56 -42
  70. package/src/devcouncil/cli/commands/skills.py +29 -20
  71. package/src/devcouncil/cli/commands/status.py +80 -67
  72. package/src/devcouncil/cli/commands/task_gate.py +295 -0
  73. package/src/devcouncil/cli/commands/tasks.py +248 -19
  74. package/src/devcouncil/cli/commands/trace.py +14 -8
  75. package/src/devcouncil/cli/commands/verify.py +33 -8
  76. package/src/devcouncil/cli/commands/version.py +14 -6
  77. package/src/devcouncil/cli/commands/watch.py +56 -40
  78. package/src/devcouncil/cli/commands/watch_fs.py +30 -19
  79. package/src/devcouncil/cli/commands/wiki.py +278 -0
  80. package/src/devcouncil/cli/main.py +58 -1
  81. package/src/devcouncil/codeintel/__init__.py +16 -0
  82. package/src/devcouncil/codeintel/build_control.py +429 -0
  83. package/src/devcouncil/codeintel/build_worker.py +78 -0
  84. package/src/devcouncil/codeintel/debug/__init__.py +17 -0
  85. package/src/devcouncil/codeintel/debug/broker.py +114 -0
  86. package/src/devcouncil/codeintel/debug/broker_client.py +61 -0
  87. package/src/devcouncil/codeintel/debug/consent.py +36 -0
  88. package/src/devcouncil/codeintel/debug/discovery.py +132 -0
  89. package/src/devcouncil/codeintel/debug/fingerprint.py +85 -0
  90. package/src/devcouncil/codeintel/debug/protocol.py +259 -0
  91. package/src/devcouncil/codeintel/debug/python_trace_runner.py +81 -0
  92. package/src/devcouncil/codeintel/debug/session.py +238 -0
  93. package/src/devcouncil/codeintel/debug/tracing.py +201 -0
  94. package/src/devcouncil/codeintel/languages/__init__.py +17 -0
  95. package/src/devcouncil/codeintel/languages/generic_extractor.py +236 -0
  96. package/src/devcouncil/codeintel/languages/registry.py +149 -0
  97. package/src/devcouncil/codeintel/languages/workers.py +245 -0
  98. package/src/devcouncil/codeintel/query/__init__.py +5 -0
  99. package/src/devcouncil/codeintel/query/engine.py +289 -0
  100. package/src/devcouncil/codeintel/resolution/__init__.py +6 -0
  101. package/src/devcouncil/codeintel/resolution/abstract_state.py +301 -0
  102. package/src/devcouncil/codeintel/resolution/frameworks/__init__.py +33 -0
  103. package/src/devcouncil/codeintel/resolution/frameworks/base.py +46 -0
  104. package/src/devcouncil/codeintel/resolution/frameworks/di.py +56 -0
  105. package/src/devcouncil/codeintel/resolution/frameworks/events.py +45 -0
  106. package/src/devcouncil/codeintel/resolution/frameworks/routes.py +88 -0
  107. package/src/devcouncil/codeintel/resolution/semantic.py +887 -0
  108. package/src/devcouncil/codeintel/service.py +104 -0
  109. package/src/devcouncil/codeintel/store/__init__.py +15 -0
  110. package/src/devcouncil/codeintel/store/sqlite.py +1565 -0
  111. package/src/devcouncil/codeintel/sync/__init__.py +19 -0
  112. package/src/devcouncil/codeintel/sync/coordinator.py +430 -0
  113. package/src/devcouncil/codeintel/sync/incremental.py +484 -0
  114. package/src/devcouncil/codeintel/sync/lease.py +96 -0
  115. package/src/devcouncil/codeintel/sync/scope.py +98 -0
  116. package/src/devcouncil/council/__init__.py +4 -0
  117. package/src/devcouncil/council/prompts/__init__.py +4 -0
  118. package/src/devcouncil/domain/checkpoint_refs.py +17 -0
  119. package/src/devcouncil/domain/evidence.py +1 -0
  120. package/src/devcouncil/domain/gap.py +10 -0
  121. package/src/devcouncil/domain/requirement.py +5 -1
  122. package/src/devcouncil/domain/task.py +43 -2
  123. package/src/devcouncil/execution/checkpoints.py +25 -31
  124. package/src/devcouncil/execution/context_builder.py +15 -44
  125. package/src/devcouncil/execution/fs_watcher.py +64 -0
  126. package/src/devcouncil/execution/gated_write.py +203 -0
  127. package/src/devcouncil/execution/handoff.py +2 -1
  128. package/src/devcouncil/execution/hook_policy.py +19 -5
  129. package/src/devcouncil/execution/lease_ops.py +177 -0
  130. package/src/devcouncil/execution/lease_validation.py +71 -0
  131. package/src/devcouncil/execution/patch.py +3 -0
  132. package/src/devcouncil/execution/permissions.py +1 -0
  133. package/src/devcouncil/execution/policy_engine.py +205 -10
  134. package/src/devcouncil/execution/prompt_builder.py +278 -33
  135. package/src/devcouncil/execution/run_trace.py +356 -0
  136. package/src/devcouncil/execution/shell_session.py +46 -5
  137. package/src/devcouncil/execution/stop_gate.py +746 -0
  138. package/src/devcouncil/execution/stop_gate_history.py +113 -0
  139. package/src/devcouncil/execution/stop_gate_state.py +54 -0
  140. package/src/devcouncil/execution/stop_gate_verify_cache.py +69 -0
  141. package/src/devcouncil/execution/task_gate_ops.py +590 -0
  142. package/src/devcouncil/execution/task_runner.py +19 -0
  143. package/src/devcouncil/executors/advisor_tool.py +315 -0
  144. package/src/devcouncil/executors/agent_registry.py +125 -17
  145. package/src/devcouncil/executors/claude_sdk.py +376 -0
  146. package/src/devcouncil/executors/coding_cli.py +724 -25
  147. package/src/devcouncil/executors/mini_swe.py +50 -8
  148. package/src/devcouncil/executors/native/agent.py +224 -19
  149. package/src/devcouncil/executors/openhands.py +50 -8
  150. package/src/devcouncil/executors/transient_retry.py +99 -0
  151. package/src/devcouncil/gating/checks/clean_git.py +5 -2
  152. package/src/devcouncil/gating/checks/planned_files_check.py +38 -11
  153. package/src/devcouncil/gating/checks/secret_scan_check.py +2 -2
  154. package/src/devcouncil/gating/policy.py +46 -2
  155. package/src/devcouncil/indexing/ast_matcher.py +41 -4
  156. package/src/devcouncil/indexing/graph/__init__.py +78 -0
  157. package/src/devcouncil/indexing/graph/api_routes.py +522 -0
  158. package/src/devcouncil/indexing/graph/build.py +862 -0
  159. package/src/devcouncil/indexing/graph/cache.py +329 -0
  160. package/src/devcouncil/indexing/graph/communities.py +28 -0
  161. package/src/devcouncil/indexing/graph/cypher.py +107 -0
  162. package/src/devcouncil/indexing/graph/embeddings.py +194 -0
  163. package/src/devcouncil/indexing/graph/export.py +381 -0
  164. package/src/devcouncil/indexing/graph/export_links.py +81 -0
  165. package/src/devcouncil/indexing/graph/extract_python.py +307 -0
  166. package/src/devcouncil/indexing/graph/extract_ts.py +1205 -0
  167. package/src/devcouncil/indexing/graph/intel.py +668 -0
  168. package/src/devcouncil/indexing/graph/liveness.py +992 -0
  169. package/src/devcouncil/indexing/graph/okf_export.py +65 -0
  170. package/src/devcouncil/indexing/graph/pdg/__init__.py +67 -0
  171. package/src/devcouncil/indexing/graph/pdg/build.py +11 -0
  172. package/src/devcouncil/indexing/graph/pdg/cdg.py +41 -0
  173. package/src/devcouncil/indexing/graph/pdg/cfg.py +199 -0
  174. package/src/devcouncil/indexing/graph/pdg/query.py +21 -0
  175. package/src/devcouncil/indexing/graph/pdg/reaching_def.py +126 -0
  176. package/src/devcouncil/indexing/graph/pdg/schema.py +253 -0
  177. package/src/devcouncil/indexing/graph/pdg/taint.py +154 -0
  178. package/src/devcouncil/indexing/graph/query.py +302 -0
  179. package/src/devcouncil/indexing/graph/resolve.py +1020 -0
  180. package/src/devcouncil/indexing/graph/schema.py +103 -0
  181. package/src/devcouncil/indexing/graph_index.py +20 -29
  182. package/src/devcouncil/indexing/lsp.py +57 -25
  183. package/src/devcouncil/indexing/lsp_client.py +577 -0
  184. package/src/devcouncil/indexing/map_artifacts.py +355 -0
  185. package/src/devcouncil/indexing/map_refresh.py +141 -0
  186. package/src/devcouncil/indexing/repo_mapper.py +1509 -138
  187. package/src/devcouncil/indexing/semantic_index.py +12 -6
  188. package/src/devcouncil/indexing/subsystem_map.py +163 -0
  189. package/src/devcouncil/indexing/ts_imports.py +343 -0
  190. package/src/devcouncil/indexing/viz.py +964 -0
  191. package/src/devcouncil/indexing/walk.py +52 -0
  192. package/src/devcouncil/indexing/wiring.py +1776 -0
  193. package/src/devcouncil/integrations/actions.py +27 -4
  194. package/src/devcouncil/integrations/check.py +211 -16
  195. package/src/devcouncil/integrations/claude_assets.py +209 -12
  196. package/src/devcouncil/integrations/clients/__init__.py +1 -0
  197. package/src/devcouncil/integrations/clients/aider.py +52 -0
  198. package/src/devcouncil/integrations/clients/antigravity.py +87 -0
  199. package/src/devcouncil/integrations/clients/claude.py +339 -0
  200. package/src/devcouncil/integrations/clients/codex.py +39 -0
  201. package/src/devcouncil/integrations/clients/common.py +332 -0
  202. package/src/devcouncil/integrations/clients/cursor.py +164 -0
  203. package/src/devcouncil/integrations/clients/gemini.py +49 -0
  204. package/src/devcouncil/integrations/clients/grok.py +105 -0
  205. package/src/devcouncil/integrations/clients/hooks.py +500 -0
  206. package/src/devcouncil/integrations/clients/opencode.py +96 -0
  207. package/src/devcouncil/integrations/clients/warp.py +75 -0
  208. package/src/devcouncil/integrations/code_review_graph.py +2 -2
  209. package/src/devcouncil/integrations/github.py +73 -7
  210. package/src/devcouncil/integrations/integration_cli.py +197 -0
  211. package/src/devcouncil/integrations/mcp/handlers/__init__.py +1 -0
  212. package/src/devcouncil/integrations/mcp/handlers/ast_lsp.py +77 -0
  213. package/src/devcouncil/integrations/mcp/handlers/checkout.py +50 -0
  214. package/src/devcouncil/integrations/mcp/handlers/cli_gate.py +43 -0
  215. package/src/devcouncil/integrations/mcp/handlers/codeintel.py +182 -0
  216. package/src/devcouncil/integrations/mcp/handlers/debug.py +236 -0
  217. package/src/devcouncil/integrations/mcp/handlers/evidence.py +70 -0
  218. package/src/devcouncil/integrations/mcp/handlers/git.py +281 -0
  219. package/src/devcouncil/integrations/mcp/handlers/graph.py +34 -0
  220. package/src/devcouncil/integrations/mcp/handlers/handoff.py +53 -0
  221. package/src/devcouncil/integrations/mcp/handlers/knowledge.py +28 -0
  222. package/src/devcouncil/integrations/mcp/handlers/lease.py +70 -0
  223. package/src/devcouncil/integrations/mcp/handlers/live.py +108 -0
  224. package/src/devcouncil/integrations/mcp/handlers/map.py +676 -0
  225. package/src/devcouncil/integrations/mcp/handlers/next_task.py +35 -0
  226. package/src/devcouncil/integrations/mcp/handlers/policy.py +80 -0
  227. package/src/devcouncil/integrations/mcp/handlers/prompts.py +168 -0
  228. package/src/devcouncil/integrations/mcp/handlers/provenance.py +87 -0
  229. package/src/devcouncil/integrations/mcp/handlers/read.py +103 -0
  230. package/src/devcouncil/integrations/mcp/handlers/router_cache.py +53 -0
  231. package/src/devcouncil/integrations/mcp/handlers/run.py +53 -0
  232. package/src/devcouncil/integrations/mcp/handlers/runs.py +69 -0
  233. package/src/devcouncil/integrations/mcp/handlers/scope.py +56 -0
  234. package/src/devcouncil/integrations/mcp/handlers/status.py +199 -0
  235. package/src/devcouncil/integrations/mcp/handlers/task.py +88 -0
  236. package/src/devcouncil/integrations/mcp/handlers/tool_specs.py +922 -0
  237. package/src/devcouncil/integrations/mcp/handlers/trace.py +65 -0
  238. package/src/devcouncil/integrations/mcp/handlers/verify.py +45 -0
  239. package/src/devcouncil/integrations/mcp/handlers/wiki.py +53 -0
  240. package/src/devcouncil/integrations/mcp/handlers/write.py +69 -0
  241. package/src/devcouncil/integrations/mcp/server.py +265 -2391
  242. package/src/devcouncil/integrations/mcp/util.py +325 -0
  243. package/src/devcouncil/integrations/setup.py +152 -0
  244. package/src/devcouncil/knowledge/fetch.py +4 -0
  245. package/src/devcouncil/knowledge/knowledge_select.py +38 -0
  246. package/src/devcouncil/knowledge/okf.py +2 -1
  247. package/src/devcouncil/knowledge/resource_discovery.py +40 -0
  248. package/src/devcouncil/knowledge/wiki.py +643 -0
  249. package/src/devcouncil/knowledge/wiki_read.py +87 -0
  250. package/src/devcouncil/live/cards.py +7 -7
  251. package/src/devcouncil/live/models.py +4 -1
  252. package/src/devcouncil/live/reviewer.py +90 -11
  253. package/src/devcouncil/live/signals.py +4 -2
  254. package/src/devcouncil/live/summary.py +21 -3
  255. package/src/devcouncil/live/tasks.py +12 -3
  256. package/src/devcouncil/live/transcripts.py +69 -2
  257. package/src/devcouncil/llm/cache.py +5 -6
  258. package/src/devcouncil/llm/model_defaults.yaml +10 -10
  259. package/src/devcouncil/llm/provider.py +647 -73
  260. package/src/devcouncil/llm/router.py +271 -46
  261. package/src/devcouncil/llm/semantic_bridge.py +614 -0
  262. package/src/devcouncil/optimization/gepa_agent.py +6 -4
  263. package/src/devcouncil/optimization/skillopt.py +9 -5
  264. package/src/devcouncil/planning/arbiter_service.py +12 -3
  265. package/src/devcouncil/planning/correction_manifest.py +107 -10
  266. package/src/devcouncil/planning/plan_difficulty.py +69 -0
  267. package/src/devcouncil/planning/plan_service.py +5 -2
  268. package/src/devcouncil/planning/planned_files_reconcile.py +191 -0
  269. package/src/devcouncil/planning/prompt_enhancer_service.py +6 -5
  270. package/src/devcouncil/planning/question_conversion.py +56 -0
  271. package/src/devcouncil/planning/spec_service.py +9 -3
  272. package/src/devcouncil/repo/ci_scaffold.py +197 -1
  273. package/src/devcouncil/repo/gitignore.py +1 -2
  274. package/src/devcouncil/reporting/evidence_export.py +124 -0
  275. package/src/devcouncil/reporting/evidence_html.py +210 -0
  276. package/src/devcouncil/reporting/json_report.py +16 -12
  277. package/src/devcouncil/reporting/markdown_report.py +38 -9
  278. package/src/devcouncil/reporting/mcp_resources.py +142 -0
  279. package/src/devcouncil/reporting/report_builder.py +40 -4
  280. package/src/devcouncil/reporting/task_provenance.py +42 -0
  281. package/src/devcouncil/reporting/verdict.py +75 -0
  282. package/src/devcouncil/skills/library/README.md +1 -0
  283. package/src/devcouncil/skills/library/devcouncil-hero-loop.md +109 -0
  284. package/src/devcouncil/skills/library/devcouncil-verification.md +109 -0
  285. package/src/devcouncil/skills/library/devcouncil.md +93 -0
  286. package/src/devcouncil/skills/registry.py +43 -12
  287. package/src/devcouncil/storage/db.py +57 -11
  288. package/src/devcouncil/storage/models.py +6 -0
  289. package/src/devcouncil/storage/native.py +5 -3
  290. package/src/devcouncil/storage/repositories.py +50 -18
  291. package/src/devcouncil/telemetry/context.py +28 -0
  292. package/src/devcouncil/telemetry/cost.py +4 -5
  293. package/src/devcouncil/telemetry/logging_setup.py +78 -11
  294. package/src/devcouncil/telemetry/model_pricing.yaml +7 -0
  295. package/src/devcouncil/telemetry/stages.py +27 -2
  296. package/src/devcouncil/telemetry/tracker.py +50 -13
  297. package/src/devcouncil/ui/dashboard.py +120 -8
  298. package/src/devcouncil/utils/fsio.py +58 -0
  299. package/src/devcouncil/utils/git_snapshot.py +112 -0
  300. package/src/devcouncil/utils/json_persist.py +53 -0
  301. package/src/devcouncil/utils/proc.py +89 -0
  302. package/src/devcouncil/verification/acceptance_compiler.py +36 -13
  303. package/src/devcouncil/verification/ad_hoc_check.py +95 -3
  304. package/src/devcouncil/verification/checks/__init__.py +41 -0
  305. package/src/devcouncil/verification/checks/acceptance.py +39 -0
  306. package/src/devcouncil/verification/checks/acceptance_corpus.py +194 -0
  307. package/src/devcouncil/verification/checks/acceptance_evidence.py +239 -0
  308. package/src/devcouncil/verification/checks/command_evidence.py +148 -0
  309. package/src/devcouncil/verification/checks/compiled_acceptance.py +179 -0
  310. package/src/devcouncil/verification/checks/corpus_stale.py +124 -0
  311. package/src/devcouncil/verification/checks/corpus_verification.py +9 -0
  312. package/src/devcouncil/verification/checks/dead_symbols.py +360 -0
  313. package/src/devcouncil/verification/checks/diff_coverage_gate.py +101 -0
  314. package/src/devcouncil/verification/checks/doc_code_ref.py +79 -0
  315. package/src/devcouncil/verification/checks/liveness_ratchet.py +336 -0
  316. package/src/devcouncil/verification/checks/orphan_diff.py +104 -0
  317. package/src/devcouncil/verification/checks/planned_files.py +98 -0
  318. package/src/devcouncil/verification/checks/semantic_diff.py +241 -0
  319. package/src/devcouncil/verification/checks/stale_map.py +80 -0
  320. package/src/devcouncil/verification/checks/stub_scan.py +71 -0
  321. package/src/devcouncil/verification/checks/subsystem_boundary.py +103 -0
  322. package/src/devcouncil/verification/checks/wiring.py +216 -0
  323. package/src/devcouncil/verification/claims/__init__.py +23 -0
  324. package/src/devcouncil/verification/claims/checks.py +395 -0
  325. package/src/devcouncil/verification/claims/mapper.py +168 -0
  326. package/src/devcouncil/verification/claims/models.py +39 -0
  327. package/src/devcouncil/verification/claims/transcript.py +92 -0
  328. package/src/devcouncil/verification/claims/verdict.py +88 -0
  329. package/src/devcouncil/verification/command_evidence.py +170 -0
  330. package/src/devcouncil/verification/command_malformation.py +147 -0
  331. package/src/devcouncil/verification/command_runner.py +164 -0
  332. package/src/devcouncil/verification/coverage_measurement.py +292 -0
  333. package/src/devcouncil/verification/diff_coverage.py +151 -0
  334. package/src/devcouncil/verification/difficulty.py +296 -0
  335. package/src/devcouncil/verification/effort_heuristics.py +178 -0
  336. package/src/devcouncil/verification/gap_ids.py +63 -0
  337. package/src/devcouncil/verification/gate_cache.py +194 -0
  338. package/src/devcouncil/verification/gate_selector.py +344 -0
  339. package/src/devcouncil/verification/git_diff_fallback.py +272 -0
  340. package/src/devcouncil/verification/implementation_reviewer.py +13 -0
  341. package/src/devcouncil/verification/incremental_check.py +241 -0
  342. package/src/devcouncil/verification/next_actions.py +60 -1
  343. package/src/devcouncil/verification/rigor_analytics.py +130 -0
  344. package/src/devcouncil/verification/sandbox.py +38 -11
  345. package/src/devcouncil/verification/stub_detector.py +369 -0
  346. package/src/devcouncil/verification/test_resolver.py +67 -1
  347. package/src/devcouncil/verification/verifier.py +137 -1666
  348. package/src/devcouncil/verification/verify_orchestration.py +610 -0
  349. package/src/devcouncil/verification/verify_setup.py +176 -0
  350. package/src/devcouncil/verification/wiki_refresh.py +208 -0
  351. package/src/semantic_layer/__init__.py +58 -0
  352. package/src/semantic_layer/benchmark.py +75 -0
  353. package/src/semantic_layer/cache.py +290 -0
  354. package/src/semantic_layer/compressor.py +137 -0
  355. package/src/semantic_layer/config.py +75 -0
  356. package/src/semantic_layer/embeddings.py +69 -0
  357. package/src/semantic_layer/llm_backends.py +99 -0
  358. package/src/semantic_layer/pipeline.py +111 -0
  359. package/src/semantic_layer/router.py +128 -0
  360. package/src/semantic_layer/tuner.py +72 -0
  361. package/uv.lock +973 -9
  362. package/src/devcouncil/artifacts/migrations.py +0 -20
  363. package/src/devcouncil/artifacts/schemas.py +0 -23
  364. package/src/devcouncil/artifacts/serializer.py +0 -21
  365. package/src/devcouncil/integrations/gitnexus.py +0 -70
  366. package/src/devcouncil/integrations/graphify.py +0 -34
@@ -26,7 +26,9 @@ import json
26
26
  from dataclasses import dataclass
27
27
  from pathlib import Path
28
28
 
29
+ from devcouncil.executors.advisor_tool import ADVISOR_STEERING_NUDGE
29
30
  from devcouncil.knowledge.frontmatter import build_frontmatter_markdown
31
+ from devcouncil.integrations.clients.hooks import SESSION_START_MATCHER
30
32
 
31
33
  # Tools a DevCouncil subagent should be allowed to use: the standard read/edit/run set
32
34
  # plus the DevCouncil MCP tools it drives the task loop with. Listing the MCP tools keeps
@@ -90,7 +92,8 @@ def _slash_commands() -> list[_SlashCommand]:
90
92
  "MCP tools to implement it: call `mcp__devcouncil__devcouncil_next_task`, then "
91
93
  "`mcp__devcouncil__devcouncil_checkout_task` to acquire a lease, make changes only "
92
94
  "through the policy-gated write tools, run tests, then "
93
- "`mcp__devcouncil__devcouncil_verify_task` and release the lease when verified."
95
+ "`mcp__devcouncil__devcouncil_verify_task` and release the lease when verified. "
96
+ f"{ADVISOR_STEERING_NUDGE}"
94
97
  ),
95
98
  allowed_tools="Bash(dev tasks:*)",
96
99
  ),
@@ -113,7 +116,7 @@ def _slash_commands() -> list[_SlashCommand]:
113
116
  body=(
114
117
  "Work through the repair guidance above. Apply the smallest changes that close the "
115
118
  "blocking gaps via the policy-gated DevCouncil write tools, then re-run "
116
- "`/devcouncil:verify` until the task is clean."
119
+ f"`/devcouncil:verify` until the task is clean. {ADVISOR_STEERING_NUDGE}"
117
120
  ),
118
121
  allowed_tools="Bash(dev repair:*)",
119
122
  ),
@@ -152,6 +155,46 @@ def _slash_commands() -> list[_SlashCommand]:
152
155
  ),
153
156
  allowed_tools="Bash(dev report:*)",
154
157
  ),
158
+ _SlashCommand(
159
+ name="map",
160
+ description="Build or refresh the deterministic repository map (no LLM).",
161
+ argument_hint="[goal]",
162
+ bash="dev map $ARGUMENTS",
163
+ body=(
164
+ "Summarize the repository map above: languages, frameworks, test commands, and "
165
+ "the most relevant entry points for the stated goal (if any). Point the user at "
166
+ "`.devcouncil/repo_map.json` for the full index and recommend `/devcouncil:next` "
167
+ "or `/devcouncil:plan` as the next step."
168
+ ),
169
+ allowed_tools="Bash(dev map:*)",
170
+ ),
171
+ _SlashCommand(
172
+ name="wiki",
173
+ description="Consult the generated codebase wiki for a topic or subsystem.",
174
+ argument_hint="[topic]",
175
+ bash="dev wiki status",
176
+ body=(
177
+ "The codebase wiki status is shown above. Use "
178
+ "`mcp__devcouncil__devcouncil_wiki_page` with query \"$ARGUMENTS\" (or no "
179
+ "arguments for the index) to read the relevant subsystem page(s), and "
180
+ "summarize what they say about the topic before making changes. If pages "
181
+ "are stale, suggest running `dev wiki update`."
182
+ ),
183
+ allowed_tools="Bash(dev wiki:*)",
184
+ ),
185
+ _SlashCommand(
186
+ name="supervise",
187
+ description="Review a recorded agent run and decide keep/revert/repair.",
188
+ argument_hint="[RUN-ID or TASK-ID]",
189
+ bash="dev runs list",
190
+ body=(
191
+ "The recorded runs are listed above. For the run the user named (or the "
192
+ "newest relevant one), run `dev runs supervise $ARGUMENTS` and present the "
193
+ "verdict with its findings. If the verdict is revert, show `dev runs diff "
194
+ "$ARGUMENTS` and ask before running `dev runs revert $ARGUMENTS`."
195
+ ),
196
+ allowed_tools="Bash(dev runs:*)",
197
+ ),
155
198
  ]
156
199
 
157
200
 
@@ -169,6 +212,34 @@ def _slash_command_markdown(cmd: _SlashCommand) -> str:
169
212
  return build_frontmatter_markdown(meta, "\n".join(lines))
170
213
 
171
214
 
215
+ # Bash permission rules merged into .claude/settings.local.json so slash commands and
216
+ # common hero-loop CLIs run without interactive approval. Kept here (with the slash
217
+ # commands) so the allow-list stays in sync with generated command allowed-tools.
218
+ _EXTRA_BASH_PERMISSIONS = (
219
+ "Bash(dev go:*)",
220
+ "Bash(dev check:*)",
221
+ "Bash(dev gaps:*)",
222
+ "Bash(dev export:*)",
223
+ "Bash(dev doctor:*)",
224
+ "Bash(devcouncil mcp-server)",
225
+ )
226
+
227
+
228
+ def claude_bash_permission_allow() -> list[str]:
229
+ """Ordered, de-duplicated Bash allow-rules for Claude Code settings merge."""
230
+ seen: set[str] = set()
231
+ rules: list[str] = []
232
+ for cmd in _slash_commands():
233
+ if cmd.allowed_tools and cmd.allowed_tools not in seen:
234
+ seen.add(cmd.allowed_tools)
235
+ rules.append(cmd.allowed_tools)
236
+ for rule in _EXTRA_BASH_PERMISSIONS:
237
+ if rule not in seen:
238
+ seen.add(rule)
239
+ rules.append(rule)
240
+ return rules
241
+
242
+
172
243
  def build_slash_commands(root: Path) -> list[GeneratedAsset]:
173
244
  base = root / ".claude" / "commands" / "devcouncil"
174
245
  return [
@@ -237,8 +308,9 @@ def _subagents() -> list[_Subagent]:
237
308
  "and `devcouncil_get_diff` to inspect.\n"
238
309
  "3. Change files only via `devcouncil_write_file` / `devcouncil_apply_patch` (the gate "
239
310
  "rejects out-of-scope or protected paths) and run tests via `devcouncil_run_command`.\n"
240
- "4. `devcouncil_verify_task`; fix any blocking gaps and re-verify.\n"
241
- "5. `devcouncil_release_task` when verified.\n\n"
311
+ f"4. {ADVISOR_STEERING_NUDGE}\n"
312
+ "5. `devcouncil_verify_task`; fix any blocking gaps and re-verify.\n"
313
+ "6. `devcouncil_release_task` when verified.\n\n"
242
314
  "Never touch files outside the task scope. Report the final status and remaining gaps."
243
315
  ),
244
316
  ),
@@ -314,6 +386,7 @@ def build_output_style(root: Path) -> list[GeneratedAsset]:
314
386
  "`file:line`. Do not call work done while blocking gaps remain.\n"
315
387
  "- When unsure of project conventions, consult `.devcouncil/repo_map.json` and the "
316
388
  "applicable skills before writing code.\n"
389
+ f"- {ADVISOR_STEERING_NUDGE}\n"
317
390
  "- Be concise: report what changed, what was verified, and what is still blocking."
318
391
  )
319
392
  return [GeneratedAsset(root / ".claude" / "output-styles" / "devcouncil.md", build_frontmatter_markdown(meta, body))]
@@ -364,23 +437,26 @@ def _marketplace_json(version: str) -> str:
364
437
  def _plugin_hooks_json(*, write_gate: bool = False) -> str:
365
438
  """hooks.json for the plugin, resolving the project root via ${CLAUDE_PROJECT_DIR}.
366
439
 
367
- Assist-mode by default (no blocking write-gate) so installing the plugin into an
368
- interactive session never fail-closes it. The blocking PreToolUse/PostToolUse gate is
369
- included only when ``write_gate`` is True."""
440
+ Assist-mode by default installs refresh-only PostToolUse (never gates writes) plus
441
+ lifecycle hooks. The blocking PreToolUse write-gate is included only when
442
+ ``write_gate`` is True."""
370
443
  def cmd(event: str) -> str:
371
444
  return f'devcouncil hook {event} --client claude --project-root "${{CLAUDE_PROJECT_DIR}}"'
372
445
 
446
+ tool_matcher = "Bash|Write|Edit|MultiEdit"
373
447
  hooks: dict[str, list] = {
374
- "Stop": [{"hooks": [{"type": "command", "command": cmd("agent-response"), "timeout": 10000}]}],
375
- "SessionStart": [{"matcher": "startup|resume", "hooks": [{"type": "command", "command": cmd("session-start"), "timeout": 10000}]}],
448
+ "PostToolUse": [{"matcher": tool_matcher, "hooks": [{"type": "command", "command": cmd("post-tool-use"), "timeout": 10000}]}],
449
+ "Stop": [{"hooks": [{"type": "command", "command": cmd("agent-response"), "timeout": 150000}]}],
450
+ "SessionStart": [{"matcher": SESSION_START_MATCHER, "hooks": [{"type": "command", "command": cmd("session-start"), "timeout": 10000}]}],
376
451
  "UserPromptSubmit": [{"hooks": [{"type": "command", "command": cmd("user-prompt-submit"), "timeout": 10000}]}],
377
- "SubagentStop": [{"hooks": [{"type": "command", "command": cmd("subagent-stop"), "timeout": 10000}]}],
452
+ "SessionEnd": [{"hooks": [{"type": "command", "command": cmd("session-end"), "timeout": 10000}]}],
453
+ "PreCompact": [{"hooks": [{"type": "command", "command": cmd("pre-compact"), "timeout": 10000}]}],
454
+ "PostCompact": [{"hooks": [{"type": "command", "command": cmd("post-compact"), "timeout": 10000}]}],
455
+ "SubagentStop": [{"hooks": [{"type": "command", "command": cmd("subagent-stop"), "timeout": 150000}]}],
378
456
  "Notification": [{"hooks": [{"type": "command", "command": cmd("notification"), "timeout": 10000}]}],
379
457
  }
380
458
  if write_gate:
381
- tool_matcher = "Bash|Write|Edit|MultiEdit"
382
459
  hooks["PreToolUse"] = [{"matcher": tool_matcher, "hooks": [{"type": "command", "command": cmd("pre-tool-use"), "timeout": 10000}]}]
383
- hooks["PostToolUse"] = [{"matcher": tool_matcher, "hooks": [{"type": "command", "command": cmd("post-tool-use"), "timeout": 10000}]}]
384
460
  return json.dumps({"hooks": hooks}, indent=2) + "\n"
385
461
 
386
462
 
@@ -398,6 +474,122 @@ def _plugin_mcp_json(root: Path) -> str:
398
474
  return json.dumps(config, indent=2) + "\n"
399
475
 
400
476
 
477
+ def _plugin_lsp_json(root: Path) -> str | None:
478
+ """Build the plugin's ``.lsp.json`` from DevCouncil's language-server detection.
479
+
480
+ DevCouncil already knows which LSP servers match the repo's languages (it detects
481
+ them for the repo map); this ships that knowledge to Claude Code so the plugin grants
482
+ real code intelligence (go-to-definition, references, diagnostics) instead of only
483
+ detecting servers. One server per detected language (the preferred candidate), keyed by
484
+ language name, in Claude Code's documented schema: ``command`` + ``args`` +
485
+ ``extensionToLanguage``. The consumer still installs the binary (Claude Code flags a
486
+ missing one in ``/plugin`` Errors). Returns None when the repo has no supported
487
+ languages, so the bundle simply omits the file."""
488
+ from devcouncil.indexing.lsp import LspInspector
489
+
490
+ inspector = LspInspector(root)
491
+ ext_by_language: dict[str, dict[str, str]] = {}
492
+ for ext, language in LspInspector._EXTENSIONS.items():
493
+ ext_by_language.setdefault(language, {})[ext] = language
494
+
495
+ servers: dict[str, dict] = {}
496
+ for candidate in inspector.server_candidates():
497
+ if candidate.language in servers:
498
+ continue # first (preferred) candidate per language wins
499
+ command = list(candidate.command)
500
+ entry: dict = {"command": command[0]}
501
+ if command[1:]:
502
+ entry["args"] = command[1:]
503
+ entry["extensionToLanguage"] = ext_by_language.get(candidate.language, {})
504
+ servers[candidate.language] = entry
505
+
506
+ if not servers:
507
+ return None
508
+ return json.dumps(servers, indent=2) + "\n"
509
+
510
+
511
+ _GITHUB_WORKFLOW = """\
512
+ # DevCouncil + Claude Code — event-driven task runner.
513
+ #
514
+ # Generated by `dev integrate claude-github`. This is the stable-primitive alternative to
515
+ # Claude Code's (experimental) cloud Routines: it runs DevCouncil's verify loop on pull
516
+ # requests and, on demand or on a schedule, hands the next task to headless Claude Code —
517
+ # staying inside DevCouncil's evidence/verify gate the whole way.
518
+ #
519
+ # Setup: add an ANTHROPIC_API_KEY repository secret for the autonomous (dispatch/schedule)
520
+ # runs. The pull_request job needs no secret; it only runs read-only verification.
521
+ name: DevCouncil
522
+
523
+ on:
524
+ pull_request:
525
+ workflow_dispatch:
526
+ schedule:
527
+ - cron: "0 6 * * *" # nightly task pickup (UTC); adjust or remove as needed
528
+
529
+ permissions:
530
+ contents: read
531
+ pull-requests: write
532
+
533
+ jobs:
534
+ verify:
535
+ # Read-only DevCouncil verification on every PR — no model calls, no secrets.
536
+ if: github.event_name == 'pull_request'
537
+ runs-on: ubuntu-latest
538
+ steps:
539
+ - uses: actions/checkout@v4
540
+ - uses: astral-sh/setup-uv@v7
541
+ - name: Install DevCouncil
542
+ run: |
543
+ uv tool install devcouncil
544
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH" # put the dev/devcouncil CLIs on PATH
545
+ - name: Verify project state
546
+ run: |
547
+ dev status
548
+ dev report
549
+
550
+ autonomous:
551
+ # On demand or on schedule: let headless Claude Code pick up and implement the next task
552
+ # through the DevCouncil MCP loop, then verify.
553
+ if: github.event_name != 'pull_request'
554
+ runs-on: ubuntu-latest
555
+ steps:
556
+ - uses: actions/checkout@v4
557
+ - uses: astral-sh/setup-uv@v7
558
+ - uses: actions/setup-node@v5
559
+ with:
560
+ node-version: "24"
561
+ - name: Install DevCouncil and Claude Code
562
+ run: |
563
+ uv tool install devcouncil
564
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH" # put the dev/devcouncil CLIs on PATH
565
+ npm install -g @anthropic-ai/claude-code
566
+ - name: Wire DevCouncil into Claude Code
567
+ run: dev integrate claude --apply
568
+ - name: Implement next task (headless, gated)
569
+ env:
570
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
571
+ # --dangerously-skip-permissions is appropriate here: the runner is an ephemeral
572
+ # sandbox, and DevCouncil's own scope gate + the verify step below still constrain
573
+ # the result. Without it, headless Claude blocks on MCP-tool permission prompts.
574
+ run: |
575
+ claude -p --dangerously-skip-permissions --output-format json \\
576
+ "Use the DevCouncil MCP tools to implement the next task: call \\
577
+ mcp__devcouncil__devcouncil_next_task, checkout a lease, make only the \\
578
+ authorized changes, then verify and release the lease."
579
+ - name: Verify result
580
+ run: dev verify || true
581
+ """
582
+
583
+
584
+ def build_github_workflow(root: Path) -> GeneratedAsset:
585
+ """Generate ``.github/workflows/devcouncil.yml``.
586
+
587
+ Delivers the event-driven-run value of Claude Code Routines using stable primitives
588
+ (GitHub Actions + headless Claude Code) instead of the experimental cloud API: read-only
589
+ DevCouncil verification on PRs, and gated autonomous task pickup on dispatch/schedule."""
590
+ return GeneratedAsset(root / ".github" / "workflows" / "devcouncil.yml", _GITHUB_WORKFLOW)
591
+
592
+
401
593
  def _plugin_readme() -> str:
402
594
  return (
403
595
  "# DevCouncil Claude Code plugin\n\n"
@@ -426,6 +618,11 @@ def build_plugin_bundle(
426
618
  GeneratedAsset(plugin / ".mcp.json", _plugin_mcp_json(root)),
427
619
  GeneratedAsset(plugin / "README.md", _plugin_readme()),
428
620
  ]
621
+ # Ship an .lsp.json (auto-discovered at plugin root) for the repo's languages, so the
622
+ # plugin delivers live code intelligence — omitted entirely when nothing is detected.
623
+ lsp_config = _plugin_lsp_json(root)
624
+ if lsp_config:
625
+ assets.append(GeneratedAsset(plugin / ".lsp.json", lsp_config))
429
626
  # Bundle command + agent copies into the plugin tree (plugin layout puts them at the
430
627
  # plugin root, not under .claude/).
431
628
  for cmd in _slash_commands():
@@ -0,0 +1 @@
1
+ """Per-client integration adapters for coding CLIs."""
@@ -0,0 +1,52 @@
1
+ """Aider integration adapter."""
2
+ from __future__ import annotations
3
+
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+
8
+
9
+ from devcouncil.integrations.clients import common as _common
10
+ _project_root = _common._project_root
11
+ _warn_if_verify_only = _common._warn_if_verify_only
12
+ _server_args = _common._server_args
13
+ _format_command = _common._format_command
14
+ _quote_powershell_arg = _common._quote_powershell_arg
15
+ _run = _common._run
16
+ _run_capture = _common._run_capture
17
+ _config_path = _common._config_path
18
+ _load_raw_config = _common._load_raw_config
19
+ _save_raw_config = _common._save_raw_config
20
+ _load_json = _common._load_json
21
+ _save_json = _common._save_json
22
+ _load_json_strict = _common._load_json_strict
23
+ _mutate_raw_config = _common._mutate_raw_config
24
+ _batched_raw_config = _common._batched_raw_config
25
+ _probe_mcp_tools = _common._probe_mcp_tools
26
+ _print_command = _common._print_command
27
+ _configure = _common._configure
28
+
29
+ console = _common.console
30
+ def _record_aider_config(project_root: Path) -> None:
31
+ def mutate(config: dict) -> None:
32
+ config.setdefault("integrations", {}).setdefault("aider", {}).update({"enabled": True})
33
+
34
+ _mutate_raw_config(project_root, mutate)
35
+
36
+
37
+ def _configure_aider(project_root: Path, apply: bool) -> bool:
38
+ command = ["aider", "--yes", "--no-show-model-warnings", "--message", "<task prompt>"]
39
+ if not apply:
40
+ console.print("[bold]Aider[/bold]")
41
+ console.print("Built-in executor: [dim]dev run TASK-001 --executor aider[/dim]")
42
+ console.print("Launch command: [dim]" + _format_command(command) + "[/dim]")
43
+ console.print("Aider does not expose a first-party DevCouncil MCP server.")
44
+ return True
45
+
46
+ if not shutil.which("aider"):
47
+ console.print("[yellow]Aider CLI not found on PATH. Install it before using `dev run --executor aider`.[/yellow]")
48
+ _record_aider_config(project_root)
49
+ console.print("[green]Aider executor enabled in .devcouncil/config.yaml.[/green]")
50
+ return True
51
+
52
+
@@ -0,0 +1,87 @@
1
+ """Antigravity integration adapter."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import shutil
6
+ from pathlib import Path
7
+
8
+
9
+
10
+ from devcouncil.integrations.clients import common as _common
11
+ _project_root = _common._project_root
12
+ _warn_if_verify_only = _common._warn_if_verify_only
13
+ _server_args = _common._server_args
14
+ _format_command = _common._format_command
15
+ _quote_powershell_arg = _common._quote_powershell_arg
16
+ _run = _common._run
17
+ _run_capture = _common._run_capture
18
+ _config_path = _common._config_path
19
+ _load_raw_config = _common._load_raw_config
20
+ _save_raw_config = _common._save_raw_config
21
+ _load_json = _common._load_json
22
+ _save_json = _common._save_json
23
+ _load_json_strict = _common._load_json_strict
24
+ _mutate_raw_config = _common._mutate_raw_config
25
+ _batched_raw_config = _common._batched_raw_config
26
+ _probe_mcp_tools = _common._probe_mcp_tools
27
+ _print_command = _common._print_command
28
+ _configure = _common._configure
29
+
30
+ console = _common.console
31
+ def _antigravity_mcp_path(project_root: Path) -> Path:
32
+ return project_root / ".agents" / "mcp_config.json"
33
+
34
+ def _antigravity_mcp_config(project_root: Path) -> dict:
35
+ return {
36
+ "mcpServers": {
37
+ "devcouncil": {
38
+ "command": "devcouncil",
39
+ "args": ["mcp-server"],
40
+ "env": {"DEVCOUNCIL_PROJECT_ROOT": str(project_root)},
41
+ "cwd": str(project_root),
42
+ }
43
+ }
44
+ }
45
+
46
+ def _record_antigravity_config(project_root: Path) -> None:
47
+ def mutate(config: dict) -> None:
48
+ antigravity = config.setdefault("integrations", {}).setdefault("antigravity", {})
49
+ antigravity.update({
50
+ "enabled": True,
51
+ "mcp_config_path": str(_antigravity_mcp_path(project_root).relative_to(project_root)),
52
+ })
53
+
54
+ _mutate_raw_config(project_root, mutate)
55
+
56
+ def _write_antigravity_mcp_config(project_root: Path) -> Path:
57
+ path = _antigravity_mcp_path(project_root)
58
+ data = _load_json_strict(path, "Antigravity")
59
+ mcp_servers = data.setdefault("mcpServers", {})
60
+ mcp_servers["devcouncil"] = _antigravity_mcp_config(project_root)["mcpServers"]["devcouncil"]
61
+ _save_json(path, data)
62
+ return path
63
+
64
+ def _configure_antigravity(project_root: Path, apply: bool) -> bool:
65
+ path = _antigravity_mcp_path(project_root)
66
+ config = _antigravity_mcp_config(project_root)
67
+ if not apply:
68
+ console.print("[bold]Google Antigravity CLI[/bold]")
69
+ console.print(f"Project MCP config file: [dim]{path}[/dim]")
70
+ console.print(json.dumps(config, separators=(",", ":")), soft_wrap=True)
71
+ console.print(
72
+ "Direct executor command: "
73
+ "[dim]agy --print --print-timeout 30m "
74
+ '"Read and execute the DevCouncil task prompt at .devcouncil/TASK-001-antigravity-task.md."[/dim]'
75
+ )
76
+ return True
77
+
78
+ if not shutil.which("agy"):
79
+ console.print("[yellow]Antigravity CLI (`agy`) not found on PATH. Install it before using `dev run --executor antigravity`.[/yellow]")
80
+ try:
81
+ written = _write_antigravity_mcp_config(project_root)
82
+ except ValueError as exc:
83
+ console.print(f"[red]{exc}[/red]")
84
+ return False
85
+ _record_antigravity_config(project_root)
86
+ console.print(f"[green]Antigravity MCP config written:[/green] {written}")
87
+ return True