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
loopx/bootstrap.py ADDED
@@ -0,0 +1,1116 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ import shlex
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from .control_plane.runtime.time import now_local_iso
10
+ from .control_plane.todos.active_state_editing import (
11
+ TODO_SECTION_HEADINGS,
12
+ insertion_anchor,
13
+ section_bounds,
14
+ )
15
+ from .execution_profile import (
16
+ build_execution_profile,
17
+ compact_execution_profile,
18
+ execution_profile_summary,
19
+ )
20
+ from .global_registry import sync_project_registry_to_global
21
+ from .install_contract import NO_CLONE_INSTALL_URL
22
+ from .onboarding import build_onboarding_scan
23
+ from .orchestration import (
24
+ DEFAULT_ORCHESTRATION_MODE,
25
+ MULTI_SUBAGENT_ORCHESTRATION_MODE,
26
+ )
27
+ from .paths import DEFAULT_RUNTIME_ROOT, rel_or_abs
28
+ from .registry_writability import probe_registry_write_path
29
+ from .todos import add_todo_to_lines
30
+
31
+
32
+ DEFAULT_OBJECTIVE = "Improve this project through bounded, verified goal segments."
33
+ DEFAULT_DOMAIN = "project-goal-control-plane"
34
+ GENERIC_ONBOARDING_ADAPTER_KINDS = frozenset(
35
+ {"generic_project_goal_v0", "read_only_project_map_v0"}
36
+ )
37
+ NO_CLONE_INSTALL_REPAIR_COMMAND = (
38
+ f"curl -fsSL {NO_CLONE_INSTALL_URL} | bash\n"
39
+ 'export PATH="$HOME/.local/bin:$PATH"\n'
40
+ "loopx doctor"
41
+ )
42
+ HEARTBEAT_OPT_IN_STATUS_REQUIRED = (
43
+ "requires explicit heartbeat=yes/no before a recurring Codex App automation is installed"
44
+ )
45
+ HEARTBEAT_OPT_IN_STATUS_PREAUTHORIZED = (
46
+ "explicitly preauthorized; create or update the host loop before claiming recurring automation is active"
47
+ )
48
+ HEARTBEAT_OPT_IN_STATUS_DECLINED = (
49
+ "explicitly declined; keep the goal manual or on-demand unless the user later opts in"
50
+ )
51
+ HEARTBEAT_OPT_IN_INSTRUCTION = (
52
+ "Ask the user whether to enable the Codex App heartbeat. heartbeat=yes means create or update a recurring "
53
+ "Codex App automation from an identity-scoped `loopx heartbeat-prompt --thin` task body; heartbeat=no means "
54
+ "keep the goal manual or on-demand."
55
+ )
56
+ HEARTBEAT_OPT_IN_PREAUTHORIZED_INSTRUCTION = (
57
+ "The user preauthorized the Codex App heartbeat. Create or update the recurring automation from an "
58
+ "identity-scoped `loopx heartbeat-prompt --thin` task body before claiming recurring automation is active."
59
+ )
60
+ HEARTBEAT_OPT_IN_DECLINED_INSTRUCTION = (
61
+ "The user declined the Codex App heartbeat. Do not install recurring automation; keep the goal manual or "
62
+ "on-demand unless the user later opts in."
63
+ )
64
+ CODEX_APP_HEARTBEAT_CHOICES = {"ask", "yes", "no"}
65
+
66
+
67
+ def slugify_goal_id(value: str) -> str:
68
+ slug = re.sub(r"[^a-zA-Z0-9]+", "-", value.lower()).strip("-")
69
+ return slug or "project-goal"
70
+
71
+
72
+ def default_goal_id(project: Path) -> str:
73
+ return f"{slugify_goal_id(project.name)}-goal"
74
+
75
+
76
+ def now_iso() -> str:
77
+ return now_local_iso()
78
+
79
+
80
+ def read_json_if_exists(path: Path) -> dict[str, Any]:
81
+ if not path.exists():
82
+ return {}
83
+ with path.open(encoding="utf-8") as f:
84
+ payload = json.load(f)
85
+ if not isinstance(payload, dict):
86
+ raise ValueError(f"{path} must contain a JSON object")
87
+ return payload
88
+
89
+
90
+ def write_json(path: Path, payload: dict[str, Any]) -> None:
91
+ path.parent.mkdir(parents=True, exist_ok=True)
92
+ path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
93
+
94
+
95
+ def resolve_project_path(project: Path, path: Path | None) -> Path | None:
96
+ if path is None:
97
+ return None
98
+ path = path.expanduser()
99
+ return path if path.is_absolute() else project / path
100
+
101
+
102
+ def render_authority_sources(project: Path, goal_doc: Path | None) -> str:
103
+ if not goal_doc:
104
+ return "- No explicit goal document was provided during bootstrap."
105
+ return f"- Primary goal document: `{rel_or_abs(goal_doc, project)}`"
106
+
107
+
108
+ def repair_missing_todo_source_sections(state_text: str) -> tuple[str, list[str]]:
109
+ """Add missing durable todo sources without replacing existing state content."""
110
+
111
+ lines = state_text.splitlines()
112
+ added_roles: list[str] = []
113
+ for role in ("user", "agent"):
114
+ if section_bounds(lines, role) is not None:
115
+ continue
116
+ anchor = insertion_anchor(lines, role)
117
+ section = [f"## {TODO_SECTION_HEADINGS[role]}", ""]
118
+ if anchor > 0 and lines[anchor - 1].strip():
119
+ section.insert(0, "")
120
+ lines[anchor:anchor] = section
121
+ added_roles.append(role)
122
+ if not added_roles:
123
+ return state_text, []
124
+ trailing_newline = "\n" if state_text.endswith("\n") else ""
125
+ return "\n".join(lines) + trailing_newline, added_roles
126
+
127
+
128
+ def onboarding_candidates(onboarding_scan: dict[str, Any] | None) -> list[dict[str, Any]]:
129
+ if not isinstance(onboarding_scan, dict):
130
+ return []
131
+ candidates = onboarding_scan.get("agent_todo_candidates")
132
+ if not isinstance(candidates, list):
133
+ return []
134
+ return [candidate for candidate in candidates if isinstance(candidate, dict)]
135
+
136
+
137
+ def normalize_codex_app_heartbeat(value: str | None) -> str:
138
+ choice = (value or "ask").strip().lower()
139
+ if choice not in CODEX_APP_HEARTBEAT_CHOICES:
140
+ raise ValueError("codex_app_heartbeat must be one of: ask, yes, no")
141
+ return choice
142
+
143
+
144
+ def heartbeat_opt_in_required(
145
+ *,
146
+ onboarding_scan: dict[str, Any] | None,
147
+ codex_app_heartbeat: str,
148
+ ) -> bool:
149
+ return bool(onboarding_scan and codex_app_heartbeat == "ask")
150
+
151
+
152
+ def host_loop_activation_required(
153
+ *,
154
+ onboarding_scan: dict[str, Any] | None,
155
+ codex_app_heartbeat: str,
156
+ ) -> bool:
157
+ return bool(onboarding_scan and codex_app_heartbeat in {"ask", "yes"})
158
+
159
+
160
+ def heartbeat_status(codex_app_heartbeat: str) -> str:
161
+ if codex_app_heartbeat == "yes":
162
+ return HEARTBEAT_OPT_IN_STATUS_PREAUTHORIZED
163
+ if codex_app_heartbeat == "no":
164
+ return HEARTBEAT_OPT_IN_STATUS_DECLINED
165
+ return HEARTBEAT_OPT_IN_STATUS_REQUIRED
166
+
167
+
168
+ def heartbeat_instruction(codex_app_heartbeat: str) -> str | None:
169
+ if codex_app_heartbeat == "yes":
170
+ return HEARTBEAT_OPT_IN_PREAUTHORIZED_INSTRUCTION
171
+ if codex_app_heartbeat == "no":
172
+ return HEARTBEAT_OPT_IN_DECLINED_INSTRUCTION
173
+ return HEARTBEAT_OPT_IN_INSTRUCTION
174
+
175
+
176
+ def render_onboarding_state_markdown(
177
+ *,
178
+ onboarding_scan: dict[str, Any] | None,
179
+ accept_onboarding_agent_todos: bool,
180
+ begin_autonomous_advance: bool,
181
+ codex_app_heartbeat: str,
182
+ ) -> str:
183
+ if not onboarding_scan:
184
+ return ""
185
+ scan_policy = onboarding_scan.get("scan_policy")
186
+ scan_policy = scan_policy if isinstance(scan_policy, dict) else {}
187
+ recent_commits = onboarding_scan.get("recent_commits")
188
+ recent_commits = recent_commits if isinstance(recent_commits, list) else []
189
+ signal_files = onboarding_scan.get("signal_files")
190
+ signal_files = signal_files if isinstance(signal_files, list) else []
191
+ validation_files = onboarding_scan.get("validation_signal_files")
192
+ validation_files = validation_files if isinstance(validation_files, list) else []
193
+ validation_paths = [
194
+ str(item.get("path"))
195
+ for item in validation_files
196
+ if isinstance(item, dict) and item.get("path")
197
+ ]
198
+ acceptance_status = (
199
+ "accepted and written into Agent Todo"
200
+ if accept_onboarding_agent_todos
201
+ else "requires user selection before delivery work"
202
+ )
203
+ autonomous_status = (
204
+ "allowed after accepted agent todos and a fresh quota guard"
205
+ if begin_autonomous_advance
206
+ else "requires an explicit user yes/no choice"
207
+ )
208
+ lines = [
209
+ "## Onboarding Control",
210
+ "",
211
+ "- Fast repository scan: `enabled`.",
212
+ f"- Scan read file bodies: `{bool(scan_policy.get('raw_file_bodies_read'))}`.",
213
+ f"- Git repo detected: `{bool(onboarding_scan.get('is_git_repo'))}`.",
214
+ f"- Local change count from `git status --short`: `{int(onboarding_scan.get('status_path_count') or 0)}`.",
215
+ f"- Recent commits sampled: `{len(recent_commits)}`.",
216
+ f"- Project signal files: `{', '.join(str(item) for item in signal_files) or 'none'}`.",
217
+ f"- Validation signal files: `{', '.join(validation_paths) or 'none'}`.",
218
+ f"- Candidate agent todos: `{acceptance_status}`.",
219
+ f"- Autonomous advancement: `{autonomous_status}`.",
220
+ f"- Codex App heartbeat: `{heartbeat_status(codex_app_heartbeat)}`.",
221
+ "",
222
+ "## Proposed Onboarding Candidates",
223
+ "",
224
+ ]
225
+ candidates = onboarding_candidates(onboarding_scan)
226
+ for index, candidate in enumerate(candidates, start=1):
227
+ text = str(candidate.get("text") or "").strip()
228
+ reason = str(candidate.get("reason") or "").strip()
229
+ action_kind = str(candidate.get("action_kind") or "analyze").strip()
230
+ task_class = str(candidate.get("task_class") or "advancement_task").strip()
231
+ lines.append(f"{index}. {text}")
232
+ if reason:
233
+ lines.append(f" - reason: {reason}")
234
+ lines.append(f" - metadata: `{task_class}:{action_kind}`")
235
+ if not candidates:
236
+ lines.append("No candidate agent todos were generated.")
237
+ return "\n".join(lines)
238
+
239
+
240
+ def onboarding_user_todo_text(
241
+ *,
242
+ acceptance_required: bool,
243
+ autonomous_choice_required: bool,
244
+ heartbeat_choice_required: bool,
245
+ ) -> str | None:
246
+ decisions: list[str] = []
247
+ reply_parts: list[str] = []
248
+ if acceptance_required:
249
+ decisions.append("which proposed onboarding agent todos to accept")
250
+ reply_parts.append("accepted numbers")
251
+ if autonomous_choice_required:
252
+ decisions.append("whether Codex may start autonomous advancement")
253
+ reply_parts.append("autonomous=yes/no")
254
+ if heartbeat_choice_required:
255
+ decisions.append("whether to enable the Codex App heartbeat")
256
+ reply_parts.append("heartbeat=yes/no")
257
+ if not decisions:
258
+ return None
259
+ verb = "Choose" if acceptance_required else "Decide"
260
+ return f"[P1] {verb} {' and '.join(decisions)}; reply with {' plus '.join(reply_parts)}."
261
+
262
+
263
+ def onboarding_agent_review_todo_text(
264
+ *,
265
+ acceptance_required: bool,
266
+ autonomous_choice_required: bool,
267
+ heartbeat_choice_required: bool,
268
+ ) -> str | None:
269
+ if not acceptance_required and not autonomous_choice_required and not heartbeat_choice_required:
270
+ return None
271
+ prompts: list[str] = []
272
+ if acceptance_required:
273
+ prompts.append("which candidate agent todos to accept")
274
+ if autonomous_choice_required:
275
+ prompts.append("whether autonomous advancement may start")
276
+ if heartbeat_choice_required:
277
+ prompts.append("whether to enable the Codex App heartbeat")
278
+ prefix = "Present the onboarding scan and ask " if acceptance_required else "Ask "
279
+ text = f"[P1] {prefix}{', '.join(prompts)} before delivery work."
280
+ if heartbeat_choice_required:
281
+ text += (
282
+ " If heartbeat=yes, create or update the Codex App heartbeat from an identity-scoped "
283
+ "`loopx heartbeat-prompt --thin` task body before claiming recurring automation is active."
284
+ )
285
+ return text
286
+
287
+
288
+ def onboarding_connection_validation_action(adapter_kind: str) -> dict[str, str] | None:
289
+ if adapter_kind not in GENERIC_ONBOARDING_ADAPTER_KINDS:
290
+ return None
291
+ return {
292
+ "text": (
293
+ "[P1] Run `loopx check` against the project registry and record the first "
294
+ "project-specific adapter signal or an explicit no-follow-up rationale."
295
+ ),
296
+ "task_class": "advancement_task",
297
+ "action_kind": "onboarding_connection_validation",
298
+ }
299
+
300
+
301
+ def onboarding_next_action(
302
+ *,
303
+ adapter_kind: str,
304
+ onboarding_scan: dict[str, Any] | None,
305
+ accept_onboarding_agent_todos: bool,
306
+ begin_autonomous_advance: bool,
307
+ codex_app_heartbeat: str,
308
+ ) -> str:
309
+ if not onboarding_scan:
310
+ validation_action = onboarding_connection_validation_action(adapter_kind)
311
+ if validation_action:
312
+ return validation_action["text"]
313
+ return "Initial routing is owned by the connected domain adapter."
314
+ need_heartbeat_choice = codex_app_heartbeat == "ask"
315
+ if not accept_onboarding_agent_todos or not begin_autonomous_advance or need_heartbeat_choice:
316
+ asks: list[str] = []
317
+ if not accept_onboarding_agent_todos:
318
+ asks.append("which proposed onboarding agent todos to accept")
319
+ if not begin_autonomous_advance:
320
+ asks.append("whether Codex may start autonomous advancement")
321
+ if need_heartbeat_choice:
322
+ asks.append("whether to enable the Codex App heartbeat")
323
+ follow_up = "then write accepted choices and refresh state before delivery work."
324
+ heartbeat_follow_up = ""
325
+ if need_heartbeat_choice:
326
+ heartbeat_follow_up = (
327
+ " If heartbeat=yes, create or update the recurring automation from an identity-scoped "
328
+ "`loopx heartbeat-prompt --thin` task body."
329
+ )
330
+ elif codex_app_heartbeat == "yes":
331
+ heartbeat_follow_up = (
332
+ " Create or update the preauthorized recurring automation from an identity-scoped "
333
+ "`loopx heartbeat-prompt --thin` task body."
334
+ )
335
+ autonomous_follow_up = (
336
+ " If autonomous=yes, run the quota guard and execute the first accepted onboarding agent todo."
337
+ if not begin_autonomous_advance
338
+ else " Run the quota guard and execute the first accepted onboarding agent todo once accepted choices permit."
339
+ )
340
+ return f"Ask the user {', '.join(asks)}, {follow_up}{heartbeat_follow_up}{autonomous_follow_up}"
341
+ if codex_app_heartbeat == "yes":
342
+ return (
343
+ "Create or update the Codex App heartbeat from an identity-scoped `loopx heartbeat-prompt --thin` task "
344
+ "body, run the quota guard, execute the first accepted onboarding Agent Todo as a bounded segment, write "
345
+ "evidence, complete or update the todo, and refresh state."
346
+ )
347
+ return (
348
+ "Run the quota guard, execute the first accepted onboarding Agent Todo as a bounded segment, write evidence, "
349
+ "complete or update the todo, and refresh state."
350
+ )
351
+
352
+
353
+ def apply_onboarding_todos_to_state(
354
+ text: str,
355
+ *,
356
+ adapter_kind: str,
357
+ updated_at: str,
358
+ onboarding_scan: dict[str, Any] | None,
359
+ accept_onboarding_agent_todos: bool,
360
+ begin_autonomous_advance: bool,
361
+ codex_app_heartbeat: str,
362
+ ) -> str:
363
+ if not onboarding_scan:
364
+ lines = text.splitlines()
365
+ action = onboarding_connection_validation_action(adapter_kind)
366
+ if action:
367
+ add_todo_to_lines(
368
+ lines,
369
+ role="agent",
370
+ text=action["text"],
371
+ task_class=action["task_class"],
372
+ action_kind=action["action_kind"],
373
+ updated_at=updated_at,
374
+ )
375
+ return "\n".join(lines) + "\n"
376
+ lines = text.splitlines()
377
+ if accept_onboarding_agent_todos:
378
+ for candidate in onboarding_candidates(onboarding_scan):
379
+ todo_text = str(candidate.get("text") or "").strip()
380
+ if not todo_text:
381
+ continue
382
+ add_todo_to_lines(
383
+ lines,
384
+ role="agent",
385
+ text=todo_text,
386
+ task_class=str(candidate.get("task_class") or "advancement_task"),
387
+ action_kind=str(candidate.get("action_kind") or "analyze"),
388
+ updated_at=updated_at,
389
+ )
390
+
391
+ acceptance_required = not accept_onboarding_agent_todos
392
+ autonomous_choice_required = not begin_autonomous_advance
393
+ heartbeat_choice_required = codex_app_heartbeat == "ask"
394
+ user_todo = onboarding_user_todo_text(
395
+ acceptance_required=acceptance_required,
396
+ autonomous_choice_required=autonomous_choice_required,
397
+ heartbeat_choice_required=heartbeat_choice_required,
398
+ )
399
+ if user_todo:
400
+ add_todo_to_lines(
401
+ lines,
402
+ role="user",
403
+ text=user_todo,
404
+ task_class="user_gate",
405
+ action_kind="onboarding_decision",
406
+ updated_at=updated_at,
407
+ )
408
+ agent_todo = onboarding_agent_review_todo_text(
409
+ acceptance_required=acceptance_required,
410
+ autonomous_choice_required=autonomous_choice_required,
411
+ heartbeat_choice_required=heartbeat_choice_required,
412
+ )
413
+ if agent_todo:
414
+ add_todo_to_lines(
415
+ lines,
416
+ role="agent",
417
+ text=agent_todo,
418
+ task_class="advancement_task",
419
+ action_kind="onboarding_todo_review",
420
+ updated_at=updated_at,
421
+ )
422
+ return "\n".join(lines) + "\n"
423
+
424
+
425
+ def render_state_markdown(
426
+ *,
427
+ project: Path,
428
+ goal_id: str,
429
+ adapter_kind: str,
430
+ objective: str,
431
+ updated_at: str,
432
+ goal_doc: Path | None,
433
+ execution_profile: dict[str, Any] | None,
434
+ onboarding_scan: dict[str, Any] | None = None,
435
+ accept_onboarding_agent_todos: bool = False,
436
+ begin_autonomous_advance: bool = False,
437
+ codex_app_heartbeat: str = "ask",
438
+ ) -> str:
439
+ safe_objective = objective.replace('"', '\\"')
440
+ profile_summary = execution_profile_summary(execution_profile)
441
+ onboarding_markdown = render_onboarding_state_markdown(
442
+ onboarding_scan=onboarding_scan,
443
+ accept_onboarding_agent_todos=accept_onboarding_agent_todos,
444
+ begin_autonomous_advance=begin_autonomous_advance,
445
+ codex_app_heartbeat=codex_app_heartbeat,
446
+ )
447
+ onboarding_block = f"\n{onboarding_markdown}\n" if onboarding_markdown else ""
448
+ next_action = onboarding_next_action(
449
+ adapter_kind=adapter_kind,
450
+ onboarding_scan=onboarding_scan,
451
+ accept_onboarding_agent_todos=accept_onboarding_agent_todos,
452
+ begin_autonomous_advance=begin_autonomous_advance,
453
+ codex_app_heartbeat=codex_app_heartbeat,
454
+ )
455
+ state_text = f"""---
456
+ status: active
457
+ owner_mode: goal
458
+ objective: "{safe_objective}"
459
+ updated_at: {updated_at}
460
+ adapter_id: {goal_id}
461
+ ---
462
+
463
+ # Active Goal State
464
+
465
+ ## Objective
466
+
467
+ {objective}
468
+
469
+ ## Authority Sources
470
+
471
+ {render_authority_sources(project, goal_doc)}
472
+
473
+ ## Operating Contract
474
+
475
+ - Treat this file as the durable goal state for future agent ticks.
476
+ - Treat the authority sources above as the first context to inspect before acting.
477
+ - Read current project evidence before choosing the next action.
478
+ - Run a bounded progress segment when useful; it does not have to be one tiny step.
479
+ - Keep private evidence, credentials, local paths, and raw logs out of public commits.
480
+ - End each tick with changed files, validation, residual risk, and the next action.
481
+
482
+ ## Execution Profile
483
+
484
+ - `{profile_summary}`
485
+ - Repeated small-scale follow-through should expand the next delivery batch or report a blocker before spending quota.
486
+
487
+ ## Non-Goals
488
+
489
+ - Do not perform irreversible production operations without explicit approval.
490
+ - Do not publish private project evidence.
491
+ - Do not optimize for activity if no useful artifact or decision can be produced.
492
+ {onboarding_block}
493
+
494
+ ## User Todo / Owner Review Reading Queue
495
+
496
+ ## Agent Todo
497
+
498
+ ## Next Action
499
+
500
+ - {next_action}
501
+
502
+ ## Recent User Feedback
503
+
504
+ - Initialized by `loopx bootstrap`.
505
+
506
+ ## Progress Ledger
507
+
508
+ - Created the initial goal state and registry connection.
509
+ """
510
+ return apply_onboarding_todos_to_state(
511
+ state_text,
512
+ adapter_kind=adapter_kind,
513
+ updated_at=updated_at,
514
+ onboarding_scan=onboarding_scan,
515
+ accept_onboarding_agent_todos=accept_onboarding_agent_todos,
516
+ begin_autonomous_advance=begin_autonomous_advance,
517
+ codex_app_heartbeat=codex_app_heartbeat,
518
+ )
519
+
520
+
521
+ def relative_state_file(project: Path, state_file: Path) -> str:
522
+ return rel_or_abs(state_file, project)
523
+
524
+
525
+ def todo_add_command(
526
+ *,
527
+ project: Path,
528
+ registry_path: Path,
529
+ goal_id: str,
530
+ candidate: dict[str, Any],
531
+ ) -> str:
532
+ return (
533
+ f"loopx --registry {shlex.quote(relative_state_file(project, registry_path))} todo add "
534
+ f"--goal-id {shlex.quote(goal_id)} "
535
+ "--role agent "
536
+ f"--text {shlex.quote(str(candidate.get('text') or ''))} "
537
+ f"--task-class {shlex.quote(str(candidate.get('task_class') or 'advancement_task'))} "
538
+ f"--action-kind {shlex.quote(str(candidate.get('action_kind') or 'analyze'))}"
539
+ )
540
+
541
+
542
+ def build_goal_entry(
543
+ *,
544
+ project: Path,
545
+ goal_id: str,
546
+ domain: str,
547
+ role: str,
548
+ parent_goal_id: str | None,
549
+ state_file: Path,
550
+ goal_doc: Path | None,
551
+ adapter_kind: str,
552
+ adapter_status: str,
553
+ next_probe: str | None,
554
+ spawn_allowed: bool,
555
+ max_children: int,
556
+ allowed_domains: list[str],
557
+ write_scope: list[str],
558
+ execution_profile: dict[str, Any] | None,
559
+ ) -> dict[str, Any]:
560
+ authority_sources = []
561
+ if goal_doc:
562
+ authority_sources.append(
563
+ {
564
+ "kind": "goal_doc",
565
+ "path": rel_or_abs(goal_doc, project),
566
+ "role": "primary_goal_document",
567
+ }
568
+ )
569
+ return {
570
+ "id": goal_id,
571
+ "domain": domain,
572
+ "status": "active",
573
+ "role": role,
574
+ "parent_goal_id": parent_goal_id,
575
+ "repo": str(project),
576
+ "state_file": relative_state_file(project, state_file),
577
+ "authority_sources": authority_sources,
578
+ "adapter": {
579
+ "kind": adapter_kind,
580
+ "status": adapter_status,
581
+ },
582
+ "spawn_policy": {
583
+ "mode": (
584
+ MULTI_SUBAGENT_ORCHESTRATION_MODE
585
+ if spawn_allowed and max(0, max_children) > 0
586
+ else DEFAULT_ORCHESTRATION_MODE
587
+ ),
588
+ "allowed": spawn_allowed,
589
+ "max_children": max(0, max_children),
590
+ "allowed_domains": allowed_domains,
591
+ },
592
+ "coordination": {
593
+ "write_scope": write_scope,
594
+ "requires_parent_approval": [
595
+ "write",
596
+ "publish",
597
+ "production-action",
598
+ ],
599
+ },
600
+ "execution_profile": compact_execution_profile(execution_profile),
601
+ "next_probe": next_probe
602
+ or f"loopx --registry .loopx/registry.json check --scan-root {project}",
603
+ "guards": [
604
+ "read-only by default",
605
+ "do not mutate production systems without explicit user approval",
606
+ "keep private evidence out of public commits",
607
+ ],
608
+ }
609
+
610
+
611
+ def merge_goal(registry: dict[str, Any], goal_entry: dict[str, Any], *, force: bool) -> tuple[dict[str, Any], str]:
612
+ goals = registry.get("goals")
613
+ if not isinstance(goals, list):
614
+ goals = []
615
+ merged: list[Any] = []
616
+ action = "appended"
617
+ replaced = False
618
+ for item in goals:
619
+ if isinstance(item, dict) and item.get("id") == goal_entry["id"]:
620
+ if force:
621
+ merged.append(goal_entry)
622
+ action = "replaced"
623
+ else:
624
+ merged.append(item)
625
+ action = "kept-existing"
626
+ replaced = True
627
+ else:
628
+ merged.append(item)
629
+ if not replaced:
630
+ merged.append(goal_entry)
631
+ registry["goals"] = merged
632
+ return registry, action
633
+
634
+
635
+ def bootstrap_project(
636
+ *,
637
+ project: Path,
638
+ registry_path: Path,
639
+ runtime_root: Path | None,
640
+ goal_id: str | None,
641
+ objective: str,
642
+ domain: str,
643
+ role: str,
644
+ parent_goal_id: str | None,
645
+ state_file: Path | None,
646
+ goal_doc: Path | None,
647
+ adapter_kind: str,
648
+ adapter_status: str,
649
+ next_probe: str | None,
650
+ spawn_allowed: bool,
651
+ max_children: int,
652
+ allowed_domains: list[str] | None,
653
+ write_scope: list[str] | None,
654
+ execution_minimum_scale: str | None = None,
655
+ execution_must_include: list[str] | None = None,
656
+ execution_small_streak_threshold: int | None = None,
657
+ execution_outcome_markers: list[str] | None = None,
658
+ execution_surface_only_hints: list[str] | None = None,
659
+ execution_surface_streak_threshold: int | None = None,
660
+ execution_outcome_must_advance: list[str] | None = None,
661
+ execution_turn_granularity: str | None = None,
662
+ onboarding_scan_enabled: bool = True,
663
+ accept_onboarding_agent_todos: bool = False,
664
+ begin_autonomous_advance: bool = False,
665
+ codex_app_heartbeat: str = "ask",
666
+ onboarding_max_commits: int = 5,
667
+ onboarding_max_status_paths: int = 12,
668
+ onboarding_max_top_level_files: int = 24,
669
+ preserve_todos: bool = False,
670
+ force: bool,
671
+ dry_run: bool,
672
+ sync_global: bool,
673
+ allow_global_route_replacement: bool = False,
674
+ ) -> dict[str, Any]:
675
+ project = project.expanduser().resolve()
676
+ codex_app_heartbeat = normalize_codex_app_heartbeat(codex_app_heartbeat)
677
+ registry_path = registry_path.expanduser()
678
+ if not registry_path.is_absolute():
679
+ registry_path = project / registry_path
680
+ goal_id = goal_id or default_goal_id(project)
681
+ state_file = state_file or (project / ".codex" / "goals" / goal_id / "ACTIVE_GOAL_STATE.md")
682
+ state_file = state_file.expanduser()
683
+ if not state_file.is_absolute():
684
+ state_file = project / state_file
685
+ goal_doc = resolve_project_path(project, goal_doc)
686
+ runtime_root = runtime_root.expanduser() if runtime_root else DEFAULT_RUNTIME_ROOT
687
+ updated_at = now_iso()
688
+ execution_profile = build_execution_profile(
689
+ minimum_scale=execution_minimum_scale,
690
+ must_include=execution_must_include,
691
+ small_scale_streak_threshold=execution_small_streak_threshold,
692
+ outcome_markers=execution_outcome_markers,
693
+ surface_only_hints=execution_surface_only_hints,
694
+ surface_streak_threshold=execution_surface_streak_threshold,
695
+ outcome_must_advance=execution_outcome_must_advance,
696
+ turn_granularity=execution_turn_granularity,
697
+ )
698
+ onboarding_scan = (
699
+ build_onboarding_scan(
700
+ project,
701
+ max_commits=onboarding_max_commits,
702
+ max_status_paths=onboarding_max_status_paths,
703
+ max_top_level_files=onboarding_max_top_level_files,
704
+ )
705
+ if onboarding_scan_enabled
706
+ else None
707
+ )
708
+
709
+ registry = read_json_if_exists(registry_path)
710
+ registry.setdefault("schema_version", "0.1")
711
+ registry["updated_at"] = updated_at.split("T")[0]
712
+ registry.setdefault("common_runtime_root", str(runtime_root))
713
+ if runtime_root:
714
+ registry["common_runtime_root"] = str(runtime_root)
715
+
716
+ goal_entry = build_goal_entry(
717
+ project=project,
718
+ goal_id=goal_id,
719
+ domain=domain,
720
+ role=role,
721
+ parent_goal_id=parent_goal_id,
722
+ state_file=state_file,
723
+ goal_doc=goal_doc,
724
+ adapter_kind=adapter_kind,
725
+ adapter_status=adapter_status,
726
+ next_probe=next_probe,
727
+ spawn_allowed=spawn_allowed,
728
+ max_children=max_children,
729
+ allowed_domains=allowed_domains or [],
730
+ write_scope=write_scope or [],
731
+ execution_profile=execution_profile,
732
+ )
733
+ registry, registry_goal_action = merge_goal(registry, goal_entry, force=force)
734
+
735
+ state_exists = state_file.exists()
736
+ state_action = "created"
737
+ if state_exists and force and preserve_todos:
738
+ state_action = "kept-existing-preserve-todos"
739
+ elif state_exists and not force:
740
+ state_action = "kept-existing"
741
+ elif state_exists and force:
742
+ state_action = "replaced"
743
+
744
+ repaired_state_text: str | None = None
745
+ repaired_todo_source_roles: list[str] = []
746
+ if state_exists and state_action in {
747
+ "kept-existing",
748
+ "kept-existing-preserve-todos",
749
+ }:
750
+ repaired_state_text, repaired_todo_source_roles = repair_missing_todo_source_sections(
751
+ state_file.read_text(encoding="utf-8")
752
+ )
753
+ todo_source_migration = (
754
+ {
755
+ "schema_version": "todo_source_section_migration_v0",
756
+ "added_roles": repaired_todo_source_roles,
757
+ "applied": False,
758
+ }
759
+ if repaired_todo_source_roles
760
+ else None
761
+ )
762
+
763
+ dry_state_actions = {
764
+ "created": "would-create",
765
+ "kept-existing": "would-keep-existing",
766
+ "kept-existing-preserve-todos": "would-keep-existing-preserve-todos",
767
+ "replaced": "would-replace",
768
+ }
769
+ force_bootstrap_warning = None
770
+ if state_exists and force:
771
+ force_bootstrap_warning = {
772
+ "kind": "force_reconnect_existing_active_state",
773
+ "state_file": str(state_file),
774
+ "state_action": state_action,
775
+ "will_replace_active_state": state_action == "replaced",
776
+ "preserve_todos_requested": bool(preserve_todos),
777
+ "recommended_scope_migration": (
778
+ "Use configure-goal --write-scope ... --execute to change write scope "
779
+ "without rebuilding the active state."
780
+ ),
781
+ "preserve_todos_option": "--preserve-todos",
782
+ }
783
+ actions = [
784
+ {"path": str(registry_path), "action": "would-write" if dry_run else "wrote", "goal": registry_goal_action},
785
+ {
786
+ "path": str(state_file),
787
+ "action": dry_state_actions.get(state_action, "would-write") if dry_run else state_action,
788
+ **({"todo_source_migration": todo_source_migration} if todo_source_migration else {}),
789
+ },
790
+ ]
791
+ if sync_global:
792
+ actions.append(
793
+ {
794
+ "path": str(runtime_root / "registry.global.json"),
795
+ "action": "would-sync" if dry_run else "synced",
796
+ "goal": goal_id,
797
+ }
798
+ )
799
+
800
+ candidates = onboarding_candidates(onboarding_scan)
801
+ heartbeat_required = heartbeat_opt_in_required(
802
+ onboarding_scan=onboarding_scan,
803
+ codex_app_heartbeat=codex_app_heartbeat,
804
+ )
805
+ host_loop_required = host_loop_activation_required(
806
+ onboarding_scan=onboarding_scan,
807
+ codex_app_heartbeat=codex_app_heartbeat,
808
+ )
809
+ accept_candidate_commands = [
810
+ todo_add_command(
811
+ project=project,
812
+ registry_path=registry_path,
813
+ goal_id=goal_id,
814
+ candidate=candidate,
815
+ )
816
+ for candidate in candidates
817
+ ]
818
+
819
+ global_sync: dict[str, Any] | None = None
820
+ global_writability: dict[str, Any] | None = None
821
+ if sync_global and not dry_run:
822
+ global_writability = probe_registry_write_path(runtime_root / "registry.global.json", create_parent=True)
823
+ if not global_writability.get("ok"):
824
+ for action in actions:
825
+ if action.get("path") == str(runtime_root / "registry.global.json"):
826
+ action["action"] = "blocked-write-denied"
827
+ global_sync = {
828
+ "ok": False,
829
+ "enabled": True,
830
+ "dry_run": dry_run,
831
+ "global_registry": str(runtime_root / "registry.global.json"),
832
+ "synced_goal_ids": [],
833
+ "wrote": False,
834
+ "write_denied": True,
835
+ "error_kind": "global_registry_write_denied",
836
+ "global_registry_writability": global_writability,
837
+ "requires_global_registry_repair": True,
838
+ "requires_host_permission": bool(global_writability.get("requires_host_permission")),
839
+ "recommended_action": global_writability.get("recommended_action"),
840
+ }
841
+ return {
842
+ "ok": False,
843
+ "dry_run": dry_run,
844
+ "project": str(project),
845
+ "goal_id": goal_id,
846
+ "registry": str(registry_path),
847
+ "state_file": str(state_file),
848
+ "goal_doc": str(goal_doc) if goal_doc else None,
849
+ "goal_doc_exists": bool(goal_doc and goal_doc.exists()),
850
+ "runtime_root": str(runtime_root),
851
+ "registry_goal_action": registry_goal_action,
852
+ "state_action": state_action,
853
+ "todo_source_migration": todo_source_migration,
854
+ "force_bootstrap_warning": force_bootstrap_warning,
855
+ "execution_profile": execution_profile,
856
+ "onboarding_scan": onboarding_scan,
857
+ "onboarding_agent_todo_candidates": candidates,
858
+ "accept_onboarding_agent_todos": accept_onboarding_agent_todos,
859
+ "begin_autonomous_advance": begin_autonomous_advance,
860
+ "codex_app_heartbeat": codex_app_heartbeat,
861
+ "onboarding_acceptance_required": bool(onboarding_scan and not accept_onboarding_agent_todos),
862
+ "autonomous_advance_choice_required": bool(onboarding_scan and not begin_autonomous_advance),
863
+ "heartbeat_opt_in_required": heartbeat_required,
864
+ "host_loop_activation_required": host_loop_required,
865
+ "heartbeat_opt_in_instruction": (
866
+ heartbeat_instruction(codex_app_heartbeat) if onboarding_scan else None
867
+ ),
868
+ "onboarding_todos_written": False,
869
+ "accept_candidate_commands": accept_candidate_commands,
870
+ "global_sync": global_sync,
871
+ "actions": actions,
872
+ "next_commands": [
873
+ "Fix global registry write access, then rerun this command.",
874
+ "Use --no-global-sync only for an explicit local-only setup.",
875
+ ],
876
+ "install_repair_command": NO_CLONE_INSTALL_REPAIR_COMMAND,
877
+ "install_repair_note": (
878
+ "If this local LoopX install is missing or stale, rerun the no-clone installer, "
879
+ "refresh PATH, and confirm with loopx doctor before continuing project delivery."
880
+ ),
881
+ "private_boundary_note": "Add .loopx/ and .codex/goals/ to the project .gitignore if the goal state contains private evidence.",
882
+ "error": str(global_writability.get("error") or "global registry is not writable"),
883
+ }
884
+ if not dry_run:
885
+ write_json(registry_path, registry)
886
+ if state_action in {"created", "replaced"}:
887
+ state_file.parent.mkdir(parents=True, exist_ok=True)
888
+ state_file.write_text(
889
+ render_state_markdown(
890
+ project=project,
891
+ goal_id=goal_id,
892
+ adapter_kind=adapter_kind,
893
+ objective=objective,
894
+ updated_at=updated_at,
895
+ goal_doc=goal_doc,
896
+ execution_profile=execution_profile,
897
+ onboarding_scan=onboarding_scan,
898
+ accept_onboarding_agent_todos=accept_onboarding_agent_todos,
899
+ begin_autonomous_advance=begin_autonomous_advance,
900
+ codex_app_heartbeat=codex_app_heartbeat,
901
+ ),
902
+ encoding="utf-8",
903
+ )
904
+ elif repaired_state_text is not None and repaired_todo_source_roles:
905
+ state_file.write_text(repaired_state_text, encoding="utf-8")
906
+ if todo_source_migration is not None:
907
+ todo_source_migration["applied"] = True
908
+ if sync_global:
909
+ global_sync = sync_project_registry_to_global(
910
+ registry_path=registry_path,
911
+ runtime_root_override=str(runtime_root),
912
+ goal_id=goal_id,
913
+ dry_run=False,
914
+ allow_route_replacement=allow_global_route_replacement,
915
+ )
916
+
917
+ return {
918
+ "ok": True,
919
+ "dry_run": dry_run,
920
+ "project": str(project),
921
+ "goal_id": goal_id,
922
+ "registry": str(registry_path),
923
+ "state_file": str(state_file),
924
+ "goal_doc": str(goal_doc) if goal_doc else None,
925
+ "goal_doc_exists": bool(goal_doc and goal_doc.exists()),
926
+ "runtime_root": str(runtime_root),
927
+ "registry_goal_action": registry_goal_action,
928
+ "state_action": state_action,
929
+ "todo_source_migration": todo_source_migration,
930
+ "force_bootstrap_warning": force_bootstrap_warning,
931
+ "execution_profile": execution_profile,
932
+ "onboarding_scan": onboarding_scan,
933
+ "onboarding_agent_todo_candidates": candidates,
934
+ "accept_onboarding_agent_todos": accept_onboarding_agent_todos,
935
+ "begin_autonomous_advance": begin_autonomous_advance,
936
+ "codex_app_heartbeat": codex_app_heartbeat,
937
+ "onboarding_acceptance_required": bool(onboarding_scan and not accept_onboarding_agent_todos),
938
+ "autonomous_advance_choice_required": bool(onboarding_scan and not begin_autonomous_advance),
939
+ "heartbeat_opt_in_required": heartbeat_required,
940
+ "host_loop_activation_required": host_loop_required,
941
+ "heartbeat_opt_in_instruction": heartbeat_instruction(codex_app_heartbeat) if onboarding_scan else None,
942
+ "onboarding_todos_written": bool(
943
+ onboarding_scan and state_action in {"created", "replaced"} and not dry_run
944
+ ),
945
+ "accept_candidate_commands": accept_candidate_commands,
946
+ "global_sync": global_sync
947
+ or {
948
+ "enabled": sync_global,
949
+ "dry_run": dry_run,
950
+ "global_registry": str(runtime_root / "registry.global.json"),
951
+ "synced_goal_ids": [goal_id] if sync_global else [],
952
+ "wrote": False,
953
+ "route_replacement_allowed": allow_global_route_replacement,
954
+ },
955
+ "actions": actions,
956
+ "next_commands": [
957
+ f"loopx --registry {relative_state_file(project, registry_path)} registry",
958
+ f"loopx --registry {relative_state_file(project, registry_path)} status",
959
+ f"loopx --registry {relative_state_file(project, registry_path)} check --scan-root {project}",
960
+ f"loopx --format json --registry {runtime_root / 'registry.global.json'} quota should-run --goal-id {goal_id} --runtime-profile generic_cli",
961
+ f"loopx --registry {relative_state_file(project, registry_path)} refresh-state --goal-id {goal_id}",
962
+ f"loopx --registry {runtime_root / 'registry.global.json'} status",
963
+ f"loopx --registry {relative_state_file(project, registry_path)} history --goal-id {goal_id}",
964
+ ],
965
+ "install_repair_command": NO_CLONE_INSTALL_REPAIR_COMMAND,
966
+ "install_repair_note": (
967
+ "If this local LoopX install is missing or stale, rerun the no-clone installer, "
968
+ "refresh PATH, and confirm with loopx doctor before continuing project delivery."
969
+ ),
970
+ "private_boundary_note": "Add .loopx/ and .codex/goals/ to the project .gitignore if the goal state contains private evidence.",
971
+ }
972
+
973
+
974
+ def render_bootstrap_markdown(payload: dict[str, Any]) -> str:
975
+ execution_profile = (
976
+ payload.get("execution_profile")
977
+ if isinstance(payload.get("execution_profile"), dict)
978
+ else None
979
+ )
980
+ execution_profile_text = execution_profile_summary(execution_profile)
981
+ lines = [
982
+ "# LoopX Bootstrap",
983
+ "",
984
+ f"- ok: `{payload.get('ok')}`",
985
+ f"- dry_run: `{payload.get('dry_run')}`",
986
+ f"- project: `{payload.get('project')}`",
987
+ f"- goal_id: `{payload.get('goal_id')}`",
988
+ f"- registry: `{payload.get('registry')}`",
989
+ f"- state_file: `{payload.get('state_file')}`",
990
+ f"- goal_doc: `{payload.get('goal_doc')}`",
991
+ f"- goal_doc_exists: `{payload.get('goal_doc_exists')}`",
992
+ f"- runtime_root: `{payload.get('runtime_root')}`",
993
+ f"- registry_goal_action: `{payload.get('registry_goal_action')}`",
994
+ f"- state_action: `{payload.get('state_action')}`",
995
+ f"- execution_profile: `{execution_profile_text}`",
996
+ f"- onboarding_acceptance_required: `{payload.get('onboarding_acceptance_required')}`",
997
+ f"- autonomous_advance_choice_required: `{payload.get('autonomous_advance_choice_required')}`",
998
+ f"- codex_app_heartbeat: `{payload.get('codex_app_heartbeat')}`",
999
+ f"- heartbeat_opt_in_required: `{payload.get('heartbeat_opt_in_required')}`",
1000
+ f"- host_loop_activation_required: `{payload.get('host_loop_activation_required')}`",
1001
+ f"- onboarding_todos_written: `{payload.get('onboarding_todos_written')}`",
1002
+ f"- global_sync: `{(payload.get('global_sync') or {}).get('wrote')}`",
1003
+ "",
1004
+ "## Actions",
1005
+ ]
1006
+ for action in payload.get("actions") or []:
1007
+ lines.append(f"- `{action.get('path')}`: {action.get('action')} ({action.get('goal', '')})")
1008
+
1009
+ force_warning = payload.get("force_bootstrap_warning")
1010
+ if isinstance(force_warning, dict):
1011
+ lines.extend(
1012
+ [
1013
+ "",
1014
+ "## Force Bootstrap Warning",
1015
+ f"- state_file: `{force_warning.get('state_file')}`",
1016
+ f"- will_replace_active_state: `{force_warning.get('will_replace_active_state')}`",
1017
+ f"- preserve_todos_requested: `{force_warning.get('preserve_todos_requested')}`",
1018
+ f"- recommended_scope_migration: {force_warning.get('recommended_scope_migration')}",
1019
+ f"- preserve_todos_option: `{force_warning.get('preserve_todos_option')}`",
1020
+ ]
1021
+ )
1022
+
1023
+ onboarding_scan = payload.get("onboarding_scan")
1024
+ if isinstance(onboarding_scan, dict):
1025
+ recent_commits = onboarding_scan.get("recent_commits")
1026
+ recent_commits = recent_commits if isinstance(recent_commits, list) else []
1027
+ signal_files = onboarding_scan.get("signal_files")
1028
+ signal_files = signal_files if isinstance(signal_files, list) else []
1029
+ status_sample = onboarding_scan.get("status_paths_sample")
1030
+ status_sample = status_sample if isinstance(status_sample, list) else []
1031
+ lines.extend(
1032
+ [
1033
+ "",
1034
+ "## Onboarding Scan",
1035
+ f"- schema: `{onboarding_scan.get('schema_version')}`",
1036
+ f"- git_repo: `{onboarding_scan.get('is_git_repo')}`",
1037
+ f"- status_path_count: `{onboarding_scan.get('status_path_count')}`",
1038
+ f"- recent_commits: `{len(recent_commits)}`",
1039
+ f"- signal_files: `{', '.join(str(item) for item in signal_files) or 'none'}`",
1040
+ "- raw_file_bodies_read: `False`",
1041
+ ]
1042
+ )
1043
+ if status_sample:
1044
+ lines.append("- status_sample:")
1045
+ for item in status_sample[:5]:
1046
+ lines.append(f" - `{item}`")
1047
+ if recent_commits:
1048
+ lines.append("- recent_commit_sample:")
1049
+ for commit in recent_commits[:5]:
1050
+ if isinstance(commit, dict):
1051
+ lines.append(f" - `{commit.get('hash')}` {commit.get('subject')}")
1052
+
1053
+ candidates = payload.get("onboarding_agent_todo_candidates")
1054
+ candidates = candidates if isinstance(candidates, list) else []
1055
+ if candidates:
1056
+ lines.extend(["", "## Proposed Onboarding Candidates"])
1057
+ for index, candidate in enumerate(candidates, start=1):
1058
+ if not isinstance(candidate, dict):
1059
+ continue
1060
+ lines.append(f"{index}. {candidate.get('text')}")
1061
+ if candidate.get("reason"):
1062
+ lines.append(f" - reason: {candidate.get('reason')}")
1063
+ lines.append(
1064
+ " - metadata: "
1065
+ f"`{candidate.get('task_class') or 'advancement_task'}:{candidate.get('action_kind') or 'analyze'}`"
1066
+ )
1067
+
1068
+ accept_commands = payload.get("accept_candidate_commands")
1069
+ accept_commands = accept_commands if isinstance(accept_commands, list) else []
1070
+ if accept_commands:
1071
+ lines.extend(
1072
+ [
1073
+ "",
1074
+ "## Accept Candidate Commands",
1075
+ "Run only the commands for candidates the user accepts, then refresh state.",
1076
+ ]
1077
+ )
1078
+ for command in accept_commands:
1079
+ lines.append(f"- `{command}`")
1080
+
1081
+ if onboarding_scan:
1082
+ lines.extend(
1083
+ [
1084
+ "",
1085
+ "## Autonomy And Heartbeat Choice",
1086
+ ]
1087
+ )
1088
+ instruction = payload.get("heartbeat_opt_in_instruction")
1089
+ if instruction:
1090
+ lines.append(f"- heartbeat_opt_in_instruction: {instruction}")
1091
+ if payload.get("autonomous_advance_choice_required"):
1092
+ lines.append(
1093
+ "- Ask the user whether Codex may start autonomous advancement. If autonomous=yes, run the quota "
1094
+ "guard and execute the first accepted Agent Todo; if autonomous=no, stop after writing accepted todos "
1095
+ "and refresh-state."
1096
+ )
1097
+
1098
+ lines.extend(["", "## Next Commands"])
1099
+ for command in payload.get("next_commands") or []:
1100
+ lines.append(f"- `{command}`")
1101
+
1102
+ if payload.get("install_repair_command"):
1103
+ lines.extend(
1104
+ [
1105
+ "",
1106
+ "## Install / Update Hint",
1107
+ str(payload.get("install_repair_note") or ""),
1108
+ "```bash",
1109
+ str(payload.get("install_repair_command")),
1110
+ "```",
1111
+ ]
1112
+ )
1113
+
1114
+ if payload.get("private_boundary_note"):
1115
+ lines.extend(["", "## Boundary Note", str(payload.get("private_boundary_note"))])
1116
+ return "\n".join(lines)