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,1375 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import shlex
5
+ import shutil
6
+ from collections.abc import Mapping
7
+ from copy import deepcopy
8
+ from datetime import datetime
9
+ from pathlib import Path, PurePosixPath
10
+ from typing import Any
11
+
12
+ from .boundary_authority import (
13
+ build_checkpointed_boundary_authority_entry,
14
+ checkpointed_boundary_authority_summary,
15
+ )
16
+ from .agent_registry import normalize_registered_agents
17
+ from .capabilities.change_quality.policy import (
18
+ CHANGE_QUALITY_POLICY_SCHEMA_VERSION,
19
+ change_quality_goal_policy_summary,
20
+ )
21
+ from .control_plane import compact_control_plane_policy, control_plane_policy_summary
22
+ from .configuration_catalog import build_goal_configuration_catalog
23
+ from .explore_graph import compact_explore_graph_policy
24
+ from .orchestration import (
25
+ DEFAULT_ORCHESTRATION_MODE,
26
+ EXPLORE_HARNESS_PROFILES,
27
+ MULTI_SUBAGENT_ORCHESTRATION_MODE,
28
+ compact_orchestration_policy,
29
+ compact_peer_task_coordination_policy,
30
+ orchestration_policy_summary,
31
+ )
32
+ from .quota import goal_quota_config
33
+ from .registry import atomic_write_json, read_json, registry_goals
34
+ from .control_plane.reward_memory import (
35
+ reward_memory_goal_policy,
36
+ reward_memory_goal_policy_summary,
37
+ )
38
+ from .control_plane.todos.contract import normalize_todo_claimed_by
39
+ from .control_plane.todos.mutation_authority import (
40
+ normalize_todo_lifecycle_authority,
41
+ )
42
+ from .execution_profile import (
43
+ compact_execution_profile,
44
+ execution_profile_with_turn_granularity,
45
+ normalize_turn_granularity,
46
+ )
47
+ from .control_plane.agents.legacy_migration import (
48
+ completed_peer_agent_runtime_migration,
49
+ legacy_agent_hierarchy_present,
50
+ migrate_coordination_to_peer_v1,
51
+ peer_agent_runtime_migration_completed,
52
+ peer_agent_runtime_migration_id,
53
+ )
54
+ from .control_plane.agents.profile import normalize_agent_profile
55
+ from .control_plane.agents.work_mode import normalize_agent_work_modes
56
+ from .control_plane.agents.runtime_model import (
57
+ AgentRuntimeModel,
58
+ agent_runtime_model_for_goal,
59
+ )
60
+ from .control_plane.agents.supervisor import normalize_peer_supervisor
61
+
62
+
63
+ WAITING_ON_CHOICES = (
64
+ "codex",
65
+ "user_or_controller",
66
+ "controller",
67
+ "external_evidence",
68
+ )
69
+
70
+ MULTI_SUBAGENT_FEATURE_CHOICES = ("off", "enabled")
71
+ DEFAULT_MULTI_SUBAGENT_MAX_CHILDREN = 2
72
+ AGENT_MODEL_CHOICES = tuple(model.value for model in AgentRuntimeModel)
73
+
74
+
75
+ def _control_plane(goal: dict[str, Any]) -> dict[str, Any]:
76
+ value = goal.get("control_plane")
77
+ return value if isinstance(value, dict) else {}
78
+
79
+
80
+ def _mutable_control_plane(goal: dict[str, Any]) -> dict[str, Any]:
81
+ control_plane = _control_plane(goal)
82
+ goal["control_plane"] = control_plane
83
+ return control_plane
84
+
85
+
86
+ def _reviewer_notification_config_summary(goal: dict[str, Any]) -> dict[str, bool]:
87
+ control_plane = _control_plane(goal)
88
+ issue_fix = (
89
+ control_plane.get("issue_fix")
90
+ if isinstance(control_plane.get("issue_fix"), dict)
91
+ else {}
92
+ )
93
+ reviewer_notification = (
94
+ issue_fix.get("reviewer_notification")
95
+ if isinstance(issue_fix.get("reviewer_notification"), dict)
96
+ else {}
97
+ )
98
+ return {
99
+ "enabled": reviewer_notification.get("enabled") is True,
100
+ "config_pointer_registered": bool(reviewer_notification.get("config_path")),
101
+ }
102
+
103
+
104
+ def _lark_event_inbox_config_summary(goal: dict[str, Any]) -> dict[str, bool]:
105
+ control_plane = _control_plane(goal)
106
+ inbox = (
107
+ control_plane.get("lark_event_inbox")
108
+ if isinstance(control_plane.get("lark_event_inbox"), dict)
109
+ else {}
110
+ )
111
+ return {
112
+ "enabled": inbox.get("enabled") is True,
113
+ "config_pointer_registered": bool(inbox.get("config_path")),
114
+ }
115
+
116
+
117
+ def _lark_kanban_heartbeat_config_summary(goal: dict[str, Any]) -> dict[str, bool]:
118
+ control_plane = _control_plane(goal)
119
+ lark_kanban = (
120
+ control_plane.get("lark_kanban")
121
+ if isinstance(control_plane.get("lark_kanban"), dict)
122
+ else {}
123
+ )
124
+ return {"enabled": lark_kanban.get("heartbeat_sync_enabled") is True}
125
+
126
+
127
+ def _local_private_config_path(
128
+ value: str | None, *, label: str = "local-private config"
129
+ ) -> str | None:
130
+ if value is None:
131
+ return None
132
+ text = str(value).strip().replace("\\", "/")
133
+ path = PurePosixPath(text)
134
+ if (
135
+ not text
136
+ or path.is_absolute()
137
+ or ".." in path.parts
138
+ or len(path.parts) < 3
139
+ or path.parts[:2] != (".loopx", "config")
140
+ or path.suffix != ".json"
141
+ ):
142
+ raise ValueError(
143
+ f"{label} must be a repo-relative JSON path "
144
+ "under .loopx/config/"
145
+ )
146
+ return path.as_posix()
147
+
148
+
149
+ def _now_iso() -> str:
150
+ return datetime.now().astimezone().replace(microsecond=0).isoformat()
151
+
152
+
153
+ def _positive_number(value: float | None, *, field: str) -> float | None:
154
+ if value is None:
155
+ return None
156
+ if value <= 0:
157
+ raise ValueError(f"{field} must be greater than 0")
158
+ return float(value)
159
+
160
+
161
+ def _non_negative_number(value: float | None, *, field: str) -> float | None:
162
+ if value is None:
163
+ return None
164
+ if value < 0:
165
+ raise ValueError(f"{field} must be greater than or equal to 0")
166
+ return float(value)
167
+
168
+
169
+ def _non_negative_int(value: int | None, *, field: str) -> int | None:
170
+ if value is None:
171
+ return None
172
+ if value < 0:
173
+ raise ValueError(f"{field} must be greater than or equal to 0")
174
+ return int(value)
175
+
176
+
177
+ def _clean_domains(values: list[str] | None) -> list[str] | None:
178
+ if values is None:
179
+ return None
180
+ domains: list[str] = []
181
+ for value in values:
182
+ for part in str(value).split(","):
183
+ domain = part.strip()
184
+ if domain and domain not in domains:
185
+ domains.append(domain)
186
+ return domains
187
+
188
+
189
+ def _clean_registered_agents(values: list[str] | None) -> list[str] | None:
190
+ if values is None:
191
+ return None
192
+ agents: list[str] = []
193
+ for value in values:
194
+ for part in str(value).split(","):
195
+ raw_agent = part.strip()
196
+ if not raw_agent:
197
+ continue
198
+ agent = normalize_todo_claimed_by(raw_agent)
199
+ if not agent:
200
+ raise ValueError("registered agents must be public-safe tokens such as codex-main-control")
201
+ if agent not in agents:
202
+ agents.append(agent)
203
+ return agents
204
+
205
+
206
+ def _clean_write_scope(values: list[str] | None) -> list[str] | None:
207
+ if values is None:
208
+ return None
209
+ scopes: list[str] = []
210
+ for value in values:
211
+ for part in str(value).split(","):
212
+ scope = part.strip()
213
+ if scope and scope not in scopes:
214
+ scopes.append(scope)
215
+ return scopes
216
+
217
+
218
+ def _settings_summary(goal: dict[str, Any]) -> dict[str, Any]:
219
+ quota = goal_quota_config(goal)
220
+ control_plane = compact_control_plane_policy(goal.get("control_plane"))
221
+ orchestration = compact_orchestration_policy(goal.get("spawn_policy"))
222
+ coordination = goal.get("coordination") if isinstance(goal.get("coordination"), dict) else {}
223
+ agent_model = agent_runtime_model_for_goal(goal)
224
+ registered_agents = normalize_registered_agents(
225
+ coordination.get("registered_agents")
226
+ )
227
+ summary = {
228
+ "execution_profile": compact_execution_profile(goal.get("execution_profile")),
229
+ "quota": {
230
+ "compute": quota.get("compute"),
231
+ "window_hours": quota.get("window_hours"),
232
+ },
233
+ "control_plane": control_plane,
234
+ "issue_fix_reviewer_notification": _reviewer_notification_config_summary(
235
+ goal
236
+ ),
237
+ "lark_event_inbox": _lark_event_inbox_config_summary(goal),
238
+ "lark_kanban_heartbeat_sync": _lark_kanban_heartbeat_config_summary(goal),
239
+ "reward_memory": reward_memory_goal_policy_summary(goal),
240
+ "change_quality_qualification": change_quality_goal_policy_summary(goal),
241
+ "explore_graph": compact_explore_graph_policy(goal.get("explore_graph")),
242
+ "orchestration": orchestration,
243
+ "waiting_on": goal.get("waiting_on"),
244
+ "write_scope": _clean_write_scope(coordination.get("write_scope") or []) or [],
245
+ "checkpointed_boundary_authority": checkpointed_boundary_authority_summary(coordination),
246
+ "registered_agents": registered_agents,
247
+ "peer_task_coordination": deepcopy(
248
+ compact_peer_task_coordination_policy(coordination)
249
+ ),
250
+ "todo_lifecycle_authority": normalize_todo_lifecycle_authority(
251
+ coordination.get("todo_lifecycle_authority"),
252
+ registered_agents=registered_agents,
253
+ ),
254
+ "agent_profiles": deepcopy(
255
+ coordination.get("agent_profiles")
256
+ if isinstance(coordination.get("agent_profiles"), dict)
257
+ else {}
258
+ ),
259
+ "agent_work_modes": normalize_agent_work_modes(
260
+ coordination.get("agent_work_modes"),
261
+ registered_agents=registered_agents,
262
+ ),
263
+ "agent_model": agent_model.value,
264
+ "configured_agent_model": coordination.get("agent_model"),
265
+ "legacy_hierarchy_present": legacy_agent_hierarchy_present(goal),
266
+ "peer_runtime_migration": deepcopy(
267
+ completed_peer_agent_runtime_migration(goal)
268
+ ),
269
+ "supervisor": deepcopy(
270
+ normalize_peer_supervisor(
271
+ coordination.get("supervisor"),
272
+ registered_agents=normalize_registered_agents(
273
+ coordination.get("registered_agents")
274
+ ),
275
+ )
276
+ ),
277
+ }
278
+ return summary
279
+
280
+
281
+ def _multi_subagent_feature_status(orchestration: dict[str, Any]) -> str:
282
+ if (
283
+ orchestration.get("mode") == MULTI_SUBAGENT_ORCHESTRATION_MODE
284
+ and orchestration.get("spawn_allowed") is True
285
+ and int(orchestration.get("max_children") or 0) > 0
286
+ ):
287
+ return "enabled"
288
+ return "off"
289
+
290
+
291
+ def _changed_fields(before: dict[str, Any], after: dict[str, Any]) -> list[str]:
292
+ changed: list[str] = []
293
+ for group, before_value in before.items():
294
+ after_value = after.get(group)
295
+ if before_value != after_value:
296
+ changed.append(group)
297
+ return changed
298
+
299
+
300
+ def _heartbeat_scope_hint(
301
+ agent_id: str,
302
+ ) -> str:
303
+ del agent_id
304
+ return "peer task claims, leases, evidence, and bounded delivery"
305
+
306
+
307
+ def _build_heartbeat_prompt_migration(
308
+ *,
309
+ goal_id: str,
310
+ changed_fields: list[str],
311
+ after: dict[str, Any],
312
+ migration_id: str | None = None,
313
+ migration_acknowledged: bool = False,
314
+ ) -> dict[str, Any] | None:
315
+ if not migration_id and not any(
316
+ field in changed_fields
317
+ for field in (
318
+ "registered_agents",
319
+ "configured_agent_model",
320
+ "legacy_hierarchy_present",
321
+ )
322
+ ):
323
+ return None
324
+ registered_agents = [
325
+ str(agent).strip()
326
+ for agent in after.get("registered_agents") or []
327
+ if str(agent).strip()
328
+ ]
329
+ if not registered_agents:
330
+ return None
331
+ agent_model = AgentRuntimeModel.PEER_V1.value
332
+ ordered_agents = list(registered_agents)
333
+ commands = []
334
+ for agent in ordered_agents:
335
+ scope = _heartbeat_scope_hint(agent)
336
+ command = {
337
+ "agent_id": agent,
338
+ "command": (
339
+ "loopx heartbeat-prompt --thin "
340
+ f"--goal-id {shlex.quote(goal_id)} "
341
+ f"--agent-id {shlex.quote(agent)} "
342
+ f"--agent-scope {shlex.quote(scope)}"
343
+ ),
344
+ }
345
+ commands.append(command)
346
+ payload = {
347
+ "schema_version": "heartbeat_prompt_migration_v1",
348
+ "agent_model": agent_model,
349
+ "migration_id": migration_id,
350
+ "host_update_idempotency_key": migration_id,
351
+ "status": "completed" if migration_acknowledged else "required",
352
+ "reason": (
353
+ "the host automation update was acknowledged and the registry hard cut completed"
354
+ if migration_acknowledged
355
+ else "coordination agent identity changed; installed heartbeats should be "
356
+ "regenerated with identity-aware prompt args"
357
+ ),
358
+ "action": (
359
+ "none; this migration id is complete and will not be projected again"
360
+ if migration_acknowledged
361
+ else "update each installed host automation once using migration_id as the "
362
+ "idempotency key, then run completion_command"
363
+ ),
364
+ "commands": [] if migration_acknowledged else commands,
365
+ }
366
+ if migration_id and not migration_acknowledged:
367
+ payload["completion_command"] = (
368
+ "loopx configure-goal "
369
+ f"--goal-id {shlex.quote(goal_id)} "
370
+ f"--ack-automation-prompt-migration {shlex.quote(migration_id)} --execute"
371
+ )
372
+ return payload
373
+
374
+
375
+ def _build_supervisor_prompt_setup(
376
+ *,
377
+ goal_id: str,
378
+ changed_fields: list[str],
379
+ after: dict[str, Any],
380
+ ) -> dict[str, Any] | None:
381
+ if "supervisor" not in changed_fields:
382
+ return None
383
+ supervisor = after.get("supervisor")
384
+ if not isinstance(supervisor, dict):
385
+ return {
386
+ "schema_version": "supervisor_prompt_setup_v0",
387
+ "status": "disabled",
388
+ "command": None,
389
+ }
390
+ agent_id = str(supervisor.get("agent_id") or "")
391
+ return {
392
+ "schema_version": "supervisor_prompt_setup_v0",
393
+ "status": "ready",
394
+ "agent_id": agent_id,
395
+ "command": (
396
+ "loopx supervisor-prompt "
397
+ f"--goal-id {shlex.quote(goal_id)} "
398
+ f"--agent-id {shlex.quote(agent_id)}"
399
+ ),
400
+ }
401
+
402
+
403
+ def configure_goal(
404
+ *,
405
+ registry_path: Path,
406
+ goal_id: str,
407
+ quota_compute: float | None = None,
408
+ quota_window_hours: float | None = None,
409
+ execution_turn_granularity: str | None = None,
410
+ self_repair_enabled: bool | None = None,
411
+ self_repair_health: bool | None = None,
412
+ self_repair_waiting_projection: bool | None = None,
413
+ change_quality_enabled: bool | None = None,
414
+ change_quality_safe_fix: bool | None = None,
415
+ change_quality_strict_receipt: bool | None = None,
416
+ multi_subagent_feature: str | None = None,
417
+ orchestration_mode: str | None = None,
418
+ spawn_allowed: bool | None = None,
419
+ max_children: int | None = None,
420
+ allowed_domains: list[str] | None = None,
421
+ clear_allowed_domains: bool = False,
422
+ explore_harness_enabled: bool | None = None,
423
+ explore_harness_profile: str | None = None,
424
+ clear_explore_harness_profile: bool = False,
425
+ explore_graph_enabled: bool | None = None,
426
+ registered_agents: list[str] | None = None,
427
+ clear_registered_agents: bool = False,
428
+ peer_task_coordinator: str | None = None,
429
+ clear_peer_task_coordinator: bool = False,
430
+ agent_profiles: list[dict[str, Any]] | None = None,
431
+ clear_agent_profiles: list[str] | None = None,
432
+ agent_work_modes: dict[str, str] | None = None,
433
+ clear_agent_work_modes: list[str] | None = None,
434
+ todo_lifecycle_authority: list[dict[str, Any]] | None = None,
435
+ clear_todo_lifecycle_authority: list[str] | None = None,
436
+ agent_model: str | None = None,
437
+ automation_prompt_migration_ack: str | None = None,
438
+ supervisor_agent: str | None = None,
439
+ supervised_agents: list[str] | None = None,
440
+ clear_supervisor: bool = False,
441
+ write_scope: list[str] | None = None,
442
+ replace_write_scope: bool = False,
443
+ clear_write_scope: bool = False,
444
+ waiting_on: str | None = None,
445
+ clear_waiting_on: bool = False,
446
+ boundary_authority_scopes: list[str] | None = None,
447
+ boundary_authority_source: str | None = None,
448
+ boundary_authority_decision_id: str | None = None,
449
+ boundary_authority_recorded_at: str | None = None,
450
+ boundary_authority_expires_at: str | None = None,
451
+ clear_boundary_authority: bool = False,
452
+ issue_fix_reviewer_notification_config: str | None = None,
453
+ clear_issue_fix_reviewer_notification_config: bool = False,
454
+ lark_event_inbox_config: str | None = None,
455
+ clear_lark_event_inbox_config: bool = False,
456
+ lark_kanban_heartbeat_sync: bool | None = None,
457
+ reward_memory_config: str | None = None,
458
+ reward_memory_agents: list[str] | None = None,
459
+ clear_reward_memory_config: bool = False,
460
+ execute: bool = False,
461
+ ) -> dict[str, Any]:
462
+ if not registry_path.exists():
463
+ raise FileNotFoundError(f"registry file does not exist: {registry_path}")
464
+ if execution_turn_granularity is not None:
465
+ execution_turn_granularity = normalize_turn_granularity(
466
+ execution_turn_granularity
467
+ )
468
+ if clear_allowed_domains and allowed_domains:
469
+ raise ValueError("--clear-allowed-domains cannot be combined with --allowed-domain")
470
+ if clear_explore_harness_profile and explore_harness_profile:
471
+ raise ValueError(
472
+ "--clear-explore-harness-profile cannot be combined with --explore-harness-profile"
473
+ )
474
+ if clear_registered_agents and registered_agents:
475
+ raise ValueError("--clear-registered-agents cannot be combined with --registered-agent")
476
+ if clear_peer_task_coordinator and peer_task_coordinator:
477
+ raise ValueError(
478
+ "--clear-peer-task-coordinator cannot be combined with "
479
+ "--peer-task-coordinator"
480
+ )
481
+ if agent_model is not None:
482
+ agent_model = str(agent_model).strip().lower()
483
+ if agent_model not in AGENT_MODEL_CHOICES:
484
+ raise ValueError("--agent-model must be one of: " + ", ".join(AGENT_MODEL_CHOICES))
485
+ if automation_prompt_migration_ack is not None:
486
+ automation_prompt_migration_ack = str(
487
+ automation_prompt_migration_ack
488
+ ).strip()
489
+ if not automation_prompt_migration_ack:
490
+ raise ValueError("--ack-automation-prompt-migration requires a migration id")
491
+ if registered_agents is not None or clear_registered_agents:
492
+ raise ValueError(
493
+ "--ack-automation-prompt-migration cannot change registered agents; "
494
+ "complete the runtime cutover first, then update the peer set separately"
495
+ )
496
+ if clear_supervisor and (supervisor_agent or supervised_agents):
497
+ raise ValueError(
498
+ "--clear-supervisor cannot be combined with --supervisor-agent or "
499
+ "--supervised-agent"
500
+ )
501
+ if supervised_agents and not supervisor_agent:
502
+ raise ValueError("--supervised-agent requires --supervisor-agent")
503
+ if clear_write_scope and write_scope:
504
+ raise ValueError("--clear-write-scope cannot be combined with --write-scope")
505
+ if replace_write_scope and not write_scope:
506
+ raise ValueError("--replace-write-scope requires --write-scope")
507
+ if clear_write_scope and replace_write_scope:
508
+ raise ValueError("--clear-write-scope cannot be combined with --replace-write-scope")
509
+ if clear_waiting_on and waiting_on:
510
+ raise ValueError("--clear-waiting-on cannot be combined with --waiting-on")
511
+ adding_boundary_authority = any(
512
+ value
513
+ for value in (
514
+ boundary_authority_scopes,
515
+ boundary_authority_source,
516
+ boundary_authority_decision_id,
517
+ boundary_authority_recorded_at,
518
+ boundary_authority_expires_at,
519
+ )
520
+ )
521
+ if clear_boundary_authority and adding_boundary_authority:
522
+ raise ValueError("--clear-boundary-authority cannot be combined with boundary authority fields")
523
+ if (
524
+ clear_issue_fix_reviewer_notification_config
525
+ and issue_fix_reviewer_notification_config
526
+ ):
527
+ raise ValueError(
528
+ "--clear-issue-fix-reviewer-notification-config cannot be combined "
529
+ "with --issue-fix-reviewer-notification-config"
530
+ )
531
+ if clear_lark_event_inbox_config and lark_event_inbox_config:
532
+ raise ValueError(
533
+ "--clear-lark-event-inbox-config cannot be combined with "
534
+ "--lark-event-inbox-config"
535
+ )
536
+ if clear_reward_memory_config and (
537
+ reward_memory_config or reward_memory_agents
538
+ ):
539
+ raise ValueError(
540
+ "--clear-reward-memory-config cannot be combined with "
541
+ "--reward-memory-config or --reward-memory-agent"
542
+ )
543
+ if waiting_on and waiting_on not in WAITING_ON_CHOICES:
544
+ raise ValueError("--waiting-on must be one of: " + ", ".join(WAITING_ON_CHOICES))
545
+ if multi_subagent_feature is not None and multi_subagent_feature not in MULTI_SUBAGENT_FEATURE_CHOICES:
546
+ raise ValueError("--multi-subagent-feature must be one of: " + ", ".join(MULTI_SUBAGENT_FEATURE_CHOICES))
547
+ if multi_subagent_feature is not None and (orchestration_mode is not None or spawn_allowed is not None):
548
+ raise ValueError(
549
+ "--multi-subagent-feature cannot be combined with --orchestration-mode or --spawn-allowed; "
550
+ "use --max-children/--allowed-domain for bounded feature settings"
551
+ )
552
+ if explore_harness_profile is not None:
553
+ explore_harness_profile = str(explore_harness_profile).strip().lower().replace("_", "-")
554
+ if explore_harness_profile not in EXPLORE_HARNESS_PROFILES:
555
+ raise ValueError(
556
+ "--explore-harness-profile must be one of: "
557
+ + ", ".join(EXPLORE_HARNESS_PROFILES)
558
+ )
559
+
560
+ quota_compute = _non_negative_number(quota_compute, field="quota_compute")
561
+ quota_window_hours = _positive_number(quota_window_hours, field="quota_window_hours")
562
+ max_children = _non_negative_int(max_children, field="max_children")
563
+ allowed_domains = _clean_domains(allowed_domains)
564
+ if multi_subagent_feature == "off":
565
+ if max_children not in (None, 0):
566
+ raise ValueError("--multi-subagent-feature off cannot be combined with --max-children greater than 0")
567
+ if allowed_domains:
568
+ raise ValueError("--multi-subagent-feature off cannot be combined with --allowed-domain")
569
+ registered_agents = _clean_registered_agents(registered_agents)
570
+ if peer_task_coordinator is not None:
571
+ peer_task_coordinator = normalize_todo_claimed_by(peer_task_coordinator)
572
+ if not peer_task_coordinator:
573
+ raise ValueError(
574
+ "--peer-task-coordinator must be a public-safe registered agent id"
575
+ )
576
+ reward_memory_agents = _clean_registered_agents(reward_memory_agents)
577
+ clear_agent_profiles = _clean_registered_agents(clear_agent_profiles)
578
+ clear_agent_work_modes = _clean_registered_agents(clear_agent_work_modes)
579
+ clear_todo_lifecycle_authority = _clean_registered_agents(
580
+ clear_todo_lifecycle_authority
581
+ )
582
+ supervised_agents = _clean_registered_agents(supervised_agents)
583
+ write_scope = _clean_write_scope(write_scope)
584
+ issue_fix_reviewer_notification_config = _local_private_config_path(
585
+ issue_fix_reviewer_notification_config,
586
+ label="reviewer notification config",
587
+ )
588
+ lark_event_inbox_config = _local_private_config_path(
589
+ lark_event_inbox_config,
590
+ label="lark event inbox config",
591
+ )
592
+ reward_memory_config = _local_private_config_path(
593
+ reward_memory_config,
594
+ label="reward memory experiment config",
595
+ )
596
+
597
+ payload = read_json(registry_path)
598
+ goals = registry_goals(payload)
599
+ goal = next((item for item in goals if str(item.get("id")) == goal_id), None)
600
+ if goal is None:
601
+ raise ValueError(f"goal_id not found in registry: {goal_id}")
602
+
603
+ existing_coordination = (
604
+ goal.get("coordination")
605
+ if isinstance(goal.get("coordination"), dict)
606
+ else {}
607
+ )
608
+ effective_registered_agents = (
609
+ []
610
+ if clear_registered_agents
611
+ else registered_agents
612
+ if registered_agents is not None
613
+ else normalize_registered_agents(existing_coordination.get("registered_agents"))
614
+ )
615
+ if (
616
+ peer_task_coordinator is not None
617
+ and peer_task_coordinator not in effective_registered_agents
618
+ ):
619
+ raise ValueError(
620
+ "--peer-task-coordinator must name an agent already registered for "
621
+ f"this goal: {peer_task_coordinator}"
622
+ )
623
+ existing_reward_memory = reward_memory_goal_policy(goal)
624
+ effective_reward_memory_agents = (
625
+ reward_memory_agents
626
+ if reward_memory_agents is not None
627
+ else existing_reward_memory["enabled_agents"]
628
+ )
629
+ if reward_memory_config is not None or reward_memory_agents is not None:
630
+ effective_reward_memory_config = (
631
+ reward_memory_config or existing_reward_memory["config_path"]
632
+ )
633
+ if not effective_reward_memory_config:
634
+ raise ValueError(
635
+ "--reward-memory-agent requires an existing or supplied "
636
+ "--reward-memory-config"
637
+ )
638
+ if not effective_reward_memory_agents:
639
+ raise ValueError(
640
+ "enabling Reward Memory requires at least one "
641
+ "--reward-memory-agent"
642
+ )
643
+ unknown_reward_memory_agents = sorted(
644
+ set(effective_reward_memory_agents) - set(effective_registered_agents)
645
+ )
646
+ reward_memory_remains_enabled = (
647
+ not clear_reward_memory_config
648
+ and (
649
+ existing_reward_memory["enabled"]
650
+ or reward_memory_config is not None
651
+ or reward_memory_agents is not None
652
+ )
653
+ )
654
+ if reward_memory_remains_enabled and unknown_reward_memory_agents:
655
+ raise ValueError(
656
+ "Reward Memory agents must already be registered for this goal: "
657
+ + ", ".join(unknown_reward_memory_agents)
658
+ )
659
+ normalized_agent_profiles: dict[str, dict[str, Any]] = {}
660
+ for raw_profile in agent_profiles or []:
661
+ if not isinstance(raw_profile, Mapping):
662
+ raise ValueError("--agent-profile-json must contain a JSON object")
663
+ profile = normalize_agent_profile(
664
+ raw_profile,
665
+ registered_agents=effective_registered_agents,
666
+ )
667
+ profile_agent_id = str(profile["agent_id"])
668
+ if profile_agent_id in normalized_agent_profiles:
669
+ raise ValueError(f"duplicate agent profile for {profile_agent_id}")
670
+ normalized_agent_profiles[profile_agent_id] = profile
671
+ profile_conflicts = sorted(
672
+ set(normalized_agent_profiles) & set(clear_agent_profiles or [])
673
+ )
674
+ if profile_conflicts:
675
+ raise ValueError(
676
+ "cannot write and clear the same agent profile: "
677
+ + ", ".join(profile_conflicts)
678
+ )
679
+ normalized_agent_work_modes = normalize_agent_work_modes(
680
+ agent_work_modes,
681
+ registered_agents=effective_registered_agents,
682
+ )
683
+ work_mode_conflicts = sorted(
684
+ set(normalized_agent_work_modes) & set(clear_agent_work_modes or [])
685
+ )
686
+ if work_mode_conflicts:
687
+ raise ValueError(
688
+ "cannot write and clear the same agent work mode: "
689
+ + ", ".join(work_mode_conflicts)
690
+ )
691
+ normalized_todo_lifecycle_authority = normalize_todo_lifecycle_authority(
692
+ todo_lifecycle_authority,
693
+ registered_agents=effective_registered_agents,
694
+ )
695
+ authority_conflicts = sorted(
696
+ {entry["agent_id"] for entry in normalized_todo_lifecycle_authority}
697
+ & set(clear_todo_lifecycle_authority or [])
698
+ )
699
+ if authority_conflicts:
700
+ raise ValueError(
701
+ "cannot write and clear the same todo lifecycle authority grant: "
702
+ + ", ".join(authority_conflicts)
703
+ )
704
+
705
+ before_goal = deepcopy(goal)
706
+ before = _settings_summary(before_goal)
707
+ if execution_turn_granularity is not None:
708
+ goal["execution_profile"] = execution_profile_with_turn_granularity(
709
+ goal.get("execution_profile"),
710
+ execution_turn_granularity,
711
+ )
712
+ legacy_hierarchy_before = legacy_agent_hierarchy_present(before_goal)
713
+ expected_migration_id = peer_agent_runtime_migration_id(goal_id, before_goal)
714
+ completed_migration_before = completed_peer_agent_runtime_migration(before_goal)
715
+ migration_completed_before = peer_agent_runtime_migration_completed(before_goal)
716
+ migration_already_completed = bool(
717
+ completed_migration_before
718
+ and completed_migration_before.get("migration_id")
719
+ == automation_prompt_migration_ack
720
+ and migration_completed_before
721
+ )
722
+ if automation_prompt_migration_ack is not None:
723
+ if migration_already_completed:
724
+ pass
725
+ elif not legacy_hierarchy_before:
726
+ raise ValueError(
727
+ "no pending peer runtime automation migration matches this goal"
728
+ )
729
+ elif automation_prompt_migration_ack != expected_migration_id:
730
+ raise ValueError(
731
+ "automation prompt migration id does not match the current goal state; "
732
+ f"expected {expected_migration_id}"
733
+ )
734
+ elif execute and legacy_hierarchy_before and not migration_completed_before and (
735
+ agent_model is not None
736
+ or registered_agents is not None
737
+ or peer_task_coordinator is not None
738
+ or clear_peer_task_coordinator
739
+ or clear_registered_agents
740
+ ):
741
+ raise ValueError(
742
+ "legacy agent hierarchy requires the one-time host automation migration first; "
743
+ "regenerate/update the installed peer heartbeat, then run "
744
+ f"`loopx configure-goal --goal-id {goal_id} "
745
+ f"--ack-automation-prompt-migration {expected_migration_id} --execute`"
746
+ )
747
+
748
+ if quota_compute is not None or quota_window_hours is not None:
749
+ quota = goal.get("quota") if isinstance(goal.get("quota"), dict) else {}
750
+ if quota_compute is not None:
751
+ quota["compute"] = quota_compute
752
+ if quota_window_hours is not None:
753
+ quota["window_hours"] = quota_window_hours
754
+ goal["quota"] = quota
755
+
756
+ if (
757
+ self_repair_enabled is not None
758
+ or self_repair_health is not None
759
+ or self_repair_waiting_projection is not None
760
+ ):
761
+ control_plane = _mutable_control_plane(goal)
762
+ self_repair = control_plane.get("self_repair") if isinstance(control_plane.get("self_repair"), dict) else {}
763
+ if self_repair_enabled is not None:
764
+ self_repair["enabled"] = self_repair_enabled
765
+ if self_repair_health is not None:
766
+ self_repair["allow_health_blocker_repair"] = self_repair_health
767
+ if self_repair_waiting_projection is not None:
768
+ self_repair["allow_waiting_projection_repair"] = self_repair_waiting_projection
769
+ control_plane["self_repair"] = self_repair
770
+
771
+ if (
772
+ change_quality_enabled is not None
773
+ or change_quality_safe_fix is not None
774
+ or change_quality_strict_receipt is not None
775
+ ):
776
+ control_plane = _mutable_control_plane(goal)
777
+ current = change_quality_goal_policy_summary(goal)
778
+ change_quality = {
779
+ "schema_version": CHANGE_QUALITY_POLICY_SCHEMA_VERSION,
780
+ "enabled": (
781
+ change_quality_enabled
782
+ if change_quality_enabled is not None
783
+ else current["enabled"]
784
+ ),
785
+ "safe_fix": (
786
+ change_quality_safe_fix
787
+ if change_quality_safe_fix is not None
788
+ else current["safe_fix"]
789
+ ),
790
+ "strict_receipt": (
791
+ change_quality_strict_receipt
792
+ if change_quality_strict_receipt is not None
793
+ else current["strict_receipt"]
794
+ ),
795
+ }
796
+ control_plane["change_quality_qualification"] = change_quality
797
+
798
+ if (
799
+ issue_fix_reviewer_notification_config is not None
800
+ or clear_issue_fix_reviewer_notification_config
801
+ ):
802
+ control_plane = _mutable_control_plane(goal)
803
+ issue_fix = (
804
+ control_plane.get("issue_fix")
805
+ if isinstance(control_plane.get("issue_fix"), dict)
806
+ else {}
807
+ )
808
+ if clear_issue_fix_reviewer_notification_config:
809
+ issue_fix.pop("reviewer_notification", None)
810
+ else:
811
+ issue_fix["reviewer_notification"] = {
812
+ "enabled": True,
813
+ "config_path": issue_fix_reviewer_notification_config,
814
+ }
815
+ if issue_fix:
816
+ control_plane["issue_fix"] = issue_fix
817
+ else:
818
+ control_plane.pop("issue_fix", None)
819
+
820
+ if lark_event_inbox_config is not None or clear_lark_event_inbox_config:
821
+ control_plane = _mutable_control_plane(goal)
822
+ if clear_lark_event_inbox_config:
823
+ control_plane.pop("lark_event_inbox", None)
824
+ else:
825
+ control_plane["lark_event_inbox"] = {
826
+ "enabled": True,
827
+ "config_path": lark_event_inbox_config,
828
+ }
829
+
830
+ if lark_kanban_heartbeat_sync is not None:
831
+ control_plane = _mutable_control_plane(goal)
832
+ lark_kanban = (
833
+ control_plane.get("lark_kanban")
834
+ if isinstance(control_plane.get("lark_kanban"), dict)
835
+ else {}
836
+ )
837
+ lark_kanban["heartbeat_sync_enabled"] = lark_kanban_heartbeat_sync
838
+ control_plane["lark_kanban"] = lark_kanban
839
+
840
+ if (
841
+ reward_memory_config is not None
842
+ or reward_memory_agents is not None
843
+ or clear_reward_memory_config
844
+ ):
845
+ control_plane = _mutable_control_plane(goal)
846
+ if clear_reward_memory_config:
847
+ control_plane.pop("reward_memory", None)
848
+ else:
849
+ current_reward_memory = reward_memory_goal_policy(goal)
850
+ control_plane["reward_memory"] = {
851
+ "enabled": True,
852
+ "experimental": True,
853
+ "config_path": (
854
+ reward_memory_config or current_reward_memory["config_path"]
855
+ ),
856
+ "enabled_agents": list(effective_reward_memory_agents),
857
+ }
858
+
859
+ if explore_graph_enabled is not None:
860
+ goal["explore_graph"] = {"enabled": explore_graph_enabled}
861
+
862
+ if (
863
+ multi_subagent_feature is not None
864
+ or
865
+ orchestration_mode is not None
866
+ or spawn_allowed is not None
867
+ or max_children is not None
868
+ or allowed_domains is not None
869
+ or clear_allowed_domains
870
+ or explore_harness_enabled is not None
871
+ or explore_harness_profile is not None
872
+ or clear_explore_harness_profile
873
+ ):
874
+ spawn_policy = goal.get("spawn_policy") if isinstance(goal.get("spawn_policy"), dict) else {}
875
+ if multi_subagent_feature == "enabled":
876
+ spawn_policy["mode"] = MULTI_SUBAGENT_ORCHESTRATION_MODE
877
+ spawn_policy["allowed"] = True
878
+ if max_children is None:
879
+ existing_children = int(compact_orchestration_policy(spawn_policy).get("max_children") or 0)
880
+ spawn_policy["max_children"] = (
881
+ existing_children
882
+ if existing_children > 0
883
+ else DEFAULT_MULTI_SUBAGENT_MAX_CHILDREN
884
+ )
885
+ elif multi_subagent_feature == "off":
886
+ spawn_policy["mode"] = DEFAULT_ORCHESTRATION_MODE
887
+ spawn_policy["allowed"] = False
888
+ spawn_policy["max_children"] = 0
889
+ spawn_policy["allowed_domains"] = []
890
+ elif orchestration_mode is not None:
891
+ spawn_policy["mode"] = orchestration_mode
892
+ if spawn_allowed is not None:
893
+ spawn_policy["allowed"] = spawn_allowed
894
+ if max_children is not None:
895
+ spawn_policy["max_children"] = max_children
896
+ if clear_allowed_domains:
897
+ spawn_policy["allowed_domains"] = []
898
+ elif allowed_domains is not None:
899
+ spawn_policy["allowed_domains"] = allowed_domains
900
+ if (
901
+ explore_harness_enabled is not None
902
+ or explore_harness_profile is not None
903
+ or clear_explore_harness_profile
904
+ ):
905
+ explore_harness = (
906
+ spawn_policy.get("explore_harness")
907
+ if isinstance(spawn_policy.get("explore_harness"), dict)
908
+ else {}
909
+ )
910
+ if explore_harness_enabled is not None:
911
+ explore_harness["enabled"] = explore_harness_enabled
912
+ if clear_explore_harness_profile:
913
+ explore_harness.pop("profile", None)
914
+ elif explore_harness_profile is not None:
915
+ explore_harness["profile"] = explore_harness_profile
916
+ if explore_harness:
917
+ spawn_policy["explore_harness"] = explore_harness
918
+ else:
919
+ spawn_policy.pop("explore_harness", None)
920
+ goal["spawn_policy"] = spawn_policy
921
+
922
+ if waiting_on is not None:
923
+ goal["waiting_on"] = waiting_on
924
+ elif clear_waiting_on:
925
+ goal.pop("waiting_on", None)
926
+
927
+ if (
928
+ clear_registered_agents
929
+ or registered_agents is not None
930
+ or peer_task_coordinator is not None
931
+ or clear_peer_task_coordinator
932
+ or normalized_agent_profiles
933
+ or clear_agent_profiles
934
+ or normalized_agent_work_modes
935
+ or clear_agent_work_modes
936
+ or normalized_todo_lifecycle_authority
937
+ or clear_todo_lifecycle_authority
938
+ or agent_model is not None
939
+ or automation_prompt_migration_ack is not None
940
+ or supervisor_agent is not None
941
+ or supervised_agents is not None
942
+ or clear_supervisor
943
+ or write_scope is not None
944
+ or clear_write_scope
945
+ or clear_boundary_authority
946
+ or adding_boundary_authority
947
+ ):
948
+ coordination = goal.get("coordination") if isinstance(goal.get("coordination"), dict) else {}
949
+ effective_agent_model = AgentRuntimeModel.PEER_V1.value
950
+ if clear_registered_agents:
951
+ coordination.pop("registered_agents", None)
952
+ coordination.pop("agent_model", None)
953
+ coordination.pop("agent_profiles", None)
954
+ coordination.pop("agent_work_modes", None)
955
+ coordination.pop("supervisor", None)
956
+ coordination.pop("todo_lifecycle_authority", None)
957
+ coordination.pop("peer_task_coordination", None)
958
+ elif registered_agents is not None:
959
+ coordination["registered_agents"] = registered_agents
960
+ current_peer_task_coordination = (
961
+ coordination.get("peer_task_coordination")
962
+ if isinstance(coordination.get("peer_task_coordination"), dict)
963
+ else {}
964
+ )
965
+ current_peer_coordinator = normalize_todo_claimed_by(
966
+ current_peer_task_coordination.get("coordinator_agent_id")
967
+ )
968
+ if (
969
+ current_peer_coordinator
970
+ and current_peer_coordinator not in registered_agents
971
+ ):
972
+ coordination.pop("peer_task_coordination", None)
973
+ existing_profiles = (
974
+ coordination.get("agent_profiles")
975
+ if isinstance(coordination.get("agent_profiles"), dict)
976
+ else {}
977
+ )
978
+ retained_profiles = {
979
+ agent: profile
980
+ for agent, profile in existing_profiles.items()
981
+ if agent in registered_agents
982
+ }
983
+ if retained_profiles:
984
+ coordination["agent_profiles"] = retained_profiles
985
+ else:
986
+ coordination.pop("agent_profiles", None)
987
+ raw_work_modes = (
988
+ coordination.get("agent_work_modes")
989
+ if isinstance(coordination.get("agent_work_modes"), Mapping)
990
+ else {}
991
+ )
992
+ retained_work_modes = normalize_agent_work_modes(
993
+ {
994
+ agent: mode
995
+ for agent, mode in raw_work_modes.items()
996
+ if agent in registered_agents
997
+ },
998
+ registered_agents=registered_agents,
999
+ )
1000
+ if retained_work_modes:
1001
+ coordination["agent_work_modes"] = retained_work_modes
1002
+ else:
1003
+ coordination.pop("agent_work_modes", None)
1004
+ retained_authority = [
1005
+ entry
1006
+ for entry in coordination.get("todo_lifecycle_authority") or []
1007
+ if isinstance(entry, Mapping)
1008
+ and normalize_todo_claimed_by(entry.get("agent_id"))
1009
+ in registered_agents
1010
+ ]
1011
+ if retained_authority:
1012
+ coordination["todo_lifecycle_authority"] = (
1013
+ normalize_todo_lifecycle_authority(
1014
+ retained_authority,
1015
+ registered_agents=registered_agents,
1016
+ )
1017
+ )
1018
+ else:
1019
+ coordination.pop("todo_lifecycle_authority", None)
1020
+ if not clear_registered_agents:
1021
+ coordination["agent_model"] = effective_agent_model
1022
+ if not clear_registered_agents:
1023
+ if clear_peer_task_coordinator:
1024
+ coordination.pop("peer_task_coordination", None)
1025
+ elif peer_task_coordinator is not None:
1026
+ coordination["peer_task_coordination"] = {
1027
+ "coordinator_agent_id": peer_task_coordinator,
1028
+ }
1029
+ if not clear_registered_agents and (
1030
+ normalized_agent_profiles or clear_agent_profiles
1031
+ ):
1032
+ profiles = (
1033
+ dict(coordination.get("agent_profiles"))
1034
+ if isinstance(coordination.get("agent_profiles"), dict)
1035
+ else {}
1036
+ )
1037
+ for profile_agent_id in clear_agent_profiles or []:
1038
+ profiles.pop(profile_agent_id, None)
1039
+ profiles.update(normalized_agent_profiles)
1040
+ if profiles:
1041
+ coordination["agent_profiles"] = profiles
1042
+ else:
1043
+ coordination.pop("agent_profiles", None)
1044
+ if not clear_registered_agents and (
1045
+ normalized_agent_work_modes or clear_agent_work_modes
1046
+ ):
1047
+ work_modes = normalize_agent_work_modes(
1048
+ coordination.get("agent_work_modes"),
1049
+ registered_agents=normalize_registered_agents(
1050
+ coordination.get("registered_agents")
1051
+ ),
1052
+ )
1053
+ for work_mode_agent_id in clear_agent_work_modes or []:
1054
+ work_modes.pop(work_mode_agent_id, None)
1055
+ work_modes.update(normalized_agent_work_modes)
1056
+ if work_modes:
1057
+ coordination["agent_work_modes"] = dict(sorted(work_modes.items()))
1058
+ else:
1059
+ coordination.pop("agent_work_modes", None)
1060
+ if not clear_registered_agents and (
1061
+ normalized_todo_lifecycle_authority
1062
+ or clear_todo_lifecycle_authority
1063
+ ):
1064
+ current_authority = normalize_todo_lifecycle_authority(
1065
+ coordination.get("todo_lifecycle_authority"),
1066
+ registered_agents=normalize_registered_agents(
1067
+ coordination.get("registered_agents")
1068
+ ),
1069
+ )
1070
+ authority_by_agent = {
1071
+ entry["agent_id"]: entry for entry in current_authority
1072
+ }
1073
+ for authority_agent_id in clear_todo_lifecycle_authority or []:
1074
+ authority_by_agent.pop(authority_agent_id, None)
1075
+ authority_by_agent.update(
1076
+ {
1077
+ entry["agent_id"]: entry
1078
+ for entry in normalized_todo_lifecycle_authority
1079
+ }
1080
+ )
1081
+ if authority_by_agent:
1082
+ coordination["todo_lifecycle_authority"] = list(
1083
+ authority_by_agent.values()
1084
+ )
1085
+ else:
1086
+ coordination.pop("todo_lifecycle_authority", None)
1087
+ if automation_prompt_migration_ack is not None and not migration_already_completed:
1088
+ coordination = migrate_coordination_to_peer_v1(
1089
+ coordination,
1090
+ migration_id=automation_prompt_migration_ack,
1091
+ completed_at=_now_iso() if execute else None,
1092
+ )
1093
+ if clear_supervisor:
1094
+ coordination.pop("supervisor", None)
1095
+ elif supervisor_agent is not None:
1096
+ normalized_supervisor_agent = normalize_todo_claimed_by(supervisor_agent)
1097
+ if not normalized_supervisor_agent:
1098
+ raise ValueError("--supervisor-agent must be a registered agent id")
1099
+ coordination["supervisor"] = normalize_peer_supervisor(
1100
+ {
1101
+ "agent_id": normalized_supervisor_agent,
1102
+ "supervised_agents": supervised_agents,
1103
+ },
1104
+ registered_agents=normalize_registered_agents(
1105
+ coordination.get("registered_agents")
1106
+ ),
1107
+ )
1108
+ if clear_write_scope:
1109
+ coordination["write_scope"] = []
1110
+ elif write_scope is not None:
1111
+ if replace_write_scope:
1112
+ coordination["write_scope"] = write_scope
1113
+ else:
1114
+ existing_write_scope = _clean_write_scope(coordination.get("write_scope") or []) or []
1115
+ coordination["write_scope"] = _clean_write_scope([*existing_write_scope, *write_scope]) or []
1116
+ if clear_boundary_authority:
1117
+ coordination.pop("checkpointed_boundary_authority", None)
1118
+ if adding_boundary_authority:
1119
+ entry = build_checkpointed_boundary_authority_entry(
1120
+ write_scopes=boundary_authority_scopes or [],
1121
+ source=boundary_authority_source or "",
1122
+ decision_id=boundary_authority_decision_id,
1123
+ recorded_at=boundary_authority_recorded_at,
1124
+ expires_at=boundary_authority_expires_at,
1125
+ )
1126
+ entries = (
1127
+ coordination.get("checkpointed_boundary_authority")
1128
+ if isinstance(coordination.get("checkpointed_boundary_authority"), list)
1129
+ else []
1130
+ )
1131
+ coordination["checkpointed_boundary_authority"] = [*entries, entry]
1132
+ goal["coordination"] = coordination
1133
+
1134
+ after = _settings_summary(goal)
1135
+ changed_fields = _changed_fields(before, after)
1136
+ dry_run = not execute
1137
+ model_changed = bool(
1138
+ before.get("legacy_hierarchy_present")
1139
+ or before.get("agent_model") != after.get("agent_model")
1140
+ or automation_prompt_migration_ack is not None
1141
+ )
1142
+ backup_path = None
1143
+
1144
+ if execute and changed_fields:
1145
+ payload["updated_at"] = _now_iso()
1146
+ if model_changed:
1147
+ stamp = datetime.now().astimezone().strftime("%Y%m%dT%H%M%S%z")
1148
+ backup_path = registry_path.with_name(
1149
+ f"{registry_path.name}.before-agent-model-{stamp}.bak"
1150
+ )
1151
+ shutil.copy2(registry_path, backup_path)
1152
+ atomic_write_json(registry_path, payload)
1153
+
1154
+ feature_summary = {
1155
+ "multi_subagent": _multi_subagent_feature_status(after.get("orchestration") or {}),
1156
+ "explore_graph": deepcopy(after.get("explore_graph") or {"enabled": False}),
1157
+ "explore_harness": deepcopy(
1158
+ (after.get("orchestration") or {}).get("explore_harness")
1159
+ or {"enabled": False}
1160
+ ),
1161
+ "peer_supervisor": deepcopy(after.get("supervisor") or {"enabled": False}),
1162
+ "peer_task_coordination": deepcopy(
1163
+ after.get("peer_task_coordination") or {"enabled": False}
1164
+ ),
1165
+ "lark_event_inbox": _lark_event_inbox_config_summary(goal),
1166
+ "lark_kanban_heartbeat_sync": _lark_kanban_heartbeat_config_summary(goal),
1167
+ "reward_memory": reward_memory_goal_policy_summary(goal),
1168
+ "change_quality_qualification": change_quality_goal_policy_summary(goal),
1169
+ "default": "off",
1170
+ "configuration_entry": "multi_subagent_feature",
1171
+ }
1172
+
1173
+ return {
1174
+ "ok": True,
1175
+ "dry_run": dry_run,
1176
+ "execute": execute,
1177
+ "registry": str(registry_path),
1178
+ "goal_id": goal_id,
1179
+ "changed": bool(changed_fields),
1180
+ "changed_fields": changed_fields,
1181
+ "backup_path": str(backup_path) if backup_path else None,
1182
+ "before": before,
1183
+ "after": after,
1184
+ "written": bool(execute and changed_fields),
1185
+ "automation_prompt_migration": {
1186
+ "migration_id": automation_prompt_migration_ack,
1187
+ "status": (
1188
+ "already_completed"
1189
+ if migration_already_completed
1190
+ else "completed"
1191
+ if automation_prompt_migration_ack is not None
1192
+ else "pending"
1193
+ if legacy_hierarchy_before
1194
+ else "not_required"
1195
+ ),
1196
+ "exactly_once_effect": True,
1197
+ },
1198
+ "control_plane_summary": control_plane_policy_summary(after.get("control_plane")),
1199
+ "orchestration_summary": orchestration_policy_summary(after.get("orchestration")),
1200
+ "feature_summary": feature_summary,
1201
+ "configuration_catalog": build_goal_configuration_catalog(
1202
+ goal_id=goal_id,
1203
+ settings=after,
1204
+ feature_summary=feature_summary,
1205
+ default_multi_subagent_max_children=DEFAULT_MULTI_SUBAGENT_MAX_CHILDREN,
1206
+ explore_harness_profiles=EXPLORE_HARNESS_PROFILES,
1207
+ ),
1208
+ "heartbeat_prompt_migration": _build_heartbeat_prompt_migration(
1209
+ goal_id=goal_id,
1210
+ changed_fields=changed_fields,
1211
+ after=after,
1212
+ migration_id=(
1213
+ automation_prompt_migration_ack
1214
+ if automation_prompt_migration_ack is not None
1215
+ else expected_migration_id
1216
+ if legacy_hierarchy_before and not migration_completed_before
1217
+ else None
1218
+ ),
1219
+ migration_acknowledged=automation_prompt_migration_ack is not None,
1220
+ ),
1221
+ "supervisor_prompt": _build_supervisor_prompt_setup(
1222
+ goal_id=goal_id,
1223
+ changed_fields=changed_fields,
1224
+ after=after,
1225
+ ),
1226
+ }
1227
+
1228
+
1229
+ def render_configure_goal_markdown(payload: dict[str, Any]) -> str:
1230
+ lines = [
1231
+ "# LoopX Goal Configuration",
1232
+ "",
1233
+ f"- ok: `{payload.get('ok')}`",
1234
+ f"- dry_run: `{payload.get('dry_run')}`",
1235
+ f"- registry: `{payload.get('registry')}`",
1236
+ f"- goal_id: `{payload.get('goal_id')}`",
1237
+ f"- changed: `{payload.get('changed')}`",
1238
+ f"- written: `{payload.get('written')}`",
1239
+ ]
1240
+ if payload.get("error"):
1241
+ lines.append(f"- error: {payload.get('error')}")
1242
+ return "\n".join(lines)
1243
+ fields = payload.get("changed_fields") or []
1244
+ lines.append(f"- changed_fields: `{', '.join(fields) if fields else 'none'}`")
1245
+ global_sync = payload.get("global_sync")
1246
+ if isinstance(global_sync, dict):
1247
+ selected_target = (
1248
+ global_sync.get("selected_target")
1249
+ if isinstance(global_sync.get("selected_target"), dict)
1250
+ else {}
1251
+ )
1252
+ readback = (
1253
+ global_sync.get("readback")
1254
+ if isinstance(global_sync.get("readback"), dict)
1255
+ else {}
1256
+ )
1257
+ lines.extend(
1258
+ [
1259
+ f"- global_sync_enabled: `{global_sync.get('enabled')}`",
1260
+ f"- global_sync_executed: `{global_sync.get('executed')}`",
1261
+ f"- global_sync_target: `{selected_target.get('global_registry')}`",
1262
+ f"- global_sync_readback: `{readback.get('status')}`",
1263
+ ]
1264
+ )
1265
+ if payload.get("control_plane_summary"):
1266
+ lines.append(f"- control_plane: {payload.get('control_plane_summary')}")
1267
+ if payload.get("orchestration_summary"):
1268
+ lines.append(f"- orchestration: {payload.get('orchestration_summary')}")
1269
+ feature_summary = payload.get("feature_summary")
1270
+ if isinstance(feature_summary, dict):
1271
+ lines.append(f"- feature_multi_subagent: `{feature_summary.get('multi_subagent')}`")
1272
+ graph = feature_summary.get("explore_graph")
1273
+ if isinstance(graph, dict):
1274
+ lines.append(
1275
+ f"- feature_explore_graph: `{'on' if graph.get('enabled') else 'off'}`"
1276
+ )
1277
+ harness = feature_summary.get("explore_harness")
1278
+ if isinstance(harness, dict):
1279
+ harness_state = "on" if harness.get("enabled") else "off"
1280
+ if harness.get("profile"):
1281
+ harness_state += f"({harness.get('profile')})"
1282
+ lines.append(f"- feature_explore_harness: `{harness_state}`")
1283
+ supervisor = feature_summary.get("peer_supervisor")
1284
+ if isinstance(supervisor, dict):
1285
+ supervisor_state = "on" if supervisor.get("enabled") else "off"
1286
+ if supervisor.get("agent_id"):
1287
+ supervisor_state += f"({supervisor.get('agent_id')})"
1288
+ lines.append(f"- feature_peer_supervisor: `{supervisor_state}`")
1289
+ catalog = payload.get("configuration_catalog")
1290
+ if isinstance(catalog, dict):
1291
+ disclosure = catalog.get("disclosure_policy") or {}
1292
+ lines.extend(
1293
+ [
1294
+ "",
1295
+ "## Optional Features (On Demand)",
1296
+ "",
1297
+ "First run requires no optional feature configuration.",
1298
+ "",
1299
+ f"- inspect: `{disclosure.get('inspect_command')}`",
1300
+ f"- all_settings_help: `{catalog.get('all_settings_help_command')}`",
1301
+ "- apply_policy: preview first; add `--execute` only after review",
1302
+ ]
1303
+ )
1304
+ for feature in catalog.get("features") or []:
1305
+ if not isinstance(feature, dict):
1306
+ continue
1307
+ current = feature.get("current") or {}
1308
+ state = "on" if current.get("enabled") else "off"
1309
+ commands = feature.get("commands") or {}
1310
+ verify_commands = commands.get("verify") or []
1311
+ documentation = feature.get("documentation") or {}
1312
+ lines.extend(
1313
+ [
1314
+ f"- `{feature.get('feature_id')}` ({feature.get('display_name')}): `{state}`",
1315
+ f" - consider: {feature.get('consider_when')}",
1316
+ f" - preview: `{commands.get('preview_enable')}`",
1317
+ f" - apply: `{commands.get('apply_enable')}`",
1318
+ f" - preview_disable: `{commands.get('preview_disable')}`",
1319
+ f" - apply_disable: `{commands.get('apply_disable')}`",
1320
+ f" - verify: {'; '.join(f'`{command}`' for command in verify_commands)}",
1321
+ f" - docs: [{documentation.get('path')}]({documentation.get('url')})",
1322
+ ]
1323
+ )
1324
+ migration = payload.get("heartbeat_prompt_migration")
1325
+ if isinstance(migration, dict):
1326
+ lines.append(f"- heartbeat_prompt_migration: {migration.get('action')}")
1327
+ for command in migration.get("commands") or []:
1328
+ if not isinstance(command, dict):
1329
+ continue
1330
+ lines.append(
1331
+ f" - {command.get('agent_id')}: `{command.get('command')}`"
1332
+ )
1333
+ supervisor_prompt = payload.get("supervisor_prompt")
1334
+ if isinstance(supervisor_prompt, dict):
1335
+ lines.append(f"- supervisor_prompt_status: `{supervisor_prompt.get('status')}`")
1336
+ if supervisor_prompt.get("command"):
1337
+ lines.append(f"- supervisor_prompt: `{supervisor_prompt.get('command')}`")
1338
+ activation = payload.get("host_loop_activation")
1339
+ if isinstance(activation, dict):
1340
+ lines.append(
1341
+ f"- host_loop_activation: `{activation.get('host_surface')}` "
1342
+ f"status=`{activation.get('status')}` "
1343
+ f"activated=`{activation.get('activated')}`"
1344
+ )
1345
+ if activation.get("activated") is not True:
1346
+ lines.append(f"- host_loop_action: {activation.get('recommended_action')}")
1347
+ if payload.get("changed"):
1348
+ lines.extend(
1349
+ [
1350
+ "",
1351
+ "## Before",
1352
+ "",
1353
+ "```json",
1354
+ json.dumps(payload.get("before") or {}, ensure_ascii=False, indent=2),
1355
+ "```",
1356
+ "",
1357
+ "## After",
1358
+ "",
1359
+ "```json",
1360
+ json.dumps(payload.get("after") or {}, ensure_ascii=False, indent=2),
1361
+ "```",
1362
+ ]
1363
+ )
1364
+ else:
1365
+ lines.extend(
1366
+ [
1367
+ "",
1368
+ "## Current Settings",
1369
+ "",
1370
+ "```json",
1371
+ json.dumps(payload.get("after") or {}, ensure_ascii=False, indent=2),
1372
+ "```",
1373
+ ]
1374
+ )
1375
+ return "\n".join(lines)