loopx 0.4.8__py3-none-any.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 (811) hide show
  1. loopx/__init__.py +5 -0
  2. loopx/agent_onboarding.py +654 -0
  3. loopx/agent_registry.py +112 -0
  4. loopx/ark_managed_agent_host.py +59 -0
  5. loopx/authority.py +805 -0
  6. loopx/benchmark.py +2875 -0
  7. loopx/benchmark_adapters/__init__.py +1 -0
  8. loopx/benchmark_adapters/agentissue.py +2644 -0
  9. loopx/benchmark_adapters/agents_last_exam.py +3998 -0
  10. loopx/benchmark_adapters/edgebench.py +322 -0
  11. loopx/benchmark_adapters/skillsbench.py +5978 -0
  12. loopx/benchmark_adapters/skillsbench_acp_failure_policy.py +143 -0
  13. loopx/benchmark_adapters/skillsbench_acp_process.py +31 -0
  14. loopx/benchmark_adapters/skillsbench_acp_relay.py +4832 -0
  15. loopx/benchmark_adapters/skillsbench_batch.py +124 -0
  16. loopx/benchmark_adapters/skillsbench_bridge_guard.py +209 -0
  17. loopx/benchmark_adapters/skillsbench_bridge_summary.py +203 -0
  18. loopx/benchmark_adapters/skillsbench_codex_goal_recovery.py +271 -0
  19. loopx/benchmark_adapters/skillsbench_codex_goal_trace.py +81 -0
  20. loopx/benchmark_adapters/skillsbench_codex_runtime.py +339 -0
  21. loopx/benchmark_adapters/skillsbench_dockerfile_runtime.py +467 -0
  22. loopx/benchmark_adapters/skillsbench_failure_signals.py +652 -0
  23. loopx/benchmark_adapters/skillsbench_proxy_runtime.py +327 -0
  24. loopx/benchmark_adapters/skillsbench_remote_bridge.py +402 -0
  25. loopx/benchmark_adapters/skillsbench_result_discovery.py +143 -0
  26. loopx/benchmark_adapters/skillsbench_runner_profile.py +436 -0
  27. loopx/benchmark_adapters/skillsbench_runner_source.py +99 -0
  28. loopx/benchmark_adapters/skillsbench_setup_preflight.py +771 -0
  29. loopx/benchmark_adapters/skillsbench_signals.py +15 -0
  30. loopx/benchmark_adapters/skillsbench_task_source.py +141 -0
  31. loopx/benchmark_adapters/skillsbench_turn_route.py +723 -0
  32. loopx/benchmark_adapters/skillsbench_turn_runtime.py +1069 -0
  33. loopx/benchmark_adapters/skillsbench_typed_repair.py +689 -0
  34. loopx/benchmark_adapters/skillsbench_uv_cache.py +111 -0
  35. loopx/benchmark_adapters/skillsbench_verifier_bootstrap.py +227 -0
  36. loopx/benchmark_adapters/skillsbench_verifier_cache.py +138 -0
  37. loopx/benchmark_adapters/terminal_bench.py +10078 -0
  38. loopx/benchmark_case_analysis.py +1276 -0
  39. loopx/benchmark_case_state.py +1079 -0
  40. loopx/benchmark_core/__init__.py +239 -0
  41. loopx/benchmark_core/adapter.py +84 -0
  42. loopx/benchmark_core/artifacts.py +517 -0
  43. loopx/benchmark_core/attempts.py +199 -0
  44. loopx/benchmark_core/container_exec.py +216 -0
  45. loopx/benchmark_core/io.py +68 -0
  46. loopx/benchmark_core/lifecycle.py +211 -0
  47. loopx/benchmark_core/loop_protocol.py +689 -0
  48. loopx/benchmark_core/observable_handles.py +348 -0
  49. loopx/benchmark_core/parity.py +256 -0
  50. loopx/benchmark_core/remote_closeout.py +482 -0
  51. loopx/benchmark_core/rounds.py +215 -0
  52. loopx/benchmark_core/route_profile.py +509 -0
  53. loopx/benchmark_core/run_permissions.py +206 -0
  54. loopx/benchmark_core/split_control.py +925 -0
  55. loopx/benchmark_core/turn_fidelity.py +326 -0
  56. loopx/benchmark_ledger.py +3793 -0
  57. loopx/benchmark_ledger_countability.py +372 -0
  58. loopx/benchmark_ledger_current.py +724 -0
  59. loopx/benchmark_trajectory.py +405 -0
  60. loopx/benchmarks/__init__.py +1 -0
  61. loopx/benchmarks/qualification/__init__.py +1 -0
  62. loopx/benchmarks/qualification/release_outcome_baseline.py +360 -0
  63. loopx/benchmarks/read_models/__init__.py +1 -0
  64. loopx/benchmarks/read_models/benchmark_attempt_accounting.py +53 -0
  65. loopx/benchmarks/read_models/benchmark_comparison.py +414 -0
  66. loopx/benchmarks/read_models/benchmark_event_timeline.py +113 -0
  67. loopx/benchmarks/read_models/benchmark_experiment_report.py +475 -0
  68. loopx/benchmarks/read_models/benchmark_learning_ledger.py +137 -0
  69. loopx/benchmarks/read_models/benchmark_lifecycle_contracts.py +228 -0
  70. loopx/benchmarks/read_models/benchmark_projection.py +723 -0
  71. loopx/benchmarks/read_models/benchmark_result.py +146 -0
  72. loopx/benchmarks/read_models/benchmark_run_execution_contract.py +116 -0
  73. loopx/benchmarks/read_models/benchmark_run_failure.py +157 -0
  74. loopx/benchmarks/read_models/benchmark_run_metrics.py +213 -0
  75. loopx/benchmarks/read_models/benchmark_run_post_execution.py +635 -0
  76. loopx/benchmarks/read_models/benchmark_run_pre_execution.py +541 -0
  77. loopx/benchmarks/read_models/benchmark_status_compaction.py +1255 -0
  78. loopx/benchmarks/read_models/benchmark_status_runner.py +780 -0
  79. loopx/benchmarks/read_models/goal_start_control_score.py +857 -0
  80. loopx/benchmarks/read_models/skillsbench_post_run_debug.py +746 -0
  81. loopx/benchmarks/read_models/skillsbench_verifier_attribution.py +269 -0
  82. loopx/bootstrap.py +1116 -0
  83. loopx/bootstrap_command_pack.py +2167 -0
  84. loopx/boundary_authority.py +199 -0
  85. loopx/canary/__init__.py +1 -0
  86. loopx/canary/maintainability_ratchet.py +800 -0
  87. loopx/canary/planner.py +1984 -0
  88. loopx/canary/premerge.py +1130 -0
  89. loopx/canary/qualification_profiles.py +309 -0
  90. loopx/canary/quality_surface_catalog.py +838 -0
  91. loopx/canary/release_profiles.py +51 -0
  92. loopx/canary/runner.py +1107 -0
  93. loopx/canary/smoke_health.py +581 -0
  94. loopx/canary/smoke_profiles.py +212 -0
  95. loopx/capabilities/__init__.py +0 -0
  96. loopx/capabilities/agent_turn_recall/__init__.py +17 -0
  97. loopx/capabilities/agent_turn_recall/cli.py +369 -0
  98. loopx/capabilities/agent_turn_recall/core.py +296 -0
  99. loopx/capabilities/auto_research/__init__.py +16 -0
  100. loopx/capabilities/auto_research/bootstrap_contract.py +157 -0
  101. loopx/capabilities/auto_research/cli.py +1468 -0
  102. loopx/capabilities/auto_research/core.py +11 -0
  103. loopx/capabilities/auto_research/defaults.py +79 -0
  104. loopx/capabilities/auto_research/demo_e2e.py +1848 -0
  105. loopx/capabilities/auto_research/demo_supervisor.py +186 -0
  106. loopx/capabilities/auto_research/evidence_packet.py +767 -0
  107. loopx/capabilities/auto_research/human_view.py +794 -0
  108. loopx/capabilities/auto_research/kernel.py +191 -0
  109. loopx/capabilities/auto_research/knn_demo_workspace.py +322 -0
  110. loopx/capabilities/auto_research/live_evidence.py +248 -0
  111. loopx/capabilities/auto_research/preset.py +176 -0
  112. loopx/capabilities/auto_research/research_state.py +1085 -0
  113. loopx/capabilities/auto_research/role_profiles.py +394 -0
  114. loopx/capabilities/auto_research/rollout_append.py +97 -0
  115. loopx/capabilities/auto_research/terminal_result_contract.py +422 -0
  116. loopx/capabilities/auto_research/terminal_result_projection.py +171 -0
  117. loopx/capabilities/auto_research/terminal_result_query.py +233 -0
  118. loopx/capabilities/auto_research/terminal_results.py +349 -0
  119. loopx/capabilities/auto_research/user_contract.py +190 -0
  120. loopx/capabilities/auto_research/worker_loop.py +163 -0
  121. loopx/capabilities/auto_research/worker_runtime.py +777 -0
  122. loopx/capabilities/auto_research/worker_skill/SKILL.md +343 -0
  123. loopx/capabilities/benchmark_toolkit/__init__.py +19 -0
  124. loopx/capabilities/benchmark_toolkit/integrity.py +387 -0
  125. loopx/capabilities/catalog.py +1875 -0
  126. loopx/capabilities/change_quality/__init__.py +19 -0
  127. loopx/capabilities/change_quality/cli.py +171 -0
  128. loopx/capabilities/change_quality/context.py +156 -0
  129. loopx/capabilities/change_quality/oracles.py +269 -0
  130. loopx/capabilities/change_quality/policy.py +34 -0
  131. loopx/capabilities/change_quality/receipt.py +482 -0
  132. loopx/capabilities/change_quality/result.py +493 -0
  133. loopx/capabilities/change_quality/scope.py +171 -0
  134. loopx/capabilities/change_quality/shadow.py +680 -0
  135. loopx/capabilities/content_ops/__init__.py +0 -0
  136. loopx/capabilities/content_ops/cli.py +649 -0
  137. loopx/capabilities/content_ops/connector_packets.py +164 -0
  138. loopx/capabilities/content_ops/item_lifecycle.py +1000 -0
  139. loopx/capabilities/content_ops/layout.py +451 -0
  140. loopx/capabilities/content_ops/markdown.py +456 -0
  141. loopx/capabilities/content_ops/schemas.py +51 -0
  142. loopx/capabilities/content_ops/social_browser_x.py +107 -0
  143. loopx/capabilities/content_ops/surface.py +1956 -0
  144. loopx/capabilities/content_ops/templates/layout-catalog-v0.json +72 -0
  145. loopx/capabilities/context_providers/__init__.py +36 -0
  146. loopx/capabilities/context_providers/base.py +189 -0
  147. loopx/capabilities/context_providers/factory.py +32 -0
  148. loopx/capabilities/context_providers/openviking.py +702 -0
  149. loopx/capabilities/context_providers/service_ownership.py +185 -0
  150. loopx/capabilities/decision_context/__init__.py +129 -0
  151. loopx/capabilities/decision_context/architecture.py +83 -0
  152. loopx/capabilities/decision_context/assembler.py +849 -0
  153. loopx/capabilities/decision_context/catalog_entry.py +195 -0
  154. loopx/capabilities/decision_context/cli.py +310 -0
  155. loopx/capabilities/decision_context/cursor_commit.py +535 -0
  156. loopx/capabilities/decision_context/outcome_feedback.py +352 -0
  157. loopx/capabilities/decision_context/packets.py +654 -0
  158. loopx/capabilities/decision_context/private_state.py +189 -0
  159. loopx/capabilities/decision_context/profile.py +453 -0
  160. loopx/capabilities/decision_context/providers.py +228 -0
  161. loopx/capabilities/decision_context/review_settlement.py +136 -0
  162. loopx/capabilities/decision_context/runtime.py +273 -0
  163. loopx/capabilities/decision_context/sources.py +415 -0
  164. loopx/capabilities/explore/__init__.py +1 -0
  165. loopx/capabilities/explore/activation.py +198 -0
  166. loopx/capabilities/explore/adaptive_replay_planner.py +221 -0
  167. loopx/capabilities/explore/child_replay_runtime.py +463 -0
  168. loopx/capabilities/explore/composition_frontier.py +291 -0
  169. loopx/capabilities/explore/counterfactual_runtime.py +578 -0
  170. loopx/capabilities/explore/episode_runtime.py +647 -0
  171. loopx/capabilities/explore/harness_checkpoint.py +171 -0
  172. loopx/capabilities/explore/harness_gate.py +115 -0
  173. loopx/capabilities/explore/harness_runtime.py +1124 -0
  174. loopx/capabilities/explore/replay_metrics.py +206 -0
  175. loopx/capabilities/explore/replay_runtime.py +1271 -0
  176. loopx/capabilities/explore/resource_portfolio.py +173 -0
  177. loopx/capabilities/explore/result_log.py +974 -0
  178. loopx/capabilities/explore/router_state.py +432 -0
  179. loopx/capabilities/explore/source_history_reconcile.py +255 -0
  180. loopx/capabilities/explore/speculative_scheduler.py +498 -0
  181. loopx/capabilities/explore/todo_branch_plan.py +650 -0
  182. loopx/capabilities/explore/todo_evidence.py +141 -0
  183. loopx/capabilities/explore/trace_runtime.py +284 -0
  184. loopx/capabilities/explore/worker_branch_plan.py +1257 -0
  185. loopx/capabilities/integration_branch/__init__.py +13 -0
  186. loopx/capabilities/integration_branch/cli.py +148 -0
  187. loopx/capabilities/integration_branch/core.py +916 -0
  188. loopx/capabilities/issue_fix/__init__.py +19 -0
  189. loopx/capabilities/issue_fix/acceptance_loop.py +1050 -0
  190. loopx/capabilities/issue_fix/candidate_evidence.py +503 -0
  191. loopx/capabilities/issue_fix/candidate_preflight.py +676 -0
  192. loopx/capabilities/issue_fix/cli.py +1822 -0
  193. loopx/capabilities/issue_fix/cli_input.py +87 -0
  194. loopx/capabilities/issue_fix/content_ops_cli.py +148 -0
  195. loopx/capabilities/issue_fix/discovered_issue_promotion.py +947 -0
  196. loopx/capabilities/issue_fix/explore_projection.py +710 -0
  197. loopx/capabilities/issue_fix/feasibility.py +542 -0
  198. loopx/capabilities/issue_fix/github_public.py +661 -0
  199. loopx/capabilities/issue_fix/intake_surface.py +832 -0
  200. loopx/capabilities/issue_fix/metadata_preview.py +218 -0
  201. loopx/capabilities/issue_fix/metrics_projection.py +1340 -0
  202. loopx/capabilities/issue_fix/metrics_supplement.py +634 -0
  203. loopx/capabilities/issue_fix/metrics_supplement_cli.py +127 -0
  204. loopx/capabilities/issue_fix/outcome_projection.py +1235 -0
  205. loopx/capabilities/issue_fix/periodic_report.py +189 -0
  206. loopx/capabilities/issue_fix/pr_description.py +418 -0
  207. loopx/capabilities/issue_fix/pr_gate_reconcile.py +496 -0
  208. loopx/capabilities/issue_fix/pr_gate_reconcile_cli.py +464 -0
  209. loopx/capabilities/issue_fix/pr_lifecycle.py +1327 -0
  210. loopx/capabilities/issue_fix/pr_lifecycle_rollout.py +85 -0
  211. loopx/capabilities/issue_fix/pr_monitor_materialization.py +257 -0
  212. loopx/capabilities/issue_fix/pr_review_ack.py +439 -0
  213. loopx/capabilities/issue_fix/provider_hooks.py +24 -0
  214. loopx/capabilities/issue_fix/repository_commit_evidence.py +186 -0
  215. loopx/capabilities/issue_fix/repository_context.py +457 -0
  216. loopx/capabilities/issue_fix/repository_memory.py +459 -0
  217. loopx/capabilities/issue_fix/repository_memory_provider.py +1454 -0
  218. loopx/capabilities/issue_fix/repository_snapshot.py +454 -0
  219. loopx/capabilities/issue_fix/reviewer_cli.py +917 -0
  220. loopx/capabilities/issue_fix/reviewer_notification.py +882 -0
  221. loopx/capabilities/issue_fix/reviewer_notification_drain.py +942 -0
  222. loopx/capabilities/issue_fix/reviewer_recommendation.py +1057 -0
  223. loopx/capabilities/issue_fix/reviewer_request.py +1282 -0
  224. loopx/capabilities/issue_fix/reward_memory.py +879 -0
  225. loopx/capabilities/issue_fix/workflow_plan.py +1286 -0
  226. loopx/capabilities/material_lifecycle/__init__.py +161 -0
  227. loopx/capabilities/material_lifecycle/_validation.py +183 -0
  228. loopx/capabilities/material_lifecycle/apply.py +672 -0
  229. loopx/capabilities/material_lifecycle/architecture.py +122 -0
  230. loopx/capabilities/material_lifecycle/cli.py +161 -0
  231. loopx/capabilities/material_lifecycle/decision_planning.py +470 -0
  232. loopx/capabilities/material_lifecycle/explore_execution.py +306 -0
  233. loopx/capabilities/material_lifecycle/intake.py +869 -0
  234. loopx/capabilities/material_lifecycle/inventory.py +147 -0
  235. loopx/capabilities/material_lifecycle/lifecycle.py +98 -0
  236. loopx/capabilities/material_lifecycle/preparation.py +147 -0
  237. loopx/capabilities/material_lifecycle/project_skill.py +83 -0
  238. loopx/capabilities/material_lifecycle/ranking.py +267 -0
  239. loopx/capabilities/material_lifecycle/readable_projection.py +500 -0
  240. loopx/capabilities/material_lifecycle/rebuild.py +480 -0
  241. loopx/capabilities/material_lifecycle/settlement.py +238 -0
  242. loopx/capabilities/periodic_report/__init__.py +71 -0
  243. loopx/capabilities/periodic_report/adapters.py +939 -0
  244. loopx/capabilities/periodic_report/archive.py +422 -0
  245. loopx/capabilities/periodic_report/bindings.py +705 -0
  246. loopx/capabilities/periodic_report/cli.py +277 -0
  247. loopx/capabilities/periodic_report/core.py +691 -0
  248. loopx/capabilities/periodic_report/extension_envelope.py +66 -0
  249. loopx/capabilities/periodic_report/presets.py +103 -0
  250. loopx/capabilities/periodic_report/profile.py +235 -0
  251. loopx/capabilities/periodic_report/project_progress.py +179 -0
  252. loopx/capabilities/periodic_report/triggers.py +452 -0
  253. loopx/capabilities/pr_review_queue/__init__.py +17 -0
  254. loopx/capabilities/pr_review_queue/core.py +506 -0
  255. loopx/capabilities/pr_review_queue/review_contract.py +506 -0
  256. loopx/capabilities/registry.py +192 -0
  257. loopx/capabilities/reward_memory/__init__.py +75 -0
  258. loopx/capabilities/reward_memory/application.py +819 -0
  259. loopx/capabilities/reward_memory/architecture.py +572 -0
  260. loopx/capabilities/reward_memory/candidate_review.py +511 -0
  261. loopx/capabilities/reward_memory/cli.py +469 -0
  262. loopx/capabilities/reward_memory/dogfood.py +574 -0
  263. loopx/capabilities/reward_memory/evaluation.py +296 -0
  264. loopx/capabilities/reward_memory/evaluation_fixtures.py +362 -0
  265. loopx/capabilities/reward_memory/experiment.py +567 -0
  266. loopx/capabilities/reward_memory/health.py +222 -0
  267. loopx/capabilities/reward_memory/ingestion.py +519 -0
  268. loopx/capabilities/reward_memory/registry.py +600 -0
  269. loopx/capabilities/reward_memory/runtime_hooks.py +312 -0
  270. loopx/capabilities/reward_memory/scoped_feedback.py +173 -0
  271. loopx/capabilities/semantic_preference/__init__.py +12 -0
  272. loopx/capabilities/semantic_preference/cli.py +189 -0
  273. loopx/capabilities/semantic_preference/contract.py +592 -0
  274. loopx/capabilities/semantic_preference/reward_memory.py +62 -0
  275. loopx/capabilities/value_connectors/__init__.py +1 -0
  276. loopx/capabilities/value_connectors/cli.py +401 -0
  277. loopx/capabilities/value_connectors/finance_extension_migration.py +108 -0
  278. loopx/capabilities/value_connectors/install_check.py +147 -0
  279. loopx/capabilities/value_connectors/planner.py +733 -0
  280. loopx/capabilities/value_connectors/source_map.py +446 -0
  281. loopx/claude_goal_baseline.py +138 -0
  282. loopx/claude_goal_mode/__init__.py +23 -0
  283. loopx/claude_goal_mode/hooks/goal_policy.py +212 -0
  284. loopx/claude_goal_mode/hooks/goal_state.py +139 -0
  285. loopx/claude_goal_mode/mcp/loopx_mcp.py +167 -0
  286. loopx/claude_goal_mode/scripts/connect.py +103 -0
  287. loopx/claude_goal_mode/scripts/goalmode_cmd.py +241 -0
  288. loopx/claude_goal_mode/scripts/install.py +328 -0
  289. loopx/claude_goal_mode/statusline/goal_status.py +97 -0
  290. loopx/cli.py +836 -0
  291. loopx/cli_commands/__init__.py +334 -0
  292. loopx/cli_commands/_host_thread.py +13 -0
  293. loopx/cli_commands/agentissue_runner_flow.py +447 -0
  294. loopx/cli_commands/agents_last_exam.py +160 -0
  295. loopx/cli_commands/agents_last_exam_baked_input.py +302 -0
  296. loopx/cli_commands/agents_last_exam_host_codex.py +374 -0
  297. loopx/cli_commands/agents_last_exam_launch_dry_run.py +372 -0
  298. loopx/cli_commands/agents_last_exam_local_plan.py +322 -0
  299. loopx/cli_commands/agents_last_exam_runner_source.py +352 -0
  300. loopx/cli_commands/agents_last_exam_task_material.py +335 -0
  301. loopx/cli_commands/agents_last_exam_validation_gate.py +236 -0
  302. loopx/cli_commands/benchmark_boundary.py +499 -0
  303. loopx/cli_commands/benchmark_dispatch.py +161 -0
  304. loopx/cli_commands/benchmark_release_outcome.py +123 -0
  305. loopx/cli_commands/benchmark_review_lifecycle.py +1275 -0
  306. loopx/cli_commands/benchmark_run_ledger.py +763 -0
  307. loopx/cli_commands/benchmark_run_ledger_case_analysis.py +249 -0
  308. loopx/cli_commands/benchmark_run_ledger_classification.py +45 -0
  309. loopx/cli_commands/benchmark_run_ledger_maintenance.py +486 -0
  310. loopx/cli_commands/benchmark_run_ledger_maintenance_registration.py +342 -0
  311. loopx/cli_commands/benchmark_run_ledger_maintenance_rendering.py +233 -0
  312. loopx/cli_commands/benchmark_run_ledger_parity.py +92 -0
  313. loopx/cli_commands/bootstrap_connect.py +238 -0
  314. loopx/cli_commands/canary.py +707 -0
  315. loopx/cli_commands/canary_release_qualification.py +79 -0
  316. loopx/cli_commands/capability.py +96 -0
  317. loopx/cli_commands/doctor.py +43 -0
  318. loopx/cli_commands/dreaming.py +143 -0
  319. loopx/cli_commands/edgebench.py +205 -0
  320. loopx/cli_commands/evidence_log.py +275 -0
  321. loopx/cli_commands/explore.py +989 -0
  322. loopx/cli_commands/explore_planning_commands.py +157 -0
  323. loopx/cli_commands/extension.py +271 -0
  324. loopx/cli_commands/first_run_report.py +73 -0
  325. loopx/cli_commands/goal_channel.py +656 -0
  326. loopx/cli_commands/handoff_mode.py +158 -0
  327. loopx/cli_commands/history.py +622 -0
  328. loopx/cli_commands/host_mode_plan.py +113 -0
  329. loopx/cli_commands/lark_inbox.py +431 -0
  330. loopx/cli_commands/lark_kanban.py +629 -0
  331. loopx/cli_commands/ml_experiment.py +321 -0
  332. loopx/cli_commands/multi_agent.py +211 -0
  333. loopx/cli_commands/opencode2_goal_worker.py +217 -0
  334. loopx/cli_commands/pr_review.py +167 -0
  335. loopx/cli_commands/presentation.py +218 -0
  336. loopx/cli_commands/preset.py +96 -0
  337. loopx/cli_commands/project.py +150 -0
  338. loopx/cli_commands/project_lifecycle.py +915 -0
  339. loopx/cli_commands/quota.py +859 -0
  340. loopx/cli_commands/quota_registration.py +241 -0
  341. loopx/cli_commands/quota_request.py +113 -0
  342. loopx/cli_commands/ready_score.py +110 -0
  343. loopx/cli_commands/registry_admin.py +975 -0
  344. loopx/cli_commands/registry_admin_configure.py +344 -0
  345. loopx/cli_commands/registry_admin_peer.py +84 -0
  346. loopx/cli_commands/registry_authority.py +218 -0
  347. loopx/cli_commands/review_batch.py +146 -0
  348. loopx/cli_commands/slash_commands.py +145 -0
  349. loopx/cli_commands/start_goal.py +251 -0
  350. loopx/cli_commands/starter.py +175 -0
  351. loopx/cli_commands/starter_bootstrap.py +179 -0
  352. loopx/cli_commands/starter_bootstrap_registration.py +198 -0
  353. loopx/cli_commands/starter_runtime_idle.py +107 -0
  354. loopx/cli_commands/starter_scheduler.py +207 -0
  355. loopx/cli_commands/starter_session_runtime.py +152 -0
  356. loopx/cli_commands/starter_visible_common.py +54 -0
  357. loopx/cli_commands/starter_visible_driver.py +161 -0
  358. loopx/cli_commands/starter_visible_pilot.py +278 -0
  359. loopx/cli_commands/status.py +867 -0
  360. loopx/cli_commands/status_registration.py +239 -0
  361. loopx/cli_commands/summary_all.py +222 -0
  362. loopx/cli_commands/support_control.py +809 -0
  363. loopx/cli_commands/support_control_registry.py +68 -0
  364. loopx/cli_commands/support_control_supervisor.py +289 -0
  365. loopx/cli_commands/task_lease.py +306 -0
  366. loopx/cli_commands/terminal_bench_adapter.py +717 -0
  367. loopx/cli_commands/terminal_bench_environment_result.py +1246 -0
  368. loopx/cli_commands/todo.py +940 -0
  369. loopx/cli_commands/todo_argument_validation.py +572 -0
  370. loopx/cli_commands/todo_event.py +114 -0
  371. loopx/cli_commands/turn.py +804 -0
  372. loopx/cli_commands/version.py +46 -0
  373. loopx/cli_commands/worker_bridge.py +659 -0
  374. loopx/cli_rollout.py +314 -0
  375. loopx/codex_cli_goal_tui.py +672 -0
  376. loopx/codex_cli_probe.py +1530 -0
  377. loopx/codex_cli_probe_markdown.py +935 -0
  378. loopx/codex_cli_runtime_probe.py +733 -0
  379. loopx/codex_cli_scheduler.py +564 -0
  380. loopx/codex_goal_baseline.py +620 -0
  381. loopx/configuration_catalog.py +617 -0
  382. loopx/configure_goal.py +1375 -0
  383. loopx/contract.py +996 -0
  384. loopx/control_plane/__init__.py +71 -0
  385. loopx/control_plane/agents/__init__.py +1 -0
  386. loopx/control_plane/agents/agent_lane_recommendation.py +516 -0
  387. loopx/control_plane/agents/agent_scope.py +1578 -0
  388. loopx/control_plane/agents/agent_scope_frontier.py +60 -0
  389. loopx/control_plane/agents/capability_gate.py +531 -0
  390. loopx/control_plane/agents/identity.py +140 -0
  391. loopx/control_plane/agents/legacy_migration.py +169 -0
  392. loopx/control_plane/agents/management_projection.py +658 -0
  393. loopx/control_plane/agents/material_frontier.py +608 -0
  394. loopx/control_plane/agents/material_handoff.py +156 -0
  395. loopx/control_plane/agents/multi_agent/__init__.py +1 -0
  396. loopx/control_plane/agents/multi_agent/codex_executable.py +207 -0
  397. loopx/control_plane/agents/multi_agent/collective_round_ledger.py +387 -0
  398. loopx/control_plane/agents/multi_agent/contract.py +474 -0
  399. loopx/control_plane/agents/multi_agent/recipe.py +110 -0
  400. loopx/control_plane/agents/multi_agent/role_successor.py +297 -0
  401. loopx/control_plane/agents/multi_agent/runtime_scripts.py +426 -0
  402. loopx/control_plane/agents/multi_agent/visible_launch_policy.py +149 -0
  403. loopx/control_plane/agents/multi_agent/visible_wake_scheduler.py +392 -0
  404. loopx/control_plane/agents/profile.py +216 -0
  405. loopx/control_plane/agents/runtime_model.py +73 -0
  406. loopx/control_plane/agents/subagent_activity.py +164 -0
  407. loopx/control_plane/agents/supervisor.py +544 -0
  408. loopx/control_plane/agents/supervisor_events.py +462 -0
  409. loopx/control_plane/agents/supervisor_inject.py +204 -0
  410. loopx/control_plane/agents/work_mode.py +56 -0
  411. loopx/control_plane/agents/workspace_guard.py +364 -0
  412. loopx/control_plane/effect_program.py +644 -0
  413. loopx/control_plane/goals/__init__.py +1 -0
  414. loopx/control_plane/goals/active_state_event_projection.py +103 -0
  415. loopx/control_plane/goals/active_state_metadata.py +47 -0
  416. loopx/control_plane/goals/active_state_sections.py +58 -0
  417. loopx/control_plane/goals/configure_goal_service.py +354 -0
  418. loopx/control_plane/goals/contract_health.py +132 -0
  419. loopx/control_plane/goals/dreaming.py +152 -0
  420. loopx/control_plane/goals/global_registry_health.py +199 -0
  421. loopx/control_plane/goals/global_registry_shadow.py +33 -0
  422. loopx/control_plane/goals/goal_channel.py +34 -0
  423. loopx/control_plane/goals/goal_channel_projection.py +560 -0
  424. loopx/control_plane/goals/goal_frontier/__init__.py +1917 -0
  425. loopx/control_plane/goals/goal_frontier/ack_policy.py +149 -0
  426. loopx/control_plane/goals/goal_frontier/outcome_continuity.py +437 -0
  427. loopx/control_plane/goals/goal_frontier/replan_rules.py +210 -0
  428. loopx/control_plane/goals/goal_frontier/semantic_history.py +314 -0
  429. loopx/control_plane/goals/goal_frontier/terminal.py +180 -0
  430. loopx/control_plane/goals/goal_vision.py +443 -0
  431. loopx/control_plane/goals/goal_vision_policy.py +36 -0
  432. loopx/control_plane/goals/goal_vision_state.py +62 -0
  433. loopx/control_plane/goals/goal_vision_wait.py +290 -0
  434. loopx/control_plane/goals/path_resolution.py +20 -0
  435. loopx/control_plane/goals/start_contract.py +206 -0
  436. loopx/control_plane/goals/vision_checkpoint.py +92 -0
  437. loopx/control_plane/handoff/__init__.py +1 -0
  438. loopx/control_plane/handoff/cross_runtime_impl_review.py +311 -0
  439. loopx/control_plane/handoff/delivery_contract.py +161 -0
  440. loopx/control_plane/handoff/handoff_runs.py +71 -0
  441. loopx/control_plane/handoff/project_handoff.py +155 -0
  442. loopx/control_plane/handoff/review_batch.py +463 -0
  443. loopx/control_plane/handoff/review_packet_context.py +216 -0
  444. loopx/control_plane/heartbeat/agent.py +173 -0
  445. loopx/control_plane/heartbeat/budget.py +66 -0
  446. loopx/control_plane/heartbeat/builder.py +501 -0
  447. loopx/control_plane/heartbeat/host.py +64 -0
  448. loopx/control_plane/heartbeat/rules.py +68 -0
  449. loopx/control_plane/heartbeat/task_body.py +759 -0
  450. loopx/control_plane/heartbeat/visible_goal.py +86 -0
  451. loopx/control_plane/projects/__init__.py +1 -0
  452. loopx/control_plane/projects/contract.py +25 -0
  453. loopx/control_plane/projects/registry.py +663 -0
  454. loopx/control_plane/quota/__init__.py +1 -0
  455. loopx/control_plane/quota/cli_projection.py +704 -0
  456. loopx/control_plane/quota/decision_summary.py +431 -0
  457. loopx/control_plane/quota/effect_program.py +152 -0
  458. loopx/control_plane/quota/error_codes.py +19 -0
  459. loopx/control_plane/quota/goal_boundary.py +464 -0
  460. loopx/control_plane/quota/heartbeat_receipt.py +277 -0
  461. loopx/control_plane/quota/heartbeat_recommendation.py +718 -0
  462. loopx/control_plane/quota/host_poll_receipts.py +162 -0
  463. loopx/control_plane/quota/live_decision.py +142 -0
  464. loopx/control_plane/quota/monitor_poll.py +786 -0
  465. loopx/control_plane/quota/policy_constants.py +40 -0
  466. loopx/control_plane/quota/projection_repair.py +262 -0
  467. loopx/control_plane/quota/recent_runs.py +210 -0
  468. loopx/control_plane/quota/scheduler_ack.py +490 -0
  469. loopx/control_plane/quota/selected_todo_projection.py +139 -0
  470. loopx/control_plane/quota/settlement.py +437 -0
  471. loopx/control_plane/quota/settlement_cli.py +246 -0
  472. loopx/control_plane/quota/settlement_validation.py +64 -0
  473. loopx/control_plane/quota/settlement_workspace_causality.py +180 -0
  474. loopx/control_plane/quota/should_run.py +249 -0
  475. loopx/control_plane/quota/should_run_packet.py +1165 -0
  476. loopx/control_plane/quota/should_run_prepare.py +675 -0
  477. loopx/control_plane/quota/slot_accounting.py +1123 -0
  478. loopx/control_plane/quota/spend_sources.py +11 -0
  479. loopx/control_plane/quota/stall_repair.py +397 -0
  480. loopx/control_plane/quota/states.py +29 -0
  481. loopx/control_plane/quota/task_orchestration.py +448 -0
  482. loopx/control_plane/quota/task_orchestration_admission.py +497 -0
  483. loopx/control_plane/quota/turn_envelope.py +889 -0
  484. loopx/control_plane/quota/usage_summary.py +140 -0
  485. loopx/control_plane/reward_memory.py +43 -0
  486. loopx/control_plane/runtime/__init__.py +2 -0
  487. loopx/control_plane/runtime/active_user_assisted_pilot.py +275 -0
  488. loopx/control_plane/runtime/agent_scoped_evidence_log.py +435 -0
  489. loopx/control_plane/runtime/decision_freshness.py +203 -0
  490. loopx/control_plane/runtime/event_ledger.py +197 -0
  491. loopx/control_plane/runtime/event_store_migration_bridge.py +196 -0
  492. loopx/control_plane/runtime/goal_project_route.py +70 -0
  493. loopx/control_plane/runtime/local_state_write_correctness.py +242 -0
  494. loopx/control_plane/runtime/promotion_readiness.py +152 -0
  495. loopx/control_plane/runtime/public_safety.py +120 -0
  496. loopx/control_plane/runtime/run_artifacts.py +78 -0
  497. loopx/control_plane/runtime/run_compaction.py +397 -0
  498. loopx/control_plane/runtime/run_context_retention.py +241 -0
  499. loopx/control_plane/runtime/run_history.py +132 -0
  500. loopx/control_plane/runtime/run_index_duplicates.py +205 -0
  501. loopx/control_plane/runtime/run_index_rebuild.py +263 -0
  502. loopx/control_plane/runtime/run_ingest_health.py +336 -0
  503. loopx/control_plane/runtime/runtime_projection_route.py +624 -0
  504. loopx/control_plane/runtime/runtime_projection_writer.py +98 -0
  505. loopx/control_plane/runtime/session_runtime.py +339 -0
  506. loopx/control_plane/runtime/shared_runtime_material_projection.py +332 -0
  507. loopx/control_plane/runtime/shared_runtime_refresh_projection.py +183 -0
  508. loopx/control_plane/runtime/stale_latest_run.py +90 -0
  509. loopx/control_plane/runtime/status_classifications.py +49 -0
  510. loopx/control_plane/runtime/status_projection_cache.py +235 -0
  511. loopx/control_plane/runtime/stride_observation.py +144 -0
  512. loopx/control_plane/runtime/time.py +39 -0
  513. loopx/control_plane/runtime/trajectory_hygiene.py +149 -0
  514. loopx/control_plane/runtime/validation_command.py +69 -0
  515. loopx/control_plane/scheduler/__init__.py +1 -0
  516. loopx/control_plane/scheduler/ack.py +329 -0
  517. loopx/control_plane/scheduler/arbitration.py +188 -0
  518. loopx/control_plane/scheduler/automation_liveness.py +183 -0
  519. loopx/control_plane/scheduler/execution_context.py +555 -0
  520. loopx/control_plane/scheduler/external_evidence_observation.py +428 -0
  521. loopx/control_plane/scheduler/monitor_display.py +143 -0
  522. loopx/control_plane/scheduler/monitor_poll_policy.py +161 -0
  523. loopx/control_plane/scheduler/monitor_poll_writeback.py +351 -0
  524. loopx/control_plane/scheduler/monitor_target.py +64 -0
  525. loopx/control_plane/scheduler/monitor_todo.py +146 -0
  526. loopx/control_plane/scheduler/monitor_wait.py +237 -0
  527. loopx/control_plane/scheduler/scheduler_hint.py +1284 -0
  528. loopx/control_plane/scheduler/state.py +354 -0
  529. loopx/control_plane/scheduler/state_transition_rules.py +179 -0
  530. loopx/control_plane/scheduler/time.py +10 -0
  531. loopx/control_plane/settlement_driver.py +293 -0
  532. loopx/control_plane/status/__init__.py +6 -0
  533. loopx/control_plane/status/active_state_projection.py +105 -0
  534. loopx/control_plane/status/agent_lane_projection.py +375 -0
  535. loopx/control_plane/status/attention_projection.py +74 -0
  536. loopx/control_plane/status/autonomous_replan_projection.py +103 -0
  537. loopx/control_plane/status/collection.py +140 -0
  538. loopx/control_plane/status/contract_projection.py +31 -0
  539. loopx/control_plane/status/dreaming_projection.py +52 -0
  540. loopx/control_plane/status/goal_attention_projection.py +157 -0
  541. loopx/control_plane/status/lifecycle_projection.py +110 -0
  542. loopx/control_plane/status/monitor_display_projection.py +69 -0
  543. loopx/control_plane/status/registry_health_projection.py +75 -0
  544. loopx/control_plane/status/run_projection.py +70 -0
  545. loopx/control_plane/status/runtime_summaries.py +161 -0
  546. loopx/control_plane/testing/__init__.py +1 -0
  547. loopx/control_plane/testing/actual_default_model_behavior_portfolio.py +1371 -0
  548. loopx/control_plane/testing/canary_harness.py +182 -0
  549. loopx/control_plane/testing/capability_monitor_repair_tool_behavior.py +674 -0
  550. loopx/control_plane/testing/cli_output_budget.py +807 -0
  551. loopx/control_plane/testing/cli_output_differential.py +250 -0
  552. loopx/control_plane/testing/cli_output_semantics.py +87 -0
  553. loopx/control_plane/testing/control_plane_composition_scenarios.py +225 -0
  554. loopx/control_plane/testing/decision_replay.py +268 -0
  555. loopx/control_plane/testing/doubao_model_behavior_actor.py +559 -0
  556. loopx/control_plane/testing/model_behavior_corpus.py +344 -0
  557. loopx/control_plane/testing/model_behavior_qualification.py +769 -0
  558. loopx/control_plane/testing/model_behavior_retained_cases.py +235 -0
  559. loopx/control_plane/testing/model_tool_behavior.py +536 -0
  560. loopx/control_plane/testing/onboarding_model_behavior_qualification.py +642 -0
  561. loopx/control_plane/testing/quota_fixtures.py +208 -0
  562. loopx/control_plane/testing/quota_should_run_parity.py +57 -0
  563. loopx/control_plane/testing/release_commit_qualification.py +671 -0
  564. loopx/control_plane/testing/replan_semantic_action_behavior.py +1302 -0
  565. loopx/control_plane/testing/scoped_gate_successor_tool_behavior.py +527 -0
  566. loopx/control_plane/testing/selected_todo_tool_behavior.py +1002 -0
  567. loopx/control_plane/testing/terminal_settlement_tool_behavior.py +656 -0
  568. loopx/control_plane/todos/__init__.py +1 -0
  569. loopx/control_plane/todos/active_state_editing.py +296 -0
  570. loopx/control_plane/todos/active_state_todo_parser.py +138 -0
  571. loopx/control_plane/todos/active_state_todos.py +175 -0
  572. loopx/control_plane/todos/addition.py +103 -0
  573. loopx/control_plane/todos/claim_visibility.py +253 -0
  574. loopx/control_plane/todos/completed_archive.py +139 -0
  575. loopx/control_plane/todos/completion_fence.py +49 -0
  576. loopx/control_plane/todos/completion_policy.py +153 -0
  577. loopx/control_plane/todos/completion_validation.py +248 -0
  578. loopx/control_plane/todos/completion_validation_accountability.py +27 -0
  579. loopx/control_plane/todos/completion_validation_projection.py +57 -0
  580. loopx/control_plane/todos/contract.py +1476 -0
  581. loopx/control_plane/todos/decision_scope.py +554 -0
  582. loopx/control_plane/todos/deferred_resume.py +546 -0
  583. loopx/control_plane/todos/durable_completion.py +201 -0
  584. loopx/control_plane/todos/event_writeback.py +484 -0
  585. loopx/control_plane/todos/frontier_deadline.py +132 -0
  586. loopx/control_plane/todos/handoff_gate.py +283 -0
  587. loopx/control_plane/todos/handoff_mode.py +444 -0
  588. loopx/control_plane/todos/handoff_note.py +202 -0
  589. loopx/control_plane/todos/line_update.py +361 -0
  590. loopx/control_plane/todos/list_projection.py +205 -0
  591. loopx/control_plane/todos/markdown.py +199 -0
  592. loopx/control_plane/todos/monitor_metadata.py +88 -0
  593. loopx/control_plane/todos/mutation_authority.py +299 -0
  594. loopx/control_plane/todos/projection.py +655 -0
  595. loopx/control_plane/todos/quota_summary.py +1138 -0
  596. loopx/control_plane/todos/route_continuation.py +267 -0
  597. loopx/control_plane/todos/succession_warning.py +174 -0
  598. loopx/control_plane/todos/summary_item.py +223 -0
  599. loopx/control_plane/todos/text.py +30 -0
  600. loopx/control_plane/todos/todo_index.py +226 -0
  601. loopx/control_plane/todos/todo_summary.py +1458 -0
  602. loopx/control_plane/todos/unblock_resume.py +326 -0
  603. loopx/control_plane/todos/user_gate.py +263 -0
  604. loopx/control_plane/todos/write_hint.py +63 -0
  605. loopx/control_plane/todos/write_policy.py +135 -0
  606. loopx/control_plane/turn_driver/__init__.py +85 -0
  607. loopx/control_plane/turn_driver/codex_cli.py +502 -0
  608. loopx/control_plane/turn_driver/driver.py +355 -0
  609. loopx/control_plane/turn_driver/executor.py +1468 -0
  610. loopx/control_plane/turn_driver/loop_controller.py +669 -0
  611. loopx/control_plane/turn_driver/settlement.py +318 -0
  612. loopx/control_plane/turn_driver/transaction.py +375 -0
  613. loopx/control_plane/work_items/__init__.py +1 -0
  614. loopx/control_plane/work_items/attention_fields.py +56 -0
  615. loopx/control_plane/work_items/attention_item.py +77 -0
  616. loopx/control_plane/work_items/attention_queue.py +322 -0
  617. loopx/control_plane/work_items/attention_routing.py +213 -0
  618. loopx/control_plane/work_items/autonomous_candidates.py +135 -0
  619. loopx/control_plane/work_items/autonomous_replan_ack.py +276 -0
  620. loopx/control_plane/work_items/autonomous_replan_obligation.py +786 -0
  621. loopx/control_plane/work_items/backlog_hygiene.py +59 -0
  622. loopx/control_plane/work_items/capability_monitor_fallback.py +221 -0
  623. loopx/control_plane/work_items/delivery_batch_scale.py +66 -0
  624. loopx/control_plane/work_items/delivery_outcome.py +152 -0
  625. loopx/control_plane/work_items/delivery_signals.py +113 -0
  626. loopx/control_plane/work_items/execution_obligation.py +235 -0
  627. loopx/control_plane/work_items/goal_route_hint.py +320 -0
  628. loopx/control_plane/work_items/interaction_contract.py +1540 -0
  629. loopx/control_plane/work_items/issue_meta_surface.py +159 -0
  630. loopx/control_plane/work_items/lifecycle.py +139 -0
  631. loopx/control_plane/work_items/operator_inbox.py +266 -0
  632. loopx/control_plane/work_items/outcome_followthrough.py +69 -0
  633. loopx/control_plane/work_items/primary_action.py +326 -0
  634. loopx/control_plane/work_items/progress_observation.py +630 -0
  635. loopx/control_plane/work_items/project_asset.py +675 -0
  636. loopx/control_plane/work_items/repair_delta.py +693 -0
  637. loopx/control_plane/work_items/runtime_capability_reentry.py +168 -0
  638. loopx/control_plane/work_items/semantic_replan_writeback.py +177 -0
  639. loopx/control_plane/work_items/status_contract.py +49 -0
  640. loopx/control_plane/work_items/task_graph.py +1046 -0
  641. loopx/control_plane/work_items/task_lease.py +1254 -0
  642. loopx/control_plane/work_items/task_lease_settlement.py +422 -0
  643. loopx/control_plane/work_items/work_lane.py +510 -0
  644. loopx/control_plane/work_items/work_lane_context.py +161 -0
  645. loopx/demo.py +247 -0
  646. loopx/diagnose.py +633 -0
  647. loopx/doctor.py +1251 -0
  648. loopx/domain_packs/__init__.py +1 -0
  649. loopx/domain_packs/issue_fix.py +571 -0
  650. loopx/domain_packs/ml_experiment.py +854 -0
  651. loopx/domain_state.py +137 -0
  652. loopx/dreaming.py +706 -0
  653. loopx/entrypoint.py +16 -0
  654. loopx/event_sourced_state.py +981 -0
  655. loopx/execution_profile.py +286 -0
  656. loopx/experiments/__init__.py +1 -0
  657. loopx/experiments/planner_worker/__init__.py +1 -0
  658. loopx/experiments/planner_worker/contract.py +523 -0
  659. loopx/experiments/planner_worker/runtime.py +391 -0
  660. loopx/experiments/planner_worker/traex.py +461 -0
  661. loopx/explore_graph.py +11 -0
  662. loopx/extensions/__init__.py +1 -0
  663. loopx/extensions/bundled.py +28 -0
  664. loopx/extensions/execution_envelope.py +126 -0
  665. loopx/extensions/lark/__init__.py +11 -0
  666. loopx/extensions/lark/event_collector.py +478 -0
  667. loopx/extensions/lark/event_collector_runtime.py +506 -0
  668. loopx/extensions/lark/event_inbox.py +454 -0
  669. loopx/extensions/lark/extension.toml +88 -0
  670. loopx/extensions/lark/goal_channel.py +44 -0
  671. loopx/extensions/lark/goal_channel_contracts.py +388 -0
  672. loopx/extensions/lark/goal_channel_lifecycle.py +218 -0
  673. loopx/extensions/lark/goal_channel_runtime.py +792 -0
  674. loopx/extensions/lark/goal_channel_setup.py +805 -0
  675. loopx/extensions/lark/goal_channel_targets.py +215 -0
  676. loopx/extensions/lark/goal_channel_transport.py +281 -0
  677. loopx/extensions/lark/inbox_reactions.py +650 -0
  678. loopx/extensions/lark/inbox_reply.py +430 -0
  679. loopx/extensions/lark/presentation/__init__.py +11 -0
  680. loopx/extensions/lark/presentation/explore_results.py +2276 -0
  681. loopx/extensions/lark/presentation/explore_singleflight.py +127 -0
  682. loopx/extensions/lark/presentation/explore_source_guard.py +121 -0
  683. loopx/extensions/lark/presentation/explore_stage_document.py +703 -0
  684. loopx/extensions/lark/presentation/explore_visual_integrity.py +122 -0
  685. loopx/extensions/lark/presentation/explore_visual_readback.py +452 -0
  686. loopx/extensions/lark/presentation/explore_visual_styles.py +156 -0
  687. loopx/extensions/lark/presentation/issue_fix_surface.py +612 -0
  688. loopx/extensions/lark/presentation/kanban.py +2791 -0
  689. loopx/extensions/lark/presentation/message_card.py +112 -0
  690. loopx/extensions/lark/presentation/periodic_report.py +261 -0
  691. loopx/extensions/lark/presentation/projection_rows.py +600 -0
  692. loopx/extensions/lark/presentation/record_io.py +95 -0
  693. loopx/extensions/lark/presentation/sync_receipt.py +145 -0
  694. loopx/extensions/lark/private_json.py +40 -0
  695. loopx/extensions/lark/provider.py +86 -0
  696. loopx/extensions/lark/reviewer_notification.py +604 -0
  697. loopx/extensions/manifest.py +385 -0
  698. loopx/extensions/openviking_periodic_report/__init__.py +17 -0
  699. loopx/extensions/openviking_periodic_report/activation.py +173 -0
  700. loopx/extensions/openviking_periodic_report/extension.toml +17 -0
  701. loopx/extensions/openviking_periodic_report/provider.py +355 -0
  702. loopx/extensions/openviking_periodic_report/sink.py +117 -0
  703. loopx/extensions/openviking_semantic_preference/__init__.py +5 -0
  704. loopx/extensions/openviking_semantic_preference/extension.toml +16 -0
  705. loopx/extensions/openviking_semantic_preference/history_export.py +484 -0
  706. loopx/extensions/openviking_semantic_preference/project_peer.py +68 -0
  707. loopx/extensions/openviking_semantic_preference/provider.py +312 -0
  708. loopx/extensions/presentation.py +979 -0
  709. loopx/extensions/process_runtime.py +204 -0
  710. loopx/extensions/readiness.py +168 -0
  711. loopx/extensions/runtime.py +931 -0
  712. loopx/extensions/scaffold.py +335 -0
  713. loopx/feedback.py +581 -0
  714. loopx/file_lock.py +382 -0
  715. loopx/global_registry.py +842 -0
  716. loopx/global_risks.py +970 -0
  717. loopx/global_todos.py +568 -0
  718. loopx/handoff_budget.py +28 -0
  719. loopx/heartbeat_prequota.py +80 -0
  720. loopx/heartbeat_prompt.py +159 -0
  721. loopx/help_surface.py +516 -0
  722. loopx/history.py +1507 -0
  723. loopx/host_loop_activation.py +1311 -0
  724. loopx/host_mode_planner.py +991 -0
  725. loopx/install_contract.py +1 -0
  726. loopx/interface_budget.py +196 -0
  727. loopx/long_task_cadence.py +208 -0
  728. loopx/materials.py +185 -0
  729. loopx/ml_experiment.py +3 -0
  730. loopx/onboarding.py +214 -0
  731. loopx/opencode2_goal_mode/README.md +81 -0
  732. loopx/opencode2_goal_mode/__init__.py +9 -0
  733. loopx/opencode2_goal_mode/opencode2-goal-worker.mjs +1018 -0
  734. loopx/opencode_goal_mode/README.md +99 -0
  735. loopx/opencode_goal_mode/__init__.py +13 -0
  736. loopx/opencode_goal_mode/goal-bridge-runtime.mjs +858 -0
  737. loopx/opencode_goal_mode/loopx-goal.js +8 -0
  738. loopx/operator_gate.py +420 -0
  739. loopx/orchestration.py +127 -0
  740. loopx/paths.py +59 -0
  741. loopx/pi_goal_mode/README.md +67 -0
  742. loopx/pi_goal_mode/__init__.py +13 -0
  743. loopx/pi_goal_mode/loopx-goal.ts +254 -0
  744. loopx/pi_goal_mode/pi-goal-loop-runtime.mjs +574 -0
  745. loopx/pr_review.py +1206 -0
  746. loopx/presentation/__init__.py +1 -0
  747. loopx/presentation/explore_views.py +1334 -0
  748. loopx/presentation/markdown.py +61 -0
  749. loopx/presentation/projection_source_reconcile.py +140 -0
  750. loopx/presentation/public_safety.py +42 -0
  751. loopx/presentation/renderers/__init__.py +17 -0
  752. loopx/presentation/renderers/goal_channel_html.py +269 -0
  753. loopx/presentation/renderers/periodic_report_html.py +786 -0
  754. loopx/presentation/renderers/periodic_report_markdown.py +184 -0
  755. loopx/presentation/renderers/quota_event_markdown.py +116 -0
  756. loopx/presentation/renderers/quota_markdown.py +1112 -0
  757. loopx/presentation/renderers/status_markdown.py +1570 -0
  758. loopx/presentation/renderers/trajectory_hygiene_markdown.py +39 -0
  759. loopx/presentation/renderers/turn_envelope_markdown.py +33 -0
  760. loopx/presentation/sinks/__init__.py +5 -0
  761. loopx/presentation/sinks/openviking_periodic_report.py +7 -0
  762. loopx/presentation/static_site.py +691 -0
  763. loopx/presets.py +369 -0
  764. loopx/project_alias.py +217 -0
  765. loopx/project_map.py +589 -0
  766. loopx/project_prompt.py +1153 -0
  767. loopx/project_skill_cli.py +125 -0
  768. loopx/project_skill_delivery.py +470 -0
  769. loopx/project_uninstall.py +462 -0
  770. loopx/promotion_gate.py +197 -0
  771. loopx/quota.py +1197 -0
  772. loopx/ready_score.py +413 -0
  773. loopx/registry.py +621 -0
  774. loopx/registry_writability.py +64 -0
  775. loopx/release_candidate.py +148 -0
  776. loopx/release_manifest.py +316 -0
  777. loopx/repository_identity.py +100 -0
  778. loopx/review_packet.py +1024 -0
  779. loopx/rollout_event_log.py +505 -0
  780. loopx/runtime.py +112 -0
  781. loopx/self_update.py +750 -0
  782. loopx/session_runtime.py +418 -0
  783. loopx/skill_install_readback.py +500 -0
  784. loopx/slash_command_install.py +1393 -0
  785. loopx/slash_commands.py +264 -0
  786. loopx/state_backup.py +573 -0
  787. loopx/state_migration.py +350 -0
  788. loopx/state_projection.py +809 -0
  789. loopx/state_refresh.py +1416 -0
  790. loopx/status.py +1383 -0
  791. loopx/status_server.py +935 -0
  792. loopx/summary_all.py +725 -0
  793. loopx/terminal_bench_agent.py +2056 -0
  794. loopx/thread_agent_binding.py +408 -0
  795. loopx/todo_followups.py +168 -0
  796. loopx/todo_suggestion_prompt.py +204 -0
  797. loopx/todos.py +2229 -0
  798. loopx/turn_identity.py +17 -0
  799. loopx/upgrade.py +1083 -0
  800. loopx/visible_governance.py +667 -0
  801. loopx/visible_multi_agent_launcher.py +1253 -0
  802. loopx/visible_multi_agent_tmux.py +429 -0
  803. loopx/worker_bridge.py +1574 -0
  804. loopx-0.4.8.dist-info/METADATA +708 -0
  805. loopx-0.4.8.dist-info/RECORD +811 -0
  806. loopx-0.4.8.dist-info/WHEEL +5 -0
  807. loopx-0.4.8.dist-info/entry_points.txt +5 -0
  808. loopx-0.4.8.dist-info/licenses/LICENSE +202 -0
  809. loopx-0.4.8.dist-info/licenses/LICENSE-MIT +21 -0
  810. loopx-0.4.8.dist-info/licenses/NOTICE +6 -0
  811. loopx-0.4.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env python3
2
+ """Smart entry for the `/loopx` slash command — the loopx setup helper.
3
+
4
+ LoopX does NOT own the run loop on Claude Code. Claude Code's native `/loop` is
5
+ the scheduler/executor; loopx provides the control-plane protocol (the MCP tools
6
+ + a per-iteration `.claude/loop.md`). `/loopx` just sets a goal up and hands off
7
+ to `/loop`.
8
+
9
+ Routing by first token:
10
+ <free text task> -> ONE-SHOT: ensure a goal exists for this project (bootstrap
11
+ if needed), register a default agent, add the task as a
12
+ todo, write `.claude/loop.md` (the protocol), and do one
13
+ bounded first segment. Then drive it with native `/loop`.
14
+ (no args) / on -> (re)write `.claude/loop.md` for this project's existing
15
+ goal and show how to drive it with `/loop`.
16
+ status -> the project's goal detail (objective, state, next, todos).
17
+ off -> remove `.claude/loop.md` (native `/loop` then has nothing
18
+ to run). Registry/goal are left intact.
19
+
20
+ The LoopX registry (`.loopx/registry.json`) is the single source of truth for
21
+ goal_id/agent/scope. The default agent `cc` is registered so the loopx identity
22
+ contract is active and `quota should-run --agent-id cc` is satisfied.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import re
28
+ import shutil
29
+ import subprocess
30
+ import sys
31
+ from pathlib import Path
32
+
33
+ HERE = Path(__file__).resolve().parent
34
+ DEFAULT_AGENT = "cc"
35
+
36
+ # registry-driven context, shared with the hooks/MCP
37
+ sys.path.insert(0, str(HERE.parent / "hooks"))
38
+ from goal_state import goal_context, find_registry, loop_md_path # noqa: E402
39
+
40
+
41
+ def gh_prefix():
42
+ """Cross-platform loopx invocation: the CLI shim if on PATH, else the module."""
43
+ exe = shutil.which("loopx")
44
+ return [exe] if exe else [sys.executable, "-m", "loopx.cli"]
45
+
46
+
47
+ def gh(args, cwd=None):
48
+ return subprocess.run(gh_prefix() + args, cwd=cwd, capture_output=True, text=True, timeout=120)
49
+
50
+
51
+ def slug(name: str) -> str:
52
+ s = re.sub(r"[^a-zA-Z0-9]+", "-", name).strip("-").lower() or "project"
53
+ return f"cc-{s}"[:48]
54
+
55
+
56
+ def loop_md_content(goal_id, agent_id) -> str:
57
+ """The per-iteration protocol that native `/loop` runs (written to
58
+ .claude/loop.md). loopx's should_run is the deterministic per-tick gate; the
59
+ agent uses the wired loopx MCP tools, never raw CLI guessing.
60
+
61
+ The leading `loopx:armed` marker persists WHICH goal /loopx armed for this
62
+ project, so goal_state.goal_context() resolves the right goal in multi-goal
63
+ registries instead of guessing from registry order."""
64
+ armed = json.dumps({"goal_id": goal_id, "agent_id": agent_id})
65
+ return (
66
+ f"<!-- loopx:armed {armed} -->\n"
67
+ f"loopx tick — advance goal `{goal_id}` (agent `{agent_id}`). Use the wired loopx MCP\n"
68
+ f"tools; do NOT run `loopx --help` or guess ids.\n\n"
69
+ f"1. Call `should_run()`. If should_run=false, say why in ONE line and STOP this\n"
70
+ f" iteration (do nothing else) — loopx has paused, gated, or converged.\n"
71
+ f"2. If should_run=true: `claim_task` the next open todo, do ONE bounded segment,\n"
72
+ f" then VERIFY it with a real check (build/test) — never claim success from\n"
73
+ f" reasoning — and `complete_task(..., agent_id=\"{agent_id}\", evidence=\"<ran + result>\")`.\n"
74
+ f"3. Stay within the goal's scope; do not start initiatives outside the todos.\n"
75
+ f" Irreversible actions (push/delete) only to finish work already authorized.\n"
76
+ f"4. Re-check `should_run()`; stop when should_run=false or no open todos remain.\n"
77
+ )
78
+
79
+
80
+ def write_loop_md(proj: Path, goal_id, agent_id) -> Path:
81
+ """Write the protocol to <project>/.claude/loop.md (bare `/loop` runs it)."""
82
+ path = loop_md_path(proj)
83
+ path.parent.mkdir(parents=True, exist_ok=True)
84
+ path.write_text(loop_md_content(goal_id, agent_id), encoding="utf-8")
85
+ return path
86
+
87
+
88
+ def goal_detail(ctx):
89
+ """Objective (from the registry goal entry's active-state file) + live state
90
+ (from quota should-run) for the `/loopx status` detail view."""
91
+ gid, reg, agent = ctx.get("goal_id"), ctx.get("registry"), ctx.get("agent_id")
92
+ objective = ""
93
+ if reg:
94
+ try:
95
+ regp = Path(reg)
96
+ data = json.loads(regp.read_text(encoding="utf-8"))
97
+ entry = next((g for g in data.get("goals", []) if g.get("id") == gid), None)
98
+ sf = (entry or {}).get("state_file")
99
+ if sf:
100
+ text = (regp.parent.parent / sf).read_text(encoding="utf-8")
101
+ m = re.search(r"^objective:\s*(.+)$", text, re.MULTILINE)
102
+ if m:
103
+ objective = m.group(1).strip().strip('"').strip("'")
104
+ except Exception:
105
+ pass
106
+ payload = {}
107
+ try:
108
+ cmd = gh_prefix() + (["--registry", reg] if reg else []) + \
109
+ ["--format", "json", "quota", "should-run", "--goal-id", gid]
110
+ if agent:
111
+ cmd += ["--agent-id", agent]
112
+ out = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
113
+ payload = json.loads(out.stdout or "{}")
114
+ except Exception:
115
+ pass
116
+ return objective, payload
117
+
118
+
119
+ def print_status(ctx):
120
+ gid = ctx.get("goal_id")
121
+ objective, d = goal_detail(ctx)
122
+ a = d.get("agent_todo_summary") or {}
123
+ done, open_ = a.get("done_count"), a.get("open_count")
124
+ gate = d.get("gate_prompt")
125
+ if gate:
126
+ state = f"⚠ needs you: {gate}"
127
+ elif d.get("should_run") is True:
128
+ state = "▶ running"
129
+ else:
130
+ state = f"⏸ {d.get('state') or 'paused'}" + (f" — {d['reason']}" if d.get("reason") else "")
131
+ print(f"goal : {gid}")
132
+ print(f"agent : {ctx.get('agent_id') or DEFAULT_AGENT}")
133
+ if objective:
134
+ print(f"objective : {objective}")
135
+ print(f"state : {state}")
136
+ if d.get("recommended_action"):
137
+ print(f"next : {d['recommended_action']}")
138
+ if done is not None or open_ is not None:
139
+ print(f"todos : {done} done / {open_} open")
140
+ for it in (a.get("first_open_items") or [])[:8]:
141
+ t = (it.get("text") or "").strip()
142
+ if t:
143
+ print(f" ▸ {t}")
144
+ armed = "armed (.claude/loop.md present)" if loop_md_path(Path.cwd()).exists() else "not armed (run /loopx to arm)"
145
+ print(f"loop : {armed} — drive with native /loop")
146
+
147
+
148
+ def main():
149
+ args = sys.argv[1:]
150
+ first = args[0] if args else None
151
+ proj = Path.cwd()
152
+
153
+ # off: remove the loop protocol; native /loop then has nothing to run.
154
+ if first == "off":
155
+ lp = loop_md_path(proj)
156
+ if not lp.exists():
157
+ print("goal-mode OFF (no .claude/loop.md here).")
158
+ return
159
+ try:
160
+ lp.unlink()
161
+ print("goal-mode OFF — removed .claude/loop.md. (Press Esc to stop a running /loop.)")
162
+ except OSError as e:
163
+ print(f"goal-mode OFF — could not remove {lp} ({e}); remove it manually.")
164
+ return
165
+
166
+ # status: full goal detail.
167
+ if first == "status":
168
+ ctx = goal_context(proj)
169
+ if not ctx:
170
+ print("loopx goal-mode: no goal in this project yet — run `/loopx <task>` to create one.")
171
+ return
172
+ print_status(ctx)
173
+ return
174
+
175
+ # bare (=on) / on: (re)arm THIS project's existing goal and show how to drive it.
176
+ if not args or first == "on":
177
+ ctx = goal_context(proj)
178
+ if not ctx or not ctx.get("goal_id"):
179
+ print("loopx goal-mode: ready — no goal set in this project yet.")
180
+ print("Tell me what to work on and I'll set it up:")
181
+ print(" /loopx <your goal> e.g. /loopx 写一个 RTL 模块并跑通仿真")
182
+ return
183
+ write_loop_md(proj, ctx["goal_id"], ctx.get("agent_id") or DEFAULT_AGENT)
184
+ print(f"goal-mode armed goal={ctx['goal_id']} agent={ctx.get('agent_id') or DEFAULT_AGENT}")
185
+ print("Drive it with native /loop: `/loop` (Claude self-paces) | `/loop 10m` (fixed).")
186
+ print("Stop with Esc; `/loopx off` removes the loop protocol.")
187
+ return
188
+
189
+ # free-text task -> one-shot setup + write loop.md + first bounded segment.
190
+ task = " ".join(args).strip().strip('"').strip("'")
191
+ reg = find_registry(proj)
192
+ if reg is not None:
193
+ ctx = goal_context(proj) or {}
194
+ goal_id = ctx.get("goal_id")
195
+ registry = str(reg)
196
+ else:
197
+ goal_id = slug(proj.name)
198
+ registry = str(proj / ".loopx" / "registry.json")
199
+ # Claude projects keep goal state under .claude/ (not the Codex-default .codex/)
200
+ state_file = f".claude/goals/{goal_id}/ACTIVE_GOAL_STATE.md"
201
+ r = gh(["bootstrap", "--project", str(proj), "--goal-id", goal_id,
202
+ "--objective", task, "--state-file", state_file, "--no-onboarding-scan"])
203
+ if "ok: `True`" not in r.stdout and "ok=True" not in r.stdout and r.returncode != 0:
204
+ print("[loopx] bootstrap failed:\n" + (r.stdout + r.stderr)[:600])
205
+ sys.exit(1)
206
+
207
+ if not goal_id:
208
+ print("[loopx] could not determine goal id")
209
+ sys.exit(1)
210
+
211
+ # register the default agent (identity contract) and add the task as a todo
212
+ gh(["--registry", registry, "configure-goal", "--goal-id", goal_id,
213
+ "--agent-model", "peer_v1", "--registered-agent", DEFAULT_AGENT, "--execute"])
214
+ add = gh(["--registry", registry, "--format", "json", "todo", "add",
215
+ "--goal-id", goal_id, "--role", "agent", "--text", task])
216
+ todo_id = ""
217
+ try:
218
+ todo_id = json.loads(add.stdout).get("todo_id", "")
219
+ except Exception:
220
+ pass
221
+
222
+ # write the per-iteration protocol; the RUN happens when the user types /loop
223
+ # (this command only SETS UP the goal — it must not do the work itself).
224
+ write_loop_md(proj, goal_id, DEFAULT_AGENT)
225
+
226
+ tid = todo_id or "(see should_run output)"
227
+ print("goal set up. loopx is the control plane; Claude Code's native /loop is the runtime.")
228
+ print(f" goal_id : {goal_id}")
229
+ print(f" agent : {DEFAULT_AGENT}")
230
+ print(f" todo_id : {tid}")
231
+ print(f" scope : {proj}")
232
+ print(f" task : {task}")
233
+ print(f" wrote : .claude/loop.md (the per-tick protocol)")
234
+ print()
235
+ print("START WORKING — run native `/loop` (Claude self-paces) or `/loop 10m` (fixed cadence).")
236
+ print("Each /loop tick runs: should_run -> claim_task -> ONE bounded verified segment -> complete_task.")
237
+ print("Stop with Esc or `/loopx off`.")
238
+
239
+
240
+ if __name__ == "__main__":
241
+ main()
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env python3
2
+ """Install the loopx Claude Code adapter — EXPLICIT, scoped, opt-in.
3
+
4
+ This is NOT run by the default loopx installer. It is invoked deliberately
5
+ (`LOOPX_INSTALL_CLAUDE=1 scripts/install-local.sh`, or directly). It installs the
6
+ minimum: the loopx **MCP server** (the control-plane tools) + the **`/loopx`**
7
+ slash command. The run loop is Claude Code's native `/loop`; loopx only provides
8
+ the `should_run` protocol, so NO global hooks are wired by default.
9
+
10
+ python install.py --scope project [--project DIR] # this project only (preferred)
11
+ python install.py --scope user # all your Claude Code projects
12
+ python install.py --scope ... --harden # ALSO add the optional
13
+ # PreToolUse should_run gate
14
+ # + statusline at that scope
15
+
16
+ `--scope` is required (a deliberate choice). User scope is announced loudly. We
17
+ NEVER delete existing permission rules; legacy loopx entries get a printed
18
+ cleanup suggestion instead.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import argparse
23
+ import json
24
+ import shutil
25
+ import subprocess
26
+ import sys
27
+ from pathlib import Path
28
+
29
+ PLUGIN_ROOT = Path(__file__).resolve().parents[1]
30
+ MCP_VENV = Path.home() / ".local" / "share" / "loopx" / "mcp-venv"
31
+
32
+
33
+ def _p(*parts) -> str:
34
+ return str(PLUGIN_ROOT.joinpath(*parts)).replace("\\", "/")
35
+
36
+
37
+ def _python_cmd() -> str:
38
+ """Interpreter to bake into hook / statusline / command strings — robust where
39
+ only `python` (not `python3`) is registered."""
40
+ return shutil.which("python3") or shutil.which("python") or sys.executable
41
+
42
+
43
+ def deep_merge(base: dict, add: dict) -> dict:
44
+ for k, v in add.items():
45
+ if isinstance(v, dict) and isinstance(base.get(k), dict):
46
+ deep_merge(base[k], v)
47
+ elif isinstance(v, list) and isinstance(base.get(k), list):
48
+ base[k] += [x for x in v if x not in base[k]]
49
+ else:
50
+ base[k] = v
51
+ return base
52
+
53
+
54
+ # ---- optional hardening (only with --harden) --------------------------------
55
+
56
+ def hardening_block() -> dict:
57
+ """The OPTIONAL per-tool gate + statusline. Not installed unless --harden."""
58
+ py = _python_cmd()
59
+ return {
60
+ "hooks": {
61
+ "PreToolUse": [{"matcher": "*", "hooks": [
62
+ {"type": "command", "command": f'{py} "{_p("hooks", "goal_policy.py")}"', "timeout": 10}]}],
63
+ },
64
+ "statusLine": {"type": "command", "command": f'{py} "{_p("statusline", "goal_status.py")}"'},
65
+ }
66
+
67
+
68
+ # ---- MCP dependency provisioning --------------------------------------------
69
+
70
+ def _venv_python(venv: Path) -> Path:
71
+ sub = "Scripts" if sys.platform == "win32" else "bin"
72
+ exe = "python.exe" if sys.platform == "win32" else "python"
73
+ return venv / sub / exe
74
+
75
+
76
+ # The server imports `mcp.server.fastmcp`, which MCP SDK 2.x no longer ships.
77
+ # Checking a bare `import mcp` accepts an interpreter that cannot actually run
78
+ # the server, so registration would write a config that fails to start —
79
+ # `cursor-agent mcp list` reports "Connection failed" and Claude silently drops
80
+ # the tools. Probe the module the server really needs.
81
+ MCP_PROBE = "import mcp.server.fastmcp"
82
+ # Upper bound for the same reason; drop it once loopx_mcp.py speaks the 2.x API.
83
+ MCP_REQUIREMENT = "mcp<2"
84
+
85
+
86
+ def _has_mcp(py) -> bool:
87
+ try:
88
+ return subprocess.run([str(py), "-c", MCP_PROBE], capture_output=True).returncode == 0
89
+ except (FileNotFoundError, OSError):
90
+ return False
91
+
92
+
93
+ def provision_mcp_python(dry: bool, allow_system_pip: bool = False) -> str:
94
+ """Return an interpreter that can `import mcp`, installing it into a dedicated
95
+ venv if needed (works under PEP 668 externally-managed pythons).
96
+
97
+ We install `mcp` ONLY into a dedicated venv we own. We never silently mutate
98
+ the user's active/system interpreter (`pip install --break-system-packages`);
99
+ that is gated behind an explicit ``allow_system_pip`` opt-in."""
100
+ if _has_mcp(sys.executable):
101
+ print(f"[deps] mcp already importable by {sys.executable}")
102
+ return sys.executable
103
+ vpy = _venv_python(MCP_VENV)
104
+ if _has_mcp(vpy):
105
+ print(f"[deps] reusing mcp venv {MCP_VENV}")
106
+ return str(vpy)
107
+ if dry:
108
+ print(f"[deps] (dry-run) would create venv {MCP_VENV} and pip install mcp")
109
+ return str(vpy)
110
+ print(f"[deps] creating mcp venv {MCP_VENV} …")
111
+ MCP_VENV.parent.mkdir(parents=True, exist_ok=True)
112
+ r = subprocess.run([sys.executable, "-m", "venv", str(MCP_VENV)], capture_output=True, text=True)
113
+ if r.returncode == 0:
114
+ subprocess.run([str(vpy), "-m", "pip", "install", "-q", "--upgrade", "pip"], capture_output=True, text=True)
115
+ pip = subprocess.run([str(vpy), "-m", "pip", "install", "-q", MCP_REQUIREMENT], capture_output=True, text=True)
116
+ if pip.returncode == 0 and _has_mcp(vpy):
117
+ print(f"[deps] mcp installed into {MCP_VENV}")
118
+ return str(vpy)
119
+ print("[deps] venv pip install failed:\n" + (pip.stdout + pip.stderr)[:300])
120
+ else:
121
+ print("[deps] venv creation failed:\n" + (r.stdout + r.stderr)[:300])
122
+ # The dedicated venv is the only place we install `mcp`. Do NOT touch the
123
+ # user's active/system interpreter unless they explicitly opted in.
124
+ if allow_system_pip:
125
+ print("[deps] --allow-system-pip: pip install --break-system-packages mcp")
126
+ subprocess.run([sys.executable, "-m", "pip", "install", "-q", "--break-system-packages", MCP_REQUIREMENT],
127
+ capture_output=True, text=True)
128
+ if _has_mcp(sys.executable):
129
+ return sys.executable
130
+ print("[deps] WARNING: could not provision `mcp` into a dedicated venv, and we will\n"
131
+ " NOT modify your system Python. The loopx MCP tools will not load until\n"
132
+ " you install `mcp` yourself, e.g.:\n"
133
+ f" {sys.executable} -m venv {MCP_VENV} && {vpy} -m pip install '{MCP_REQUIREMENT}'\n"
134
+ " (or re-run install.py with --allow-system-pip to use the active interpreter).")
135
+ return _python_cmd()
136
+
137
+
138
+ def install_mcp(
139
+ dry: bool,
140
+ py: str,
141
+ scope: str,
142
+ migrate_goal_harness: bool = False,
143
+ project_dir: Path | None = None,
144
+ ):
145
+ """Register the loopx MCP server at the chosen scope via `claude mcp add`.
146
+
147
+ We replace only OUR `loopx` entry. A legacy/user-owned `goal-harness` MCP is
148
+ left untouched by default — we don't delete a server we don't own. If one
149
+ exists we print a manual cleanup hint; `--migrate-goal-harness` removes it."""
150
+ if scope == "project" and project_dir is None:
151
+ raise ValueError("project_dir is required for project-scoped MCP registration")
152
+ cwd_run = str(project_dir) if scope == "project" else None
153
+ claude = shutil.which("claude")
154
+ mcp_path = _p("mcp", "loopx_mcp.py")
155
+ add = ["mcp", "add", "--scope", scope, "loopx", "--", py, mcp_path]
156
+ if not claude:
157
+ print("[mcp] claude CLI not on PATH — add the MCP server manually:\n claude " + " ".join(add))
158
+ return
159
+ print(f"[mcp] claude mcp add --scope {scope} loopx -- {py} <loopx_mcp.py>")
160
+ if dry:
161
+ return
162
+ subprocess.run(
163
+ [claude, "mcp", "remove", "--scope", scope, "loopx"],
164
+ capture_output=True,
165
+ text=True,
166
+ cwd=cwd_run,
167
+ )
168
+ has_gh = subprocess.run(
169
+ [claude, "mcp", "get", "goal-harness"],
170
+ capture_output=True,
171
+ text=True,
172
+ cwd=cwd_run,
173
+ ).returncode == 0
174
+ if has_gh:
175
+ if migrate_goal_harness:
176
+ print(f"[mcp] --migrate-goal-harness: removing legacy goal-harness MCP at {scope} scope")
177
+ subprocess.run(
178
+ [claude, "mcp", "remove", "--scope", scope, "goal-harness"],
179
+ capture_output=True,
180
+ text=True,
181
+ cwd=cwd_run,
182
+ )
183
+ else:
184
+ print("[mcp] note: a legacy `goal-harness` MCP entry exists — left untouched. Remove it "
185
+ f"yourself with `claude mcp remove --scope {scope} goal-harness`, or re-run with "
186
+ "--migrate-goal-harness.")
187
+ r = subprocess.run(
188
+ [claude, *add],
189
+ capture_output=True,
190
+ text=True,
191
+ cwd=cwd_run,
192
+ )
193
+ if r.returncode != 0:
194
+ print(" (mcp add failed; add manually:\n claude " + " ".join(add) + "\n " + (r.stdout + r.stderr)[:200] + ")")
195
+
196
+
197
+ # ---- /loopx command ----------------------------------------------------------
198
+
199
+ def command_md() -> str:
200
+ entry = _p("scripts", "goalmode_cmd.py")
201
+ py = _python_cmd()
202
+ return (
203
+ "---\n"
204
+ "description: loopx goal-mode setup (NOT Claude Code's built-in /goal). "
205
+ "`/loopx <task>` sets up a goal + writes .claude/loop.md; drive the loop with native /loop. "
206
+ "bare /loopx = arm; off | status.\n"
207
+ "argument-hint: <task to do> | (no args = arm) | off | status\n"
208
+ f"allowed-tools: Bash({py}:*)\n"
209
+ "---\n\n"
210
+ "Run the loopx setup helper and read its output:\n\n"
211
+ f"!`{py} \"{entry}\" $ARGUMENTS`\n\n"
212
+ "The output is loopx control-plane SETUP / status info — it is the COMPLETE, user-facing "
213
+ "result. Show it to the user VERBATIM and STOP. Do NOT do any work, claim todos, write "
214
+ "files, or loop here: the WORK runs when the user types Claude Code's native `/loop` (which "
215
+ "executes `.claude/loop.md`). Do not summarize a multi-line `status` detail block into one line.\n\n"
216
+ "NOTE: this is `/loopx` (loopx control-plane SETUP), NOT a runtime and NOT Claude Code's "
217
+ "built-in `/goal`. The run loop is native `/loop`; loopx provides the deterministic "
218
+ "`should_run` protocol.\n"
219
+ )
220
+
221
+
222
+ def install_command(dry: bool, cmd_dir: Path):
223
+ path = cmd_dir / "loopx.md"
224
+ print(f"[command] /loopx -> {path}")
225
+ if dry:
226
+ return
227
+ cmd_dir.mkdir(parents=True, exist_ok=True)
228
+ old = cmd_dir / "goalmode.md" # migrate the legacy /goalmode entry name
229
+ if old.exists():
230
+ old.unlink()
231
+ path.write_text(command_md(), encoding="utf-8")
232
+
233
+
234
+ def add_hardening(dry: bool, settings_path: Path):
235
+ """Deep-merge the optional hook + statusline into settings_path, preserving
236
+ existing config. NEVER deletes permission rules."""
237
+ cur = {}
238
+ if settings_path.exists():
239
+ try:
240
+ cur = json.loads(settings_path.read_text(encoding="utf-8"))
241
+ except Exception:
242
+ cur = {}
243
+ # prune prior loopx PreToolUse entries (avoid stacking on reinstall)
244
+ for grp in (cur.get("hooks", {}) or {}).get("PreToolUse", []) or []:
245
+ grp["hooks"] = [h for h in grp.get("hooks", []) if "goal_policy.py" not in str(h.get("command", ""))]
246
+ if isinstance(cur.get("hooks", {}).get("PreToolUse"), list):
247
+ cur["hooks"]["PreToolUse"] = [g for g in cur["hooks"]["PreToolUse"] if g.get("hooks")]
248
+ merged = deep_merge(cur, hardening_block())
249
+ print(f"[harden] PreToolUse should_run gate + statusline -> {settings_path}")
250
+ if not dry:
251
+ settings_path.parent.mkdir(parents=True, exist_ok=True)
252
+ settings_path.write_text(json.dumps(merged, indent=2), encoding="utf-8")
253
+
254
+
255
+ def warn_legacy_perms(settings_path: Path):
256
+ """Detect a legacy loopx credential-deny and SUGGEST manual cleanup. Never mutate."""
257
+ try:
258
+ cur = json.loads(settings_path.read_text(encoding="utf-8"))
259
+ except Exception:
260
+ return
261
+ deny = ((cur.get("permissions") or {}).get("deny")) or []
262
+ legacy = [r for r in deny if r in ("Read(~/.ssh/**)", "Read(~/.aws/**)")]
263
+ if legacy:
264
+ print(f"[note] {settings_path} has loopx-era permission deny rules {legacy}. "
265
+ "We no longer add these and will NOT remove them automatically. "
266
+ "To drop them, edit that file's `permissions.deny` by hand.")
267
+
268
+
269
+ def main():
270
+ ap = argparse.ArgumentParser()
271
+ ap.add_argument("--scope", choices=["user", "project"], required=True,
272
+ help="user = ~/.claude (all projects); project = THIS project's .claude (preferred)")
273
+ ap.add_argument("--project", default=None, help="project dir for --scope project (default: cwd)")
274
+ ap.add_argument("--harden", action="store_true",
275
+ help="ALSO install the optional PreToolUse should_run gate + statusline")
276
+ ap.add_argument("--skip-mcp", action="store_true",
277
+ help="skip MCP venv provisioning + `claude mcp add` (for tests/CI)")
278
+ ap.add_argument("--allow-system-pip", action="store_true",
279
+ help="if the dedicated mcp venv can't be built, fall back to "
280
+ "`pip install --break-system-packages mcp` into the active interpreter "
281
+ "(off by default — we don't mutate your system Python)")
282
+ ap.add_argument("--migrate-goal-harness", action="store_true",
283
+ help="also remove a legacy `goal-harness` MCP entry at this scope "
284
+ "(off by default — we don't delete MCP servers we don't own)")
285
+ ap.add_argument("--dry-run", action="store_true")
286
+ a = ap.parse_args()
287
+ dry = a.dry_run
288
+
289
+ project_dir = None
290
+ if a.scope == "project":
291
+ project_dir = Path(a.project).resolve() if a.project else Path.cwd()
292
+ claude_dir = project_dir / ".claude"
293
+ print(f"[scope] PROJECT — installs into {claude_dir} (this project only)")
294
+ else:
295
+ claude_dir = Path.home() / ".claude"
296
+ print("[scope] USER — installs into ~/.claude. The /loopx command and MCP become")
297
+ print(" available in ALL your Claude Code projects." +
298
+ (" --harden adds USER-LEVEL, matcher-wide hooks too." if a.harden else ""))
299
+
300
+ if a.skip_mcp:
301
+ print("[mcp] skipped (--skip-mcp)")
302
+ else:
303
+ mcp_python = provision_mcp_python(dry, a.allow_system_pip)
304
+ install_mcp(
305
+ dry,
306
+ mcp_python,
307
+ a.scope,
308
+ a.migrate_goal_harness,
309
+ project_dir=project_dir,
310
+ )
311
+ install_command(dry, claude_dir / "commands")
312
+
313
+ settings_path = claude_dir / "settings.json"
314
+ if a.harden:
315
+ add_hardening(dry, settings_path)
316
+ else:
317
+ print("[harden] skipped (default): no hooks/statusline installed. Add later with --harden.")
318
+ warn_legacy_perms(settings_path)
319
+
320
+ print("\nloopx Claude adapter installed.")
321
+ print("Next: in a project with a goal, type `/loopx <task>`, then drive it with native `/loop`.")
322
+ print("Restart any open Claude Code session so the command/MCP load.")
323
+ if dry:
324
+ print("(dry-run: nothing written)")
325
+
326
+
327
+ if __name__ == "__main__":
328
+ main()
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ """Statusline segment: a glanceable loopx goal state for the Claude Code CLI.
3
+
4
+ Claude Code feeds session JSON on stdin; we resolve THIS project's goal (only
5
+ while goal-mode is armed) and run one quick `loopx quota should-run` probe, then
6
+ render a single compact line. We surface the signals a watching user actually
7
+ needs, in priority order:
8
+
9
+ 1. ⚠ needs you — an operator gate / open user todo is blocking (highest signal)
10
+ 2. ▶ working — should_run=true, plus the next concrete action loopx picked
11
+ 3. ⏸ <state> — paused/holding, plus the short reason (quota, gate, health…)
12
+
13
+ …always tailed with todo progress (done✓/open▸). Prints nothing when there is no
14
+ goal here or goal-mode is off.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ import subprocess
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ # Share the registry-driven resolver with the hooks so the statusline shows THIS
24
+ # session's project goal, and only while goal-mode is armed (heartbeat installed).
25
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "hooks"))
26
+ from goal_state import active_context
27
+
28
+
29
+ import shutil as _shutil
30
+ def _gh_prefix():
31
+ _exe = _shutil.which("loopx")
32
+ return [_exe] if _exe else [__import__("sys").executable, "-m", "loopx.cli"]
33
+
34
+
35
+ def _clip(s, n: int) -> str:
36
+ s = " ".join(str(s or "").split()) # collapse whitespace/newlines
37
+ return s if len(s) <= n else s[: n - 1] + "…"
38
+
39
+
40
+ def _render(gid: str, d: dict) -> str:
41
+ """Turn a `quota should-run` payload into one compact statusline string."""
42
+ agent = d.get("agent_todo_summary") or {}
43
+ done, open_ = agent.get("done_count"), agent.get("open_count")
44
+ prog = f"{done}✓/{open_}▸" if (done is not None or open_ is not None) else ""
45
+
46
+ ic = d.get("interaction_contract") or {}
47
+ user_ch = ic.get("user_channel") or {}
48
+ users = d.get("user_todo_summary") or {}
49
+ gate = d.get("gate_prompt")
50
+ needs_user = bool(gate) or bool(user_ch.get("action_required")) or bool(users.get("open_count"))
51
+
52
+ if needs_user:
53
+ msg = gate or f"{users.get('open_count') or 'a'} user todo(s) to answer"
54
+ return f"[loopx {gid} · ⚠ needs you: {_clip(msg, 46)}]"
55
+
56
+ if d.get("should_run") is True:
57
+ nxt = d.get("recommended_action")
58
+ head = f"▶ {prog}".rstrip() if prog else "▶ working"
59
+ return f"[loopx {gid} · {head}" + (f" · next: {_clip(nxt, 40)}]" if nxt else "]")
60
+
61
+ # paused / holding: lead with WHY (state + short reason), then progress
62
+ state = (d.get("state") or "paused").strip()
63
+ reason = d.get("reason")
64
+ tail = f" · {prog}" if prog else ""
65
+ return f"[loopx {gid} · ⏸ {state}" + (f": {_clip(reason, 38)}" if reason else "") + f"{tail}]"
66
+
67
+
68
+ def main():
69
+ raw = sys.stdin.read() # Claude's session json carries this session's cwd
70
+ cwd = None
71
+ try:
72
+ sess = json.loads(raw or "{}")
73
+ cwd = sess.get("cwd") or (sess.get("workspace") or {}).get("current_dir")
74
+ except Exception:
75
+ pass
76
+ st = active_context(cwd or Path.cwd())
77
+ if not st:
78
+ print("") # no goal here, or goal-mode off -> no segment
79
+ return
80
+ gid = st.get("goal_id", "?")
81
+ try:
82
+ cmd = list(_gh_prefix())
83
+ if st.get("registry"):
84
+ cmd += ["--registry", st["registry"]]
85
+ cmd += ["--format", "json", "quota", "should-run", "--goal-id", gid]
86
+ if st.get("agent_id"):
87
+ cmd += ["--agent-id", st["agent_id"]]
88
+ out = subprocess.run(cmd, capture_output=True, text=True, timeout=8)
89
+ d = json.loads(out.stdout or "{}")
90
+ print(_render(gid, d))
91
+ except Exception:
92
+ # probe failed: still show that goal-mode is armed, without counts/state
93
+ print(f"[loopx {gid}]")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()