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,2167 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from .agent_registry import registered_agent_ids_for_goal
8
+ from .bootstrap import default_goal_id
9
+ from .capabilities.issue_fix.candidate_preflight import (
10
+ candidate_preflight_input_contract,
11
+ )
12
+ from .capabilities.issue_fix.workflow_plan import (
13
+ ISSUE_FIX_GOAL_CANDIDATE_DISCOVERY_COMMAND_TEMPLATE,
14
+ build_issue_fix_goal_command_templates,
15
+ )
16
+ from .control_plane.effect_program import effect_program_from_ordered_steps
17
+ from .control_plane.goals.start_contract import (
18
+ build_goal_start_contract,
19
+ build_goal_start_prompt,
20
+ )
21
+ from .host_loop_activation import (
22
+ agent_type_for_host_surface,
23
+ build_host_loop_activation_packet,
24
+ scheduler_command_binding_for_agent_type,
25
+ )
26
+ from .project_alias import resolve_canonical_project_alias
27
+ from .project_prompt import (
28
+ DEFAULT_HANDOFF_ADAPTER_KIND,
29
+ DEFAULT_HANDOFF_ADAPTER_STATUS,
30
+ render_available_capability_args,
31
+ render_quota_guard_command,
32
+ render_refresh_state_command,
33
+ render_scheduler_execution_args,
34
+ shell_arg,
35
+ )
36
+ from .registry import registry_goals, resolve_state_file
37
+ from .slash_commands import build_slash_command_catalog
38
+ from .thread_agent_binding import normalize_thread_id, resolve_thread_agent_binding
39
+
40
+ SCHEMA_VERSION = "loopx_bootstrap_command_pack_v0"
41
+ CANONICAL_SLASH_COMMAND = "/loopx"
42
+ GUIDED_START_SCHEMA_VERSION = "loopx_start_goal_guided_v0"
43
+ PACKET_SUMMARY_SCHEMA_VERSION = "loopx_start_goal_packet_summary_v0"
44
+ PACKET_MEASUREMENT_SCHEMA_VERSION = "loopx_packet_duplication_measurement_v0"
45
+ GUIDED_COMMAND_PACK_PROJECTION_SCHEMA_VERSION = (
46
+ "loopx_guided_command_pack_projection_v0"
47
+ )
48
+ HOST_SURFACE_SELECTION_SCHEMA_VERSION = "loopx_host_surface_selection_gate_v0"
49
+ GOAL_CAPABILITY_ROUTE_SCHEMA_VERSION = "loopx_goal_capability_route_v0"
50
+ START_GOAL_CAPABILITY_ROUTES = ("issue-fix",)
51
+ START_GOAL_HOST_SURFACES = (
52
+ "codex-app",
53
+ "codex-app-ssh",
54
+ "codex-ide-plugin",
55
+ "codex-cli-tui",
56
+ "claude-code",
57
+ "opencode",
58
+ "opencode2",
59
+ "traex-cli",
60
+ "pi",
61
+ "gemini-cli",
62
+ "cursor-agent",
63
+ "deepseek-harness",
64
+ "ark-managed-agent",
65
+ "shell",
66
+ "other-agent",
67
+ )
68
+
69
+
70
+ def _iter_string_leaves(
71
+ value: Any, path: tuple[str, ...] = ()
72
+ ) -> list[tuple[tuple[str, ...], str]]:
73
+ leaves: list[tuple[tuple[str, ...], str]] = []
74
+ if isinstance(value, dict):
75
+ for key, child in value.items():
76
+ if key == "packet_summary":
77
+ continue
78
+ leaves.extend(_iter_string_leaves(child, (*path, str(key))))
79
+ elif isinstance(value, list):
80
+ for index, child in enumerate(value):
81
+ leaves.extend(_iter_string_leaves(child, (*path, str(index))))
82
+ elif isinstance(value, str):
83
+ leaves.append((path, value))
84
+ return leaves
85
+
86
+
87
+ def _without_packet_summary(value: Any) -> Any:
88
+ if isinstance(value, dict):
89
+ return {
90
+ key: _without_packet_summary(child)
91
+ for key, child in value.items()
92
+ if key != "packet_summary"
93
+ }
94
+ if isinstance(value, list):
95
+ return [_without_packet_summary(child) for child in value]
96
+ return value
97
+
98
+
99
+ def _is_command_value(path: tuple[str, ...]) -> bool:
100
+ if not path:
101
+ return False
102
+ leaf = path[-1]
103
+ return (
104
+ (len(path) >= 2 and path[-2] == "commands")
105
+ or leaf in {"command", "command_template", "prompt", "canonical_cli_command"}
106
+ or leaf.endswith(("_command", "_prompt", "_command_if_needed"))
107
+ )
108
+
109
+
110
+ def _measure_packet_duplication(
111
+ payload: dict[str, Any], *, objective: str | None
112
+ ) -> dict[str, Any]:
113
+ compatibility_payload = _without_packet_summary(payload)
114
+ leaves = _iter_string_leaves(compatibility_payload)
115
+ objective_occurrences = 0
116
+ objective_field_count = 0
117
+ if objective:
118
+ for _, value in leaves:
119
+ count = value.count(objective)
120
+ if count:
121
+ objective_occurrences += count
122
+ objective_field_count += 1
123
+
124
+ command_values: list[str] = []
125
+ for path, value in leaves:
126
+ if not value or not _is_command_value(path):
127
+ continue
128
+ command_values.append(value)
129
+ unique_command_count = len(set(command_values))
130
+
131
+ compatibility_json = json.dumps(
132
+ compatibility_payload,
133
+ ensure_ascii=False,
134
+ separators=(",", ":"),
135
+ sort_keys=True,
136
+ )
137
+ return {
138
+ "schema_version": PACKET_MEASUREMENT_SCHEMA_VERSION,
139
+ "measurement_scope": "compatibility_projection_without_packet_summary",
140
+ "serialized_bytes": len(compatibility_json.encode("utf-8")),
141
+ "objective_content": {
142
+ "substring_occurrences": objective_occurrences,
143
+ "containing_field_count": objective_field_count,
144
+ "duplicate_occurrences": max(0, objective_occurrences - 1),
145
+ },
146
+ "command_content": {
147
+ "candidate_occurrences": len(command_values),
148
+ "unique_values": unique_command_count,
149
+ "duplicate_occurrences": len(command_values) - unique_command_count,
150
+ },
151
+ }
152
+
153
+
154
+ def _build_packet_summary(
155
+ payload: dict[str, Any],
156
+ *,
157
+ packet_kind: str,
158
+ detail_refs: dict[str, str],
159
+ legacy_fields_retained: bool = True,
160
+ compact_projection_default: bool = False,
161
+ ) -> dict[str, Any]:
162
+ next_step = payload.get("recommended_next_step")
163
+ next_step = next_step if isinstance(next_step, dict) else {}
164
+ return {
165
+ "schema_version": PACKET_SUMMARY_SCHEMA_VERSION,
166
+ "packet_kind": packet_kind,
167
+ "goal_id": payload.get("goal_id"),
168
+ "objective": payload.get("goal_text"),
169
+ "next_step_kind": next_step.get("kind"),
170
+ "detail_refs": {
171
+ name: {
172
+ "schema_version": "loopx_packet_json_pointer_ref_v0",
173
+ "json_pointer": pointer,
174
+ }
175
+ for name, pointer in detail_refs.items()
176
+ },
177
+ "compatibility": {
178
+ "legacy_fields_retained": legacy_fields_retained,
179
+ "compact_projection_default": compact_projection_default,
180
+ "removal_gate": "explicit_host_shadow_parity",
181
+ },
182
+ "duplication_measurement": _measure_packet_duplication(
183
+ payload,
184
+ objective=str(payload.get("goal_text"))
185
+ if payload.get("goal_text")
186
+ else None,
187
+ ),
188
+ }
189
+
190
+
191
+ def _start_goal_command(
192
+ *,
193
+ project: str,
194
+ goal_id: str | None,
195
+ agent_id: str | None,
196
+ thread_id: str | None,
197
+ new_peer: bool,
198
+ cli_bin: str,
199
+ host_surface: str,
200
+ goal_text: str,
201
+ available_capabilities: list[str] | None,
202
+ capability_route: str | None,
203
+ fine_grained: bool,
204
+ include_command_pack_detail: bool,
205
+ ) -> str:
206
+ return (
207
+ f"{shell_arg(cli_bin)} --format json start-goal --guided "
208
+ f"--project {shell_arg(project)}"
209
+ + (f" --goal-id {shell_arg(goal_id)}" if goal_id else "")
210
+ + (f" --agent-id {shell_arg(agent_id)}" if agent_id else "")
211
+ + (f" --thread-id {shell_arg(thread_id)}" if thread_id else "")
212
+ + (" --new-peer" if new_peer else "")
213
+ + f" --host-surface {shell_arg(host_surface)}"
214
+ + render_available_capability_args(available_capabilities)
215
+ + (" --fine-grained" if fine_grained else "")
216
+ + (
217
+ f" --capability-route {shell_arg(capability_route)}"
218
+ if capability_route
219
+ else ""
220
+ )
221
+ + f" --goal-text {shell_arg(goal_text)}"
222
+ + (" --include-command-pack-detail" if include_command_pack_detail else "")
223
+ )
224
+
225
+
226
+ def _start_goal_detail_command(
227
+ *,
228
+ project: str,
229
+ goal_id: str | None,
230
+ agent_id: str | None,
231
+ thread_id: str | None,
232
+ new_peer: bool,
233
+ cli_bin: str,
234
+ host_surface: str,
235
+ goal_text: str,
236
+ available_capabilities: list[str] | None,
237
+ capability_route: str | None,
238
+ fine_grained: bool,
239
+ ) -> str:
240
+ return _start_goal_command(
241
+ project=project,
242
+ goal_id=goal_id,
243
+ agent_id=agent_id,
244
+ thread_id=thread_id,
245
+ new_peer=new_peer,
246
+ cli_bin=cli_bin,
247
+ host_surface=host_surface,
248
+ goal_text=goal_text,
249
+ available_capabilities=available_capabilities,
250
+ capability_route=capability_route,
251
+ fine_grained=fine_grained,
252
+ include_command_pack_detail=True,
253
+ )
254
+
255
+
256
+ def _guided_command_pack_projection(
257
+ command_pack: dict[str, Any],
258
+ *,
259
+ detail_command: str,
260
+ ) -> dict[str, Any]:
261
+ """Keep the guided hot path actionable without nesting the full host packet."""
262
+
263
+ projection: dict[str, Any] = {
264
+ "ok": command_pack.get("ok"),
265
+ "schema_version": command_pack.get("schema_version"),
266
+ "projection_schema_version": GUIDED_COMMAND_PACK_PROJECTION_SCHEMA_VERSION,
267
+ "projection_mode": "guided_start_compatibility",
268
+ "read_only": command_pack.get("read_only"),
269
+ "project": command_pack.get("project"),
270
+ "goal_id": command_pack.get("goal_id"),
271
+ "agent_id": command_pack.get("agent_id"),
272
+ "host_surface": command_pack.get("host_surface"),
273
+ "canonical_cli_command": command_pack.get("canonical_cli_command"),
274
+ "goal_start_contract": command_pack.get("goal_start_contract"),
275
+ "commands": command_pack.get("commands"),
276
+ "host_loop_activation": command_pack.get("host_loop_activation"),
277
+ "safety_contract": command_pack.get("safety_contract"),
278
+ "detail_command": detail_command,
279
+ }
280
+ projection["packet_summary"] = _build_packet_summary(
281
+ projection,
282
+ packet_kind="bootstrap_command_pack_projection",
283
+ detail_refs={
284
+ "goal_start_contract": "#/goal_start_contract",
285
+ "commands": "#/commands",
286
+ "host_loop_activation": "#/host_loop_activation",
287
+ "safety_contract": "#/safety_contract",
288
+ "full_command_pack": "#/detail_command",
289
+ },
290
+ legacy_fields_retained=False,
291
+ compact_projection_default=True,
292
+ )
293
+ return projection
294
+
295
+
296
+ def build_start_goal_host_surface_selection_packet(
297
+ *,
298
+ project: Path,
299
+ goal_id: str | None,
300
+ agent_id: str | None,
301
+ cli_bin: str,
302
+ goal_text: str,
303
+ thread_id: str | None = None,
304
+ new_peer: bool = False,
305
+ available_capabilities: list[str] | None = None,
306
+ capability_route: str | None = None,
307
+ fine_grained: bool = False,
308
+ include_command_pack_detail: bool = False,
309
+ ) -> dict[str, Any]:
310
+ """Fail closed when the caller has not identified the current Codex host."""
311
+
312
+ resolved_project = str(_resolve_project(project))
313
+ normalized_goal_text = " ".join(goal_text.split())
314
+ host_descriptions = {
315
+ "codex-app": "Codex desktop app with heartbeat automation support",
316
+ "codex-app-ssh": "Codex desktop app over SSH with visible /goal support",
317
+ "codex-ide-plugin": "Codex IDE plugin; activate its visible goal mode",
318
+ "codex-cli-tui": "terminal Codex TUI with visible /goal support",
319
+ "claude-code": "Claude Code with native /loop",
320
+ "opencode": "OpenCode LoopX goal bridge",
321
+ "opencode2": "OpenCode 2 session driven by the LoopX goal worker",
322
+ "traex-cli": "terminal TraeX TUI with visible /goal support (needs [features] goals = true)",
323
+ "pi": "Pi LoopX goal extension",
324
+ "gemini-cli": "Gemini CLI driving its own loop through the LoopX skill facade",
325
+ "cursor-agent": "cursor-agent driving its own loop through the LoopX skill facade and MCP server",
326
+ "deepseek-harness": "DeepSeek Harness automation loop through scripts/dsh_turn_host_adapter.py",
327
+ "ark-managed-agent": "Ark Managed Agent with one-shot Goal submission",
328
+ "shell": "manual shell or an explicitly configured external scheduler",
329
+ "other-agent": "custom agent host using the returned activation contract",
330
+ }
331
+ choices: list[dict[str, Any]] = []
332
+ for host_surface in START_GOAL_HOST_SURFACES:
333
+ rerun_command = (
334
+ f"{shell_arg(cli_bin)} start-goal --guided "
335
+ f"--project {shell_arg(resolved_project)}"
336
+ + (f" --goal-id {shell_arg(goal_id)}" if goal_id else "")
337
+ + (f" --agent-id {shell_arg(agent_id)}" if agent_id else "")
338
+ + (f" --thread-id {shell_arg(thread_id)}" if thread_id else "")
339
+ + (" --new-peer" if new_peer else "")
340
+ + f" --host-surface {shell_arg(host_surface)}"
341
+ + render_available_capability_args(available_capabilities)
342
+ + (" --fine-grained" if fine_grained else "")
343
+ + (
344
+ f" --capability-route {shell_arg(capability_route)}"
345
+ if capability_route
346
+ else ""
347
+ )
348
+ + f" --goal-text {shell_arg(normalized_goal_text)}"
349
+ + (" --include-command-pack-detail" if include_command_pack_detail else "")
350
+ )
351
+ choices.append(
352
+ {
353
+ "host_surface": host_surface,
354
+ "description": host_descriptions[host_surface],
355
+ "rerun_command": rerun_command,
356
+ }
357
+ )
358
+ reason = (
359
+ "host surface is required because Codex App automation, Codex App over SSH, "
360
+ "the Codex IDE plugin, Codex CLI, and Ark Managed Agent "
361
+ "have different continuation contracts"
362
+ )
363
+ gate = {
364
+ "schema_version": HOST_SURFACE_SELECTION_SCHEMA_VERSION,
365
+ "state": "selection_required",
366
+ "action_required": True,
367
+ "reason": reason,
368
+ "required_cli_arg": "--host-surface <exact-host-surface>",
369
+ "choices": choices,
370
+ }
371
+ transaction = {
372
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
373
+ "mode": "dry_run_preview",
374
+ "writes_now": False,
375
+ "spends_quota_now": False,
376
+ "goal_text": normalized_goal_text,
377
+ "blocked_by": "host_surface_selection",
378
+ "host_surface_selection_gate": gate,
379
+ "ordered_steps": [
380
+ {
381
+ "id": "select_host_surface",
382
+ "kind": "host_surface_selection_gate",
383
+ "choices": choices,
384
+ "purpose": "select the current host before planning, mutation, or loop activation",
385
+ }
386
+ ],
387
+ "idempotency_policy": {"safe_to_rerun_preview": True},
388
+ "preserve_todos_policy": {
389
+ "force_bootstrap_default": "forbidden_in_guided_flow",
390
+ "before_destructive_reconnect": "select a host before any mutation",
391
+ "preferred_scope_change": "select a host before any mutation",
392
+ },
393
+ }
394
+ payload: dict[str, Any] = {
395
+ "ok": True,
396
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
397
+ "read_only": True,
398
+ "guided": True,
399
+ "project": resolved_project,
400
+ "goal_id": goal_id,
401
+ "agent_id": agent_id,
402
+ "thread_id": normalize_thread_id(thread_id),
403
+ "new_peer": new_peer,
404
+ "host_surface": None,
405
+ "goal_text": normalized_goal_text,
406
+ "host_surface_selection_gate": gate,
407
+ "recommended_next_step": {
408
+ "kind": "select_host_surface",
409
+ "requires_user_confirmation": False,
410
+ "requires_host_surface_selection": True,
411
+ "summary": reason,
412
+ },
413
+ "guided_transaction": transaction,
414
+ "command_pack_detail_included": include_command_pack_detail,
415
+ "safety_contract": {
416
+ "writes_registry": False,
417
+ "writes_state_file": False,
418
+ "creates_heartbeat": False,
419
+ "spends_quota": False,
420
+ "mutation_commands_are_previewed": False,
421
+ "force_bootstrap_allowed": False,
422
+ },
423
+ }
424
+ payload["message"] = render_start_goal_guided_markdown(payload)
425
+ payload["packet_summary"] = _build_packet_summary(
426
+ payload,
427
+ packet_kind="guided_start_host_surface_selection",
428
+ detail_refs={
429
+ "host_surface_selection_gate": "#/host_surface_selection_gate",
430
+ "guided_transaction": "#/guided_transaction",
431
+ "safety_contract": "#/safety_contract",
432
+ "compatibility_message": "#/message",
433
+ },
434
+ )
435
+ return payload
436
+
437
+
438
+ def _resolve_project(project: Path) -> Path:
439
+ project = project.expanduser()
440
+ try:
441
+ return project.resolve()
442
+ except OSError:
443
+ return project.absolute()
444
+
445
+
446
+ def _read_registry(path: Path) -> tuple[dict[str, Any] | None, str | None]:
447
+ try:
448
+ with path.open(encoding="utf-8") as f:
449
+ payload = json.load(f)
450
+ except FileNotFoundError:
451
+ return None, None
452
+ except (OSError, json.JSONDecodeError) as exc:
453
+ return None, str(exc)
454
+ if not isinstance(payload, dict):
455
+ return None, "registry root must be a JSON object"
456
+ return payload, None
457
+
458
+
459
+ def _select_goal(goals: list[dict[str, Any]], goal_id: str | None) -> tuple[str, dict[str, Any] | None]:
460
+ if goal_id:
461
+ for goal in goals:
462
+ if goal.get("id") == goal_id:
463
+ return goal_id, goal
464
+ return goal_id, None
465
+ if goals:
466
+ first_goal_id = str(goals[0].get("id"))
467
+ return first_goal_id, goals[0]
468
+ return "", None
469
+
470
+
471
+ def inspect_bootstrap_connection(
472
+ project: Path,
473
+ *,
474
+ goal_id: str | None = None,
475
+ resolve_linked_worktree_alias: bool = True,
476
+ ) -> dict[str, Any]:
477
+ """Inspect either the canonical project route or the caller's exact route."""
478
+
479
+ input_project = _resolve_project(project)
480
+ alias = (
481
+ resolve_canonical_project_alias(input_project, goal_id=goal_id)
482
+ if resolve_linked_worktree_alias
483
+ else {
484
+ "applied": False,
485
+ "kind": "exact_project_route",
486
+ "input_project": str(input_project),
487
+ "reason": "the caller requires the explicitly requested project route",
488
+ }
489
+ )
490
+ resolved_project = (
491
+ _resolve_project(Path(str(alias.get("canonical_project"))))
492
+ if alias.get("applied") and alias.get("canonical_project")
493
+ else input_project
494
+ )
495
+ registry_path = resolved_project / ".loopx" / "registry.json"
496
+ registry_exists = registry_path.exists()
497
+ registry, registry_error = _read_registry(registry_path) if registry_exists else (None, None)
498
+ inferred_goal_id = goal_id or default_goal_id(resolved_project)
499
+ state_file = resolved_project / ".codex" / "goals" / inferred_goal_id / "ACTIVE_GOAL_STATE.md"
500
+ base_connection = {
501
+ "input_project": str(input_project),
502
+ "project": str(resolved_project),
503
+ "canonical_project_alias": alias,
504
+ "registry": str(registry_path),
505
+ }
506
+
507
+ if registry_error:
508
+ return {
509
+ **base_connection,
510
+ "registry_exists": registry_exists,
511
+ "goal_id": inferred_goal_id,
512
+ "goal_found": False,
513
+ "state_file": str(state_file),
514
+ "state_file_exists": state_file.exists(),
515
+ "connection_state": "registry_invalid",
516
+ "mutation_confirmation_required": True,
517
+ "reason": registry_error,
518
+ }
519
+
520
+ if not registry:
521
+ return {
522
+ **base_connection,
523
+ "registry_exists": False,
524
+ "goal_id": inferred_goal_id,
525
+ "goal_found": False,
526
+ "state_file": str(state_file),
527
+ "state_file_exists": state_file.exists(),
528
+ "connection_state": "not_connected",
529
+ "mutation_confirmation_required": True,
530
+ "reason": "project-local .loopx/registry.json is missing",
531
+ }
532
+
533
+ goals = registry_goals(registry)
534
+ selected_goal_id, selected_goal = _select_goal(goals, goal_id)
535
+ resolved_goal_id = selected_goal_id or inferred_goal_id
536
+ fallback_state_file = resolved_project / ".codex" / "goals" / resolved_goal_id / "ACTIVE_GOAL_STATE.md"
537
+ goal_state_file = (
538
+ resolve_state_file(resolved_project, str(selected_goal.get("state_file")))
539
+ if selected_goal and selected_goal.get("state_file")
540
+ else None
541
+ )
542
+ state_file = goal_state_file or fallback_state_file
543
+
544
+ if selected_goal is None:
545
+ return {
546
+ **base_connection,
547
+ "registry_exists": True,
548
+ "goal_id": resolved_goal_id,
549
+ "goal_found": False,
550
+ "known_goal_ids": [str(goal.get("id")) for goal in goals],
551
+ "state_file": str(state_file),
552
+ "state_file_exists": state_file.exists(),
553
+ "connection_state": "registry_without_goal",
554
+ "mutation_confirmation_required": True,
555
+ "reason": "registry exists but no matching goal entry was found",
556
+ }
557
+
558
+ if not selected_goal.get("state_file"):
559
+ return {
560
+ **base_connection,
561
+ "registry_exists": True,
562
+ "goal_id": resolved_goal_id,
563
+ "goal_found": True,
564
+ "state_file": str(state_file),
565
+ "state_file_exists": state_file.exists(),
566
+ "connection_state": "registry_goal_missing_state_file",
567
+ "mutation_confirmation_required": True,
568
+ "reason": "goal entry does not declare state_file",
569
+ }
570
+
571
+ if not state_file.exists():
572
+ return {
573
+ **base_connection,
574
+ "registry_exists": True,
575
+ "goal_id": resolved_goal_id,
576
+ "goal_found": True,
577
+ "state_file": str(state_file),
578
+ "state_file_exists": False,
579
+ "connection_state": "state_file_missing",
580
+ "mutation_confirmation_required": True,
581
+ "reason": "registry goal points at a state_file that is missing",
582
+ }
583
+
584
+ return {
585
+ **base_connection,
586
+ "registry_exists": True,
587
+ "goal_id": resolved_goal_id,
588
+ "goal_found": True,
589
+ "state_file": str(state_file),
590
+ "state_file_exists": True,
591
+ "connection_state": "connected",
592
+ "mutation_confirmation_required": False,
593
+ "reason": "registry goal and active state_file are present",
594
+ }
595
+
596
+
597
+ def _bootstrap_command(
598
+ *,
599
+ project: str,
600
+ goal_id: str,
601
+ cli_bin: str,
602
+ dry_run: bool,
603
+ fine_grained: bool = False,
604
+ ) -> str:
605
+ lines = [
606
+ f"cd {shell_arg(project)}",
607
+ f"{shell_arg(cli_bin)} bootstrap \\",
608
+ " --project . \\",
609
+ f" --goal-id {shell_arg(goal_id)} \\",
610
+ f" --adapter-kind {shell_arg(DEFAULT_HANDOFF_ADAPTER_KIND)} \\",
611
+ f" --adapter-status {shell_arg(DEFAULT_HANDOFF_ADAPTER_STATUS)} \\",
612
+ " --codex-app-heartbeat ask",
613
+ ]
614
+ if fine_grained:
615
+ lines[-1] += " \\"
616
+ lines.append(" --fine-grained")
617
+ if dry_run:
618
+ lines[-1] += " \\"
619
+ lines.append(" --dry-run")
620
+ return "\n".join(lines)
621
+
622
+
623
+ def _project_command(project: str, command: str) -> str:
624
+ return "\n".join([f"cd {shell_arg(project)}", command])
625
+
626
+
627
+ def _goal_start_bootstrap_command(
628
+ *,
629
+ project: str,
630
+ goal_id: str,
631
+ goal_text: str | None,
632
+ cli_bin: str,
633
+ fine_grained: bool,
634
+ ) -> str:
635
+ objective = goal_text or "<exact /loopx goal text>"
636
+ lines = [
637
+ f"cd {shell_arg(project)}",
638
+ f"{shell_arg(cli_bin)} bootstrap \\",
639
+ " --project . \\",
640
+ f" --goal-id {shell_arg(goal_id)} \\",
641
+ f" --objective {shell_arg(objective)} \\",
642
+ f" --adapter-kind {shell_arg(DEFAULT_HANDOFF_ADAPTER_KIND)} \\",
643
+ f" --adapter-status {shell_arg(DEFAULT_HANDOFF_ADAPTER_STATUS)} \\",
644
+ " --no-onboarding-scan \\",
645
+ " --codex-app-heartbeat ask",
646
+ ]
647
+ if fine_grained:
648
+ lines[-1] += " \\"
649
+ lines.append(" --fine-grained")
650
+ return "\n".join(lines)
651
+
652
+
653
+ def _selected_goal_capability_route(
654
+ capability_route: str | None,
655
+ ) -> dict[str, Any] | None:
656
+ if capability_route is None:
657
+ return None
658
+ if capability_route not in START_GOAL_CAPABILITY_ROUTES:
659
+ raise ValueError(
660
+ "unsupported --capability-route; expected one of: "
661
+ + ", ".join(START_GOAL_CAPABILITY_ROUTES)
662
+ )
663
+ return {
664
+ "schema_version": GOAL_CAPABILITY_ROUTE_SCHEMA_VERSION,
665
+ "capability_id": "issue-fix",
666
+ "selection_source": "explicit_capability_route",
667
+ "selection_reason_code": "capability_route_enabled",
668
+ "entry_command_key": "issue_fix_workflow_plan_template",
669
+ "admission_command_key": "issue_fix_feasibility_template",
670
+ "candidate_authority": "public_open_tracker_issue",
671
+ "authority_refresh_required": "current issue body and latest comments",
672
+ "candidate_preflight": candidate_preflight_input_contract(),
673
+ "implementation_admission": {
674
+ "status": "qualification_required",
675
+ "state_owner": "issue_fix",
676
+ "route_scope": "start_goal_bootstrap_only",
677
+ "candidate_receipt_stream": "candidate-preflight",
678
+ "feasibility_required_for_route": "proceed",
679
+ "durable_execution_binding": {
680
+ "schema_version": "capability_execution_binding_v0",
681
+ "capability_id": "issue-fix",
682
+ "todo_binding_ref_field": "capability_binding_ref",
683
+ "authority_source": "admission_result.capability_execution_binding",
684
+ "authority_stream": "feasibility",
685
+ "authority_packet_schema_version": "issue_fix_feasibility_v0",
686
+ "bound_todo_fields": ["action_kind", "target_key"],
687
+ "legacy_unbound_todo_fallback": {
688
+ "authority": "current_feasibility_row",
689
+ "match": "exact_action_kind_and_target_key",
690
+ "prefix_match_allowed": False,
691
+ },
692
+ },
693
+ },
694
+ "activation_condition": (
695
+ "after selecting a public issue candidate and before substantive "
696
+ "implementation"
697
+ ),
698
+ }
699
+
700
+
701
+
702
+ def build_loopx_bootstrap_command_pack(
703
+ *,
704
+ project: Path,
705
+ goal_id: str | None,
706
+ agent_id: str | None,
707
+ cli_bin: str,
708
+ host_surface: str,
709
+ goal_text: str | None = None,
710
+ thread_id: str | None = None,
711
+ new_peer: bool = False,
712
+ available_capabilities: list[str] | None = None,
713
+ capability_route: str | None = None,
714
+ fine_grained: bool = False,
715
+ resolve_linked_worktree_alias: bool = True,
716
+ ) -> dict[str, Any]:
717
+ inspection = inspect_bootstrap_connection(
718
+ project,
719
+ goal_id=goal_id,
720
+ resolve_linked_worktree_alias=resolve_linked_worktree_alias,
721
+ )
722
+ resolved_project = str(inspection["project"])
723
+ resolved_goal_id = str(inspection["goal_id"])
724
+ connected = inspection.get("connection_state") == "connected"
725
+ mutation_confirmation_required = bool(inspection.get("mutation_confirmation_required"))
726
+ normalized_goal_text = " ".join(goal_text.split()) if goal_text else None
727
+ normalized_thread_id = normalize_thread_id(thread_id)
728
+ explicit_goal_start = bool(normalized_goal_text)
729
+ issue_fix_hint_commands = build_issue_fix_goal_command_templates(
730
+ cli_bin=cli_bin,
731
+ goal_id="<goal-id>",
732
+ )
733
+ agent_type = agent_type_for_host_surface(host_surface)
734
+ registry_path = Path(str(inspection["registry"]))
735
+ registry_payload, _registry_error = _read_registry(registry_path)
736
+ registry_goal = next(
737
+ (
738
+ goal
739
+ for goal in registry_goals(registry_payload or {})
740
+ if str(goal.get("id")) == resolved_goal_id
741
+ ),
742
+ None,
743
+ )
744
+ registered_agents = registered_agent_ids_for_goal(registry_goal)
745
+ thread_binding = resolve_thread_agent_binding(
746
+ registry_goal,
747
+ host_surface=host_surface,
748
+ thread_id=normalized_thread_id,
749
+ )
750
+ thread_binding["selection_required"] = bool(
751
+ explicit_goal_start
752
+ and agent_type == "codex-app"
753
+ and not normalized_thread_id
754
+ and not new_peer
755
+ )
756
+ effective_agent_id = agent_id
757
+ if not effective_agent_id and thread_binding.get("status") == "bound":
758
+ effective_agent_id = str(thread_binding.get("agent_id"))
759
+
760
+ fresh_agent_default = bool(
761
+ explicit_goal_start
762
+ and (
763
+ new_peer
764
+ or (
765
+ normalized_thread_id
766
+ and thread_binding.get("status") == "missing"
767
+ )
768
+ or (not normalized_thread_id and agent_type != "codex-app")
769
+ )
770
+ )
771
+
772
+ bootstrap_preview_command = _bootstrap_command(
773
+ project=resolved_project,
774
+ goal_id=resolved_goal_id,
775
+ cli_bin=cli_bin,
776
+ dry_run=True,
777
+ fine_grained=fine_grained,
778
+ )
779
+ bootstrap_after_confirmation_command = _bootstrap_command(
780
+ project=resolved_project,
781
+ goal_id=resolved_goal_id,
782
+ cli_bin=cli_bin,
783
+ dry_run=False,
784
+ fine_grained=fine_grained,
785
+ )
786
+ host_loop_activation = build_host_loop_activation_packet(
787
+ agent_type=agent_type,
788
+ goal_id=resolved_goal_id,
789
+ cli_bin=cli_bin,
790
+ agent_id=effective_agent_id,
791
+ registered_agents=registered_agents,
792
+ available_capabilities=available_capabilities,
793
+ fresh_agent_default=fresh_agent_default,
794
+ thread_binding=thread_binding,
795
+ )
796
+ selected_agent_id = host_loop_activation.get("agent_id")
797
+ thread_binding_projection = {"status": thread_binding.get("status")}
798
+ if thread_binding.get("agent_id"):
799
+ thread_binding_projection["agent_id"] = thread_binding["agent_id"]
800
+ issue_fix_commands = build_issue_fix_goal_command_templates(
801
+ cli_bin=cli_bin,
802
+ goal_id=resolved_goal_id,
803
+ agent_id=str(selected_agent_id) if selected_agent_id else "<agent-id>",
804
+ )
805
+ activation_allowed = bool(host_loop_activation.get("activation_allowed"))
806
+ activation_commands = host_loop_activation.get("commands")
807
+ activation_commands = activation_commands if isinstance(activation_commands, dict) else {}
808
+ heartbeat_prompt_command = activation_commands.get("heartbeat_prompt")
809
+ heartbeat_prompt_json_command = activation_commands.get("heartbeat_prompt_json")
810
+ scheduler_command_binding = scheduler_command_binding_for_agent_type(agent_type)
811
+ quota_guard_command = (
812
+ render_quota_guard_command(
813
+ resolved_goal_id,
814
+ cli_bin=cli_bin,
815
+ agent_id=str(selected_agent_id) if selected_agent_id else None,
816
+ available_capabilities=available_capabilities,
817
+ **scheduler_command_binding,
818
+ )
819
+ if activation_allowed
820
+ else None
821
+ )
822
+ goal_start_quota_should_run = (
823
+ (
824
+ f"{shell_arg(cli_bin)} quota should-run --goal-id "
825
+ f"{shell_arg(resolved_goal_id)}"
826
+ + (
827
+ f" --agent-id {shell_arg(str(selected_agent_id))}"
828
+ if selected_agent_id
829
+ else ""
830
+ )
831
+ + render_available_capability_args(available_capabilities)
832
+ + render_scheduler_execution_args(**scheduler_command_binding)
833
+ )
834
+ if activation_allowed
835
+ else None
836
+ )
837
+ status_command = _project_command(resolved_project, f"{shell_arg(cli_bin)} status")
838
+ goal_start_bootstrap_command = _goal_start_bootstrap_command(
839
+ project=resolved_project,
840
+ goal_id=resolved_goal_id,
841
+ goal_text=normalized_goal_text,
842
+ cli_bin=cli_bin,
843
+ fine_grained=fine_grained,
844
+ )
845
+ goal_start_plan_prompt = build_goal_start_prompt(
846
+ goal_text=normalized_goal_text,
847
+ goal_id=resolved_goal_id,
848
+ agent_id=str(selected_agent_id) if selected_agent_id else None,
849
+ fine_grained=fine_grained,
850
+ )
851
+ slash_command_catalog = build_slash_command_catalog(cli_bin=cli_bin)
852
+
853
+ identity_selection_gate = host_loop_activation.get("identity_selection_gate")
854
+ if isinstance(identity_selection_gate, dict):
855
+ recommended_next_step = {
856
+ "kind": "select_agent_identity",
857
+ "requires_user_confirmation": False,
858
+ "requires_agent_selection": True,
859
+ "summary": identity_selection_gate.get("reason"),
860
+ "identity_selection_gate": identity_selection_gate,
861
+ }
862
+ elif explicit_goal_start:
863
+ recommended_next_step = {
864
+ "kind": "goal_plan_write_and_activate",
865
+ "requires_user_confirmation": False,
866
+ "confirmation_source": "/loopx <goal text>",
867
+ "summary": (
868
+ "The slash command includes an explicit goal. Connect the project if needed, plan ranked todos, "
869
+ "write them in exact plan order, refresh state, activate the host loop if missing/stale, "
870
+ "and enter the quota-gated automation flow."
871
+ ),
872
+ "connect_command_if_needed": goal_start_bootstrap_command,
873
+ "plan_prompt": goal_start_plan_prompt,
874
+ }
875
+ else:
876
+ recommended_next_step = {
877
+ "kind": "status_and_loop_activation" if connected else "confirm_before_bootstrap_mutation",
878
+ "requires_user_confirmation": mutation_confirmation_required,
879
+ "summary": (
880
+ "Project is connected; show status, then generate the heartbeat prompt only if the user wants a loop surface."
881
+ if connected
882
+ else "Project is not fully connected; show the dry-run preview and ask before running bootstrap/connect."
883
+ ),
884
+ }
885
+ if mutation_confirmation_required:
886
+ recommended_next_step["dry_run_command"] = bootstrap_preview_command
887
+ recommended_next_step["after_confirmation_command"] = bootstrap_after_confirmation_command
888
+
889
+ payload: dict[str, Any] = {
890
+ "ok": True,
891
+ "schema_version": SCHEMA_VERSION,
892
+ "slash_command": CANONICAL_SLASH_COMMAND,
893
+ "slash_forms": [
894
+ {"form": "/loopx", "mode": "inspect_or_connect_preview"},
895
+ {"form": "/loopx <goal text>", "mode": "goal_plan_write_and_activate"},
896
+ ],
897
+ "canonical_cli_command": (
898
+ f"{shell_arg(cli_bin)} bootstrap-command-pack --project {shell_arg(resolved_project)} "
899
+ f"--goal-id {shell_arg(resolved_goal_id)}"
900
+ + (
901
+ f" --agent-id {shell_arg(str(selected_agent_id))}"
902
+ if selected_agent_id
903
+ else ""
904
+ )
905
+ + (
906
+ f" --thread-id {shell_arg(normalized_thread_id)}"
907
+ if normalized_thread_id
908
+ else ""
909
+ )
910
+ + (" --new-peer" if new_peer else "")
911
+ + f" --host-surface {shell_arg(host_surface)}"
912
+ + render_available_capability_args(available_capabilities)
913
+ + (" --fine-grained" if fine_grained else "")
914
+ + (
915
+ f" --capability-route {shell_arg(capability_route)}"
916
+ if capability_route
917
+ else ""
918
+ )
919
+ + (
920
+ f" --goal-text {shell_arg(normalized_goal_text)}"
921
+ if normalized_goal_text
922
+ else ""
923
+ )
924
+ ),
925
+ "read_only": True,
926
+ "goal_text": normalized_goal_text,
927
+ "project": resolved_project,
928
+ "goal_id": resolved_goal_id,
929
+ "agent_id": selected_agent_id,
930
+ "requested_agent_id": agent_id,
931
+ "agent_type": agent_type,
932
+ "host_surface": host_surface,
933
+ "project_connection": inspection,
934
+ "host_loop_activation": host_loop_activation,
935
+ "available_slash_commands": slash_command_catalog,
936
+ "onboarding_hint": slash_command_catalog["onboarding"],
937
+ "recommended_next_step": recommended_next_step,
938
+ "goal_start_contract": build_goal_start_contract(
939
+ goal_text=normalized_goal_text,
940
+ selected_capability_route=_selected_goal_capability_route(
941
+ capability_route
942
+ ),
943
+ connected=connected,
944
+ agent_type=agent_type,
945
+ issue_fix_commands=issue_fix_hint_commands,
946
+ fine_grained=fine_grained,
947
+ ),
948
+ "commands": {
949
+ "doctor": f"{shell_arg(cli_bin)} doctor",
950
+ "status": status_command,
951
+ "quota_guard": quota_guard_command,
952
+ "heartbeat_prompt": heartbeat_prompt_command,
953
+ "heartbeat_prompt_json": heartbeat_prompt_json_command,
954
+ "bootstrap_dry_run_preview": bootstrap_preview_command,
955
+ "bootstrap_after_user_confirmation": bootstrap_after_confirmation_command,
956
+ "goal_start_connect_if_needed": goal_start_bootstrap_command,
957
+ **(
958
+ {
959
+ "goal_start_configure_turn_granularity": _project_command(
960
+ resolved_project,
961
+ f"{shell_arg(cli_bin)} configure-goal --goal-id "
962
+ f"{shell_arg(resolved_goal_id)} "
963
+ "--execution-turn-granularity fine --execute",
964
+ )
965
+ }
966
+ if fine_grained
967
+ else {}
968
+ ),
969
+ "goal_start_plan_prompt": goal_start_plan_prompt,
970
+ "goal_start_bind_thread": (
971
+ f"{shell_arg(cli_bin)} bind-agent-thread --goal-id {shell_arg(resolved_goal_id)} "
972
+ f"--thread-id {shell_arg(normalized_thread_id)} --host-surface {shell_arg(host_surface)} "
973
+ f"--agent-id {shell_arg(str(selected_agent_id))} --execute"
974
+ if (
975
+ normalized_thread_id
976
+ and selected_agent_id
977
+ and thread_binding.get("status") == "missing"
978
+ )
979
+ else None
980
+ ),
981
+ "goal_start_refresh_state": render_refresh_state_command(
982
+ resolved_goal_id,
983
+ cli_bin=cli_bin,
984
+ project=".",
985
+ agent_id=str(selected_agent_id) if selected_agent_id else None,
986
+ progress_scope="agent_lane" if selected_agent_id else None,
987
+ ),
988
+ "goal_start_host_loop_activation": host_loop_activation.get("activation_input_command"),
989
+ "goal_start_agent_onboard_recheck": (
990
+ f"{shell_arg(cli_bin)} agent-onboard "
991
+ f"--agent-type {shell_arg(agent_type)} "
992
+ f"--project {shell_arg(resolved_project)} "
993
+ f"--goal-id {shell_arg(resolved_goal_id)}"
994
+ + (
995
+ f" --agent-id {shell_arg(str(selected_agent_id))}"
996
+ if selected_agent_id
997
+ else ""
998
+ )
999
+ + render_available_capability_args(available_capabilities)
1000
+ ),
1001
+ "goal_start_quota_should_run": goal_start_quota_should_run,
1002
+ "identity_selection_choices": (
1003
+ identity_selection_gate.get("choices")
1004
+ if isinstance(identity_selection_gate, dict)
1005
+ else []
1006
+ ),
1007
+ "fresh_agent_registration": (
1008
+ identity_selection_gate.get("fresh_agent_registration")
1009
+ if isinstance(identity_selection_gate, dict)
1010
+ else None
1011
+ ),
1012
+ **issue_fix_commands,
1013
+ },
1014
+ "safety_contract": {
1015
+ "runs_bootstrap": False,
1016
+ "writes_registry": False,
1017
+ "writes_state_file": False,
1018
+ "creates_heartbeat": False,
1019
+ "spends_quota": False,
1020
+ "mutation_requires_user_confirmation": mutation_confirmation_required and not explicit_goal_start,
1021
+ "bare_command_mutation_requires_user_confirmation": mutation_confirmation_required,
1022
+ "explicit_goal_start_may_write_project_local_state": explicit_goal_start,
1023
+ "explicit_goal_start_must_activate_host_loop": explicit_goal_start,
1024
+ "host_loop_activation_allowed": activation_allowed,
1025
+ },
1026
+ }
1027
+ if normalized_thread_id:
1028
+ payload["thread_id"] = normalized_thread_id
1029
+ payload["thread_agent_binding"] = thread_binding_projection
1030
+ if new_peer:
1031
+ payload["new_peer"] = True
1032
+ payload["message"] = render_loopx_bootstrap_command_pack_message(payload)
1033
+ payload["packet_summary"] = _build_packet_summary(
1034
+ payload,
1035
+ packet_kind="bootstrap_command_pack",
1036
+ detail_refs={
1037
+ "project_connection": "#/project_connection",
1038
+ "host_loop_activation": "#/host_loop_activation",
1039
+ "recommended_next_step": "#/recommended_next_step",
1040
+ "goal_start_contract": "#/goal_start_contract",
1041
+ "commands": "#/commands",
1042
+ "safety_contract": "#/safety_contract",
1043
+ "compatibility_message": "#/message",
1044
+ },
1045
+ )
1046
+ return payload
1047
+
1048
+
1049
+ def _build_multi_goal_start_selection_packet(
1050
+ *,
1051
+ project: Path,
1052
+ agent_id: str | None,
1053
+ thread_id: str | None,
1054
+ new_peer: bool,
1055
+ cli_bin: str,
1056
+ host_surface: str,
1057
+ goal_text: str,
1058
+ available_capabilities: list[str] | None,
1059
+ capability_route: str | None,
1060
+ fine_grained: bool,
1061
+ include_command_pack_detail: bool,
1062
+ ) -> dict[str, Any] | None:
1063
+ inspection = inspect_bootstrap_connection(
1064
+ project,
1065
+ resolve_linked_worktree_alias=False,
1066
+ )
1067
+ registry_path = Path(str(inspection.get("registry") or ""))
1068
+ registry, registry_error = _read_registry(registry_path)
1069
+ if registry_error or not registry:
1070
+ return None
1071
+ goals = registry_goals(registry)
1072
+ if len(goals) <= 1:
1073
+ return None
1074
+
1075
+ normalized_goal_text = " ".join(goal_text.split())
1076
+ normalized_thread_id = normalize_thread_id(thread_id)
1077
+ resolved_project = str(inspection["project"])
1078
+ issue_fix_commands = build_issue_fix_goal_command_templates(
1079
+ cli_bin=cli_bin,
1080
+ goal_id="<selected-goal-id>",
1081
+ )
1082
+ choices: list[dict[str, Any]] = []
1083
+ for goal in goals:
1084
+ candidate_goal_id = str(goal.get("id") or "").strip()
1085
+ if not candidate_goal_id:
1086
+ continue
1087
+ rerun_command = (
1088
+ f"{shell_arg(cli_bin)} start-goal --guided "
1089
+ f"--project {shell_arg(resolved_project)} "
1090
+ f"--goal-id {shell_arg(candidate_goal_id)}"
1091
+ + (f" --agent-id {shell_arg(agent_id)}" if agent_id else "")
1092
+ + (
1093
+ f" --thread-id {shell_arg(normalized_thread_id)}"
1094
+ if normalized_thread_id
1095
+ else ""
1096
+ )
1097
+ + (" --new-peer" if new_peer else "")
1098
+ + f" --host-surface {shell_arg(host_surface)}"
1099
+ + render_available_capability_args(available_capabilities)
1100
+ + (" --fine-grained" if fine_grained else "")
1101
+ + (
1102
+ f" --capability-route {shell_arg(capability_route)}"
1103
+ if capability_route
1104
+ else ""
1105
+ )
1106
+ + f" --goal-text {shell_arg(normalized_goal_text)}"
1107
+ )
1108
+ choices.append(
1109
+ {
1110
+ "goal_id": candidate_goal_id,
1111
+ "status": goal.get("status"),
1112
+ "state_file": goal.get("state_file"),
1113
+ "registered_agents": registered_agent_ids_for_goal(goal),
1114
+ "rerun_command": rerun_command,
1115
+ }
1116
+ )
1117
+
1118
+ reason = (
1119
+ "multiple registered goals exist for this project; select one explicitly before "
1120
+ "planning todos, registering an agent, or activating a host loop"
1121
+ )
1122
+ goal_selection_gate = {
1123
+ "schema_version": "loopx_goal_selection_gate_v0",
1124
+ "state": "selection_required",
1125
+ "action_required": True,
1126
+ "reason": reason,
1127
+ "required_cli_arg": "--goal-id <registered-goal-id>",
1128
+ "choices": choices,
1129
+ }
1130
+ connection = {
1131
+ **inspection,
1132
+ "goal_id": None,
1133
+ "goal_found": False,
1134
+ "state_file": None,
1135
+ "state_file_exists": None,
1136
+ "known_goal_ids": [choice["goal_id"] for choice in choices],
1137
+ "connection_state": "goal_selection_required",
1138
+ "mutation_confirmation_required": False,
1139
+ "reason": reason,
1140
+ }
1141
+ recommended_next_step = {
1142
+ "kind": "select_goal",
1143
+ "requires_user_confirmation": False,
1144
+ "requires_goal_selection": True,
1145
+ "summary": reason,
1146
+ "goal_selection_gate": goal_selection_gate,
1147
+ }
1148
+ slash_command_catalog = build_slash_command_catalog(cli_bin=cli_bin)
1149
+ command_pack: dict[str, Any] = {
1150
+ "ok": True,
1151
+ "schema_version": SCHEMA_VERSION,
1152
+ "slash_command": CANONICAL_SLASH_COMMAND,
1153
+ "slash_forms": [
1154
+ {"form": "/loopx", "mode": "inspect_or_connect_preview"},
1155
+ {"form": "/loopx <goal text>", "mode": "goal_plan_write_and_activate"},
1156
+ ],
1157
+ "canonical_cli_command": None,
1158
+ "read_only": True,
1159
+ "goal_text": normalized_goal_text,
1160
+ "project": resolved_project,
1161
+ "goal_id": None,
1162
+ "agent_id": None,
1163
+ "requested_agent_id": agent_id,
1164
+ "agent_type": agent_type_for_host_surface(host_surface),
1165
+ "host_surface": host_surface,
1166
+ "project_connection": connection,
1167
+ "goal_selection_gate": goal_selection_gate,
1168
+ "host_loop_activation": {
1169
+ "activation_state": "goal_selection_required",
1170
+ "activation_allowed": False,
1171
+ "activation_required_after_todo_write": False,
1172
+ },
1173
+ "available_slash_commands": slash_command_catalog,
1174
+ "onboarding_hint": slash_command_catalog["onboarding"],
1175
+ "recommended_next_step": recommended_next_step,
1176
+ "goal_start_contract": build_goal_start_contract(
1177
+ goal_text=normalized_goal_text,
1178
+ selected_capability_route=_selected_goal_capability_route(
1179
+ capability_route
1180
+ ),
1181
+ connected=True,
1182
+ agent_type=agent_type_for_host_surface(host_surface),
1183
+ issue_fix_commands=issue_fix_commands,
1184
+ fine_grained=fine_grained,
1185
+ ),
1186
+ "commands": {
1187
+ "doctor": f"{shell_arg(cli_bin)} doctor",
1188
+ "status": _project_command(resolved_project, f"{shell_arg(cli_bin)} status"),
1189
+ "goal_selection_choices": choices,
1190
+ },
1191
+ "safety_contract": {
1192
+ "runs_bootstrap": False,
1193
+ "writes_registry": False,
1194
+ "writes_state_file": False,
1195
+ "creates_heartbeat": False,
1196
+ "spends_quota": False,
1197
+ "explicit_goal_start_may_write_project_local_state": False,
1198
+ "explicit_goal_start_must_activate_host_loop": False,
1199
+ "host_loop_activation_allowed": False,
1200
+ },
1201
+ }
1202
+ command_pack["message"] = (
1203
+ f"{reason}. Rerun exactly one goal_selection_gate choice; no mutation or host-loop "
1204
+ "command is valid before that selection."
1205
+ )
1206
+ command_pack["packet_summary"] = _build_packet_summary(
1207
+ command_pack,
1208
+ packet_kind="bootstrap_command_pack",
1209
+ detail_refs={
1210
+ "project_connection": "#/project_connection",
1211
+ "goal_selection_gate": "#/goal_selection_gate",
1212
+ "recommended_next_step": "#/recommended_next_step",
1213
+ "commands": "#/commands",
1214
+ "safety_contract": "#/safety_contract",
1215
+ "compatibility_message": "#/message",
1216
+ },
1217
+ )
1218
+ guided_transaction = {
1219
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
1220
+ "mode": "dry_run_preview",
1221
+ "writes_now": False,
1222
+ "spends_quota_now": False,
1223
+ "command_cwd_source": "#/project",
1224
+ "goal_text": normalized_goal_text,
1225
+ "blocked_by": "goal_selection",
1226
+ "goal_selection_gate": goal_selection_gate,
1227
+ "ordered_steps": [
1228
+ {
1229
+ "id": "inspect_connection",
1230
+ "kind": "read_only",
1231
+ "purpose": "inspect the requested project route and discover registered goals",
1232
+ },
1233
+ {
1234
+ "id": "select_goal",
1235
+ "kind": "goal_selection_gate",
1236
+ "choices": choices,
1237
+ "purpose": "select one registered goal before any todo, agent, state, or host-loop mutation",
1238
+ },
1239
+ ],
1240
+ "idempotency_policy": {
1241
+ "safe_to_rerun_preview": True,
1242
+ "reuse_connected_goal": True,
1243
+ },
1244
+ "preserve_todos_policy": {
1245
+ "force_bootstrap_default": "forbidden_in_guided_flow",
1246
+ "before_destructive_reconnect": "run backup-state and stop for an explicit preserve-todos confirmation",
1247
+ "preferred_scope_change": "use configure-goal incremental updates instead of force bootstrap when state already exists",
1248
+ },
1249
+ }
1250
+ detail_command = _start_goal_detail_command(
1251
+ project=resolved_project,
1252
+ goal_id=None,
1253
+ agent_id=agent_id,
1254
+ thread_id=thread_id,
1255
+ new_peer=new_peer,
1256
+ cli_bin=cli_bin,
1257
+ host_surface=host_surface,
1258
+ goal_text=normalized_goal_text,
1259
+ available_capabilities=available_capabilities,
1260
+ capability_route=capability_route,
1261
+ fine_grained=fine_grained,
1262
+ )
1263
+ selected_command_pack = (
1264
+ command_pack
1265
+ if include_command_pack_detail
1266
+ else _guided_command_pack_projection(
1267
+ command_pack,
1268
+ detail_command=detail_command,
1269
+ )
1270
+ )
1271
+ payload: dict[str, Any] = {
1272
+ "ok": True,
1273
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
1274
+ "read_only": True,
1275
+ "guided": True,
1276
+ "project": resolved_project,
1277
+ "goal_id": None,
1278
+ "agent_id": None,
1279
+ "host_surface": host_surface,
1280
+ "goal_text": normalized_goal_text,
1281
+ "project_connection": connection,
1282
+ "goal_selection_gate": goal_selection_gate,
1283
+ "recommended_next_step": recommended_next_step,
1284
+ "guided_transaction": guided_transaction,
1285
+ "command_pack": selected_command_pack,
1286
+ "command_pack_detail_included": include_command_pack_detail,
1287
+ "safety_contract": {
1288
+ "writes_registry": False,
1289
+ "writes_state_file": False,
1290
+ "creates_heartbeat": False,
1291
+ "spends_quota": False,
1292
+ "mutation_commands_are_previewed": False,
1293
+ "force_bootstrap_allowed": False,
1294
+ },
1295
+ }
1296
+ payload["message"] = render_start_goal_guided_markdown(payload)
1297
+ payload["packet_summary"] = _build_packet_summary(
1298
+ payload,
1299
+ packet_kind="guided_start_goal",
1300
+ detail_refs={
1301
+ "command_pack_summary": "#/command_pack/packet_summary",
1302
+ "project_connection": "#/project_connection",
1303
+ "goal_selection_gate": "#/goal_selection_gate",
1304
+ "recommended_next_step": "#/recommended_next_step",
1305
+ "guided_transaction": "#/guided_transaction",
1306
+ "commands": "#/guided_transaction/ordered_steps",
1307
+ "safety_contract": "#/safety_contract",
1308
+ "compatibility_message": "#/message",
1309
+ },
1310
+ legacy_fields_retained=include_command_pack_detail,
1311
+ compact_projection_default=not include_command_pack_detail,
1312
+ )
1313
+ return payload
1314
+
1315
+
1316
+ def build_start_goal_guided_packet(
1317
+ *,
1318
+ project: Path,
1319
+ goal_id: str | None,
1320
+ agent_id: str | None,
1321
+ cli_bin: str,
1322
+ host_surface: str,
1323
+ goal_text: str,
1324
+ thread_id: str | None = None,
1325
+ new_peer: bool = False,
1326
+ available_capabilities: list[str] | None = None,
1327
+ capability_route: str | None = None,
1328
+ fine_grained: bool = False,
1329
+ include_command_pack_detail: bool = False,
1330
+ ) -> dict[str, Any]:
1331
+ if goal_id is None:
1332
+ selection_packet = _build_multi_goal_start_selection_packet(
1333
+ project=project,
1334
+ agent_id=agent_id,
1335
+ thread_id=thread_id,
1336
+ new_peer=new_peer,
1337
+ cli_bin=cli_bin,
1338
+ host_surface=host_surface,
1339
+ goal_text=goal_text,
1340
+ available_capabilities=available_capabilities,
1341
+ capability_route=capability_route,
1342
+ fine_grained=fine_grained,
1343
+ include_command_pack_detail=include_command_pack_detail,
1344
+ )
1345
+ if selection_packet is not None:
1346
+ return selection_packet
1347
+ command_pack = build_loopx_bootstrap_command_pack(
1348
+ project=project,
1349
+ goal_id=goal_id,
1350
+ agent_id=agent_id,
1351
+ thread_id=thread_id,
1352
+ new_peer=new_peer,
1353
+ cli_bin=cli_bin,
1354
+ host_surface=host_surface,
1355
+ goal_text=goal_text,
1356
+ available_capabilities=available_capabilities,
1357
+ capability_route=capability_route,
1358
+ fine_grained=fine_grained,
1359
+ resolve_linked_worktree_alias=False,
1360
+ )
1361
+ commands = command_pack.get("commands")
1362
+ commands = commands if isinstance(commands, dict) else {}
1363
+ activation = command_pack.get("host_loop_activation")
1364
+ activation = activation if isinstance(activation, dict) else {}
1365
+ identity_selection_gate = activation.get("identity_selection_gate")
1366
+ if isinstance(identity_selection_gate, dict):
1367
+ def rerun_start_goal(selected_agent_id: str) -> str:
1368
+ return _start_goal_command(
1369
+ project=str(command_pack.get("project") or project),
1370
+ goal_id=str(command_pack.get("goal_id") or "") or None,
1371
+ agent_id=selected_agent_id,
1372
+ thread_id=thread_id,
1373
+ new_peer=new_peer,
1374
+ cli_bin=cli_bin,
1375
+ host_surface=host_surface,
1376
+ goal_text=str(command_pack.get("goal_text") or goal_text),
1377
+ available_capabilities=available_capabilities,
1378
+ capability_route=capability_route,
1379
+ fine_grained=fine_grained,
1380
+ include_command_pack_detail=False,
1381
+ )
1382
+
1383
+ fresh_registration = identity_selection_gate.get("fresh_agent_registration")
1384
+ if isinstance(fresh_registration, dict):
1385
+ fresh_agent_id = str(
1386
+ fresh_registration.get("agent_id") or "<new-public-safe-agent-id>"
1387
+ )
1388
+ fresh_registration["connect_if_needed_command"] = commands.get(
1389
+ "goal_start_connect_if_needed"
1390
+ )
1391
+ fresh_registration["rerun_start_goal_command"] = rerun_start_goal(
1392
+ fresh_agent_id
1393
+ )
1394
+ for choice in identity_selection_gate.get("choices") or []:
1395
+ if not isinstance(choice, dict) or not choice.get("agent_id"):
1396
+ continue
1397
+ choice["rerun_start_goal_command"] = rerun_start_goal(
1398
+ str(choice["agent_id"])
1399
+ )
1400
+ goal_start_contract = command_pack.get("goal_start_contract")
1401
+ goal_start_contract = (
1402
+ goal_start_contract if isinstance(goal_start_contract, dict) else {}
1403
+ )
1404
+ selected_capability_route = goal_start_contract.get("selected_capability_route")
1405
+ selected_capability_route = (
1406
+ selected_capability_route
1407
+ if isinstance(selected_capability_route, dict)
1408
+ else None
1409
+ )
1410
+ scheduler_ack_steps = (
1411
+ [
1412
+ {
1413
+ "id": "scheduler_ack_when_needed",
1414
+ "kind": "scheduler_state",
1415
+ "command_source": "quota.should-run.scheduler_hint.codex_app.ack_hint.cli_args",
1416
+ "purpose": "ack an applied Codex App RRULE without spending quota",
1417
+ }
1418
+ ]
1419
+ if host_surface == "codex-app"
1420
+ else []
1421
+ )
1422
+ bind_thread_steps = (
1423
+ [
1424
+ {
1425
+ "id": "bind_thread_identity",
1426
+ "kind": "identity_mutation",
1427
+ "command": commands.get("goal_start_bind_thread"),
1428
+ "purpose": "bind thread; verify readback before Todo writeback",
1429
+ "must_stop_on_failure": True,
1430
+ "result_contract": {
1431
+ "schema_version": "loopx_thread_agent_binding_continuation_v0",
1432
+ "required_result": {
1433
+ "ok": True,
1434
+ "global_sync": {"ok": True},
1435
+ "registration_readback": {"verified": True},
1436
+ },
1437
+ },
1438
+ }
1439
+ ]
1440
+ if commands.get("goal_start_bind_thread")
1441
+ else []
1442
+ )
1443
+ fine_mode_steps = (
1444
+ [
1445
+ {
1446
+ "id": "configure_fine_grained_turn_mode",
1447
+ "kind": "conditional_mutation",
1448
+ "command": commands.get("goal_start_configure_turn_granularity"),
1449
+ "purpose": (
1450
+ "persist fine turn granularity for new or already-connected goals "
1451
+ "before planning and heartbeat activation"
1452
+ ),
1453
+ }
1454
+ ]
1455
+ if fine_grained
1456
+ else []
1457
+ )
1458
+ guided_transaction = {
1459
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
1460
+ "mode": "dry_run_preview",
1461
+ "writes_now": False,
1462
+ "spends_quota_now": False,
1463
+ "command_cwd_source": "#/project",
1464
+ **(
1465
+ {
1466
+ "checkpoint_policy": {
1467
+ "task_frontier": "agent_advancement_todos_only",
1468
+ "protocol_step_todo_projection": "forbidden",
1469
+ "protocol_step_advancement_checkpoint": False,
1470
+ "protocol_step_turn_settlement": False,
1471
+ "settlement": "once_after_task_facing_slice",
1472
+ }
1473
+ }
1474
+ if fine_grained
1475
+ else {}
1476
+ ),
1477
+ "ordered_steps": [
1478
+ {
1479
+ "id": "inspect_connection",
1480
+ "kind": "read_only",
1481
+ "command_source": "#/command_pack/canonical_cli_command",
1482
+ "purpose": "resolve the requested project route, goal id, registry, and active state before any mutation",
1483
+ },
1484
+ {
1485
+ "id": "connect_if_needed",
1486
+ "kind": "conditional_mutation",
1487
+ "command": commands.get("goal_start_connect_if_needed"),
1488
+ "purpose": "create or reuse project-local LoopX state only when no matching goal exists",
1489
+ },
1490
+ *bind_thread_steps,
1491
+ *fine_mode_steps,
1492
+ {
1493
+ "id": "plan_ranked_todos",
1494
+ "kind": "model_checkpoint",
1495
+ "prompt": commands.get("goal_start_plan_prompt"),
1496
+ "purpose": (
1497
+ "produce one public-safe, small, verifiable checkpoint Todo; keep "
1498
+ "later options as evidence-linked planning notes"
1499
+ if fine_grained
1500
+ else "produce concise public-safe P0/P1/P2 todos before todo writeback"
1501
+ ),
1502
+ },
1503
+ {
1504
+ "id": "write_ordered_todos",
1505
+ "kind": "operator_or_agent_actions",
1506
+ "command_template": (
1507
+ f"{shell_arg(cli_bin)} todo add --goal-id "
1508
+ f"{shell_arg(str(command_pack.get('goal_id') or ''))} "
1509
+ "--project . "
1510
+ "--role agent "
1511
+ + (
1512
+ f"--claimed-by {shell_arg(str(command_pack.get('agent_id') or ''))} "
1513
+ if command_pack.get("agent_id")
1514
+ else "--claimed-by <agent-id> "
1515
+ )
1516
+ + "--task-class advancement_task --action-kind <action_kind> "
1517
+ "[--target-key <target_key>] --text '<[P0/P1/P2] ...>'"
1518
+ ),
1519
+ "purpose": (
1520
+ "write only the current checkpoint Todo; the existing replan path "
1521
+ "qualifies any successor after completion evidence"
1522
+ if fine_grained
1523
+ else "write todos in planner order; capability successors preserve "
1524
+ "the admitted action_kind and target_key for later quota re-entry"
1525
+ ),
1526
+ },
1527
+ {
1528
+ "id": "refresh_state",
1529
+ "kind": "state_sync",
1530
+ "command": commands.get("goal_start_refresh_state"),
1531
+ "purpose": "project the accepted plan and next action into active state/history",
1532
+ },
1533
+ {
1534
+ "id": "activate_host_loop",
1535
+ "kind": "identity_gate" if identity_selection_gate else "host_loop",
1536
+ "command": commands.get("goal_start_host_loop_activation"),
1537
+ "purpose": "install or refresh the host loop only when it is missing, unknown, stale, or agent type changed",
1538
+ },
1539
+ {
1540
+ "id": "quota_guard",
1541
+ "kind": "guard",
1542
+ "command": commands.get("goal_start_quota_should_run"),
1543
+ "purpose": "let LoopX choose the first bounded segment and scheduler cadence",
1544
+ },
1545
+ *scheduler_ack_steps,
1546
+ ],
1547
+ "idempotency_policy": {
1548
+ "safe_to_rerun_preview": True,
1549
+ "reuse_connected_goal": True,
1550
+ "do_not_duplicate_existing_todos": (
1551
+ "Do not duplicate existing todos; before writing, compare active todos by text/action_kind "
1552
+ "and update or skip matching items."
1553
+ ),
1554
+ "host_loop_recheck": (
1555
+ "Only regenerate or update automation when the host loop is missing, unknown, stale, or agent type changed."
1556
+ ),
1557
+ },
1558
+ "preserve_todos_policy": {
1559
+ "force_bootstrap_default": "forbidden_in_guided_flow",
1560
+ "before_destructive_reconnect": "run backup-state and stop for an explicit preserve-todos confirmation",
1561
+ "preferred_scope_change": "use configure-goal incremental updates instead of force bootstrap when state already exists",
1562
+ },
1563
+ }
1564
+ if isinstance(identity_selection_gate, dict):
1565
+ guided_transaction["blocked_by"] = "agent_identity_selection"
1566
+ guided_transaction["identity_selection_gate"] = identity_selection_gate
1567
+ guided_transaction["ordered_steps"].insert(
1568
+ 2,
1569
+ {
1570
+ "id": "select_agent_identity",
1571
+ "kind": "identity_gate",
1572
+ "default_action": identity_selection_gate.get("default_action"),
1573
+ "fresh_agent_registration": identity_selection_gate.get(
1574
+ "fresh_agent_registration"
1575
+ ),
1576
+ "choices": identity_selection_gate.get("choices") or [],
1577
+ "purpose": (
1578
+ "register a fresh identity by default for a stable unbound host "
1579
+ "session; select an existing identity only for explicit takeover"
1580
+ ),
1581
+ },
1582
+ )
1583
+ if selected_capability_route is not None:
1584
+ entry_key = str(selected_capability_route["entry_command_key"])
1585
+ admission_key = str(selected_capability_route["admission_command_key"])
1586
+ guided_transaction["ordered_steps"].insert(
1587
+ 3 if isinstance(identity_selection_gate, dict) else 2,
1588
+ {
1589
+ "id": "qualify_selected_capability",
1590
+ "kind": "capability_guard",
1591
+ "candidate_discovery_command_template": (
1592
+ ISSUE_FIX_GOAL_CANDIDATE_DISCOVERY_COMMAND_TEMPLATE
1593
+ ),
1594
+ "candidate_authority": selected_capability_route[
1595
+ "candidate_authority"
1596
+ ],
1597
+ "authority_refresh_required": selected_capability_route[
1598
+ "authority_refresh_required"
1599
+ ],
1600
+ "candidate_preflight": selected_capability_route[
1601
+ "candidate_preflight"
1602
+ ],
1603
+ "command_source": f"#/command_pack/commands/{entry_key}",
1604
+ "admission_command_source": (
1605
+ f"#/command_pack/commands/{admission_key}"
1606
+ ),
1607
+ "activation_condition": selected_capability_route[
1608
+ "activation_condition"
1609
+ ],
1610
+ "durable_successor_sources": {
1611
+ "proceed": "admission_result.transition.projected_todo",
1612
+ "non_proceed": (
1613
+ "entry_result.ordered_loopx_todo_writeback_preview"
1614
+ ),
1615
+ },
1616
+ "completion_condition": (
1617
+ "persist candidate preflight; for proceed, persist feasibility "
1618
+ "and write its exact successor Todo; for non-proceed, write the "
1619
+ "preflight successor or record no-follow-up"
1620
+ ),
1621
+ "when_condition_unmet": (
1622
+ "keep candidate discovery or qualification as a normal Todo, "
1623
+ "then re-enter this guard after selecting a public candidate"
1624
+ ),
1625
+ "purpose": (
1626
+ "select public issue authority and persist capability-owned "
1627
+ "qualification before planning implementation"
1628
+ ),
1629
+ }
1630
+ )
1631
+ guided_transaction["selected_capability_route"] = selected_capability_route
1632
+ detail_command = _start_goal_detail_command(
1633
+ project=str(command_pack.get("project") or project),
1634
+ goal_id=str(command_pack.get("goal_id") or "") or None,
1635
+ agent_id=str(command_pack.get("agent_id") or "") or None,
1636
+ thread_id=thread_id,
1637
+ new_peer=new_peer,
1638
+ cli_bin=cli_bin,
1639
+ host_surface=host_surface,
1640
+ goal_text=str(command_pack.get("goal_text") or goal_text),
1641
+ available_capabilities=available_capabilities,
1642
+ capability_route=capability_route,
1643
+ fine_grained=fine_grained,
1644
+ )
1645
+ selected_command_pack = (
1646
+ command_pack
1647
+ if include_command_pack_detail
1648
+ else _guided_command_pack_projection(
1649
+ command_pack,
1650
+ detail_command=detail_command,
1651
+ )
1652
+ )
1653
+ payload = {
1654
+ "ok": True,
1655
+ "schema_version": GUIDED_START_SCHEMA_VERSION,
1656
+ "read_only": True,
1657
+ "guided": True,
1658
+ "project": command_pack.get("project"),
1659
+ "goal_id": command_pack.get("goal_id"),
1660
+ "agent_id": command_pack.get("agent_id"),
1661
+ "host_surface": command_pack.get("host_surface"),
1662
+ "goal_text": command_pack.get("goal_text"),
1663
+ "project_connection": command_pack.get("project_connection"),
1664
+ "recommended_next_step": command_pack.get("recommended_next_step"),
1665
+ "guided_transaction": guided_transaction,
1666
+ "command_pack": selected_command_pack,
1667
+ "command_pack_detail_included": include_command_pack_detail,
1668
+ "safety_contract": {
1669
+ "writes_registry": False,
1670
+ "writes_state_file": False,
1671
+ "creates_heartbeat": False,
1672
+ "spends_quota": False,
1673
+ "mutation_commands_are_previewed": True,
1674
+ "force_bootstrap_allowed": False,
1675
+ },
1676
+ }
1677
+ if command_pack.get("thread_id"):
1678
+ payload["thread_id"] = command_pack["thread_id"]
1679
+ payload["thread_agent_binding"] = command_pack.get("thread_agent_binding")
1680
+ if command_pack.get("new_peer"):
1681
+ payload["new_peer"] = True
1682
+ payload["message"] = render_start_goal_guided_markdown(payload)
1683
+ payload["packet_summary"] = _build_packet_summary(
1684
+ payload,
1685
+ packet_kind="guided_start_goal",
1686
+ detail_refs={
1687
+ "command_pack_summary": "#/command_pack/packet_summary",
1688
+ "project_connection": "#/project_connection",
1689
+ "recommended_next_step": "#/recommended_next_step",
1690
+ "guided_transaction": "#/guided_transaction",
1691
+ "commands": "#/guided_transaction/ordered_steps",
1692
+ "safety_contract": "#/safety_contract",
1693
+ "compatibility_message": "#/message",
1694
+ },
1695
+ legacy_fields_retained=include_command_pack_detail,
1696
+ compact_projection_default=not include_command_pack_detail,
1697
+ )
1698
+ return payload
1699
+
1700
+
1701
+ def render_start_goal_guided_markdown(payload: dict[str, Any]) -> str:
1702
+ def command_summary(value: Any) -> str:
1703
+ parts = str(value or "").split()
1704
+ return " ".join(parts[:3]) + (" ..." if len(parts) > 3 else "")
1705
+
1706
+ def actionable_shell_command(value: Any) -> str:
1707
+ lines = [
1708
+ line.removesuffix("\\").strip()
1709
+ for line in str(value or "").splitlines()
1710
+ if line.strip()
1711
+ ]
1712
+ if len(lines) > 1 and lines[0].startswith("cd "):
1713
+ return f"{lines[0]} && {' '.join(lines[1:])}"
1714
+ return " ".join(lines)
1715
+
1716
+ transaction = payload.get("guided_transaction")
1717
+ transaction = transaction if isinstance(transaction, dict) else {}
1718
+ command_pack = payload.get("command_pack")
1719
+ command_pack = command_pack if isinstance(command_pack, dict) else {}
1720
+ commands = command_pack.get("commands")
1721
+ commands = commands if isinstance(commands, dict) else {}
1722
+ selected_route = transaction.get("selected_capability_route")
1723
+ selected_route = selected_route if isinstance(selected_route, dict) else {}
1724
+ ordered_steps = transaction.get("ordered_steps")
1725
+ ordered_steps = ordered_steps if isinstance(ordered_steps, list) else []
1726
+ program = effect_program_from_ordered_steps(ordered_steps)
1727
+ step_lines: list[str] = []
1728
+ for index, step in enumerate(program.steps, start=1):
1729
+ raw_step = step.raw
1730
+ command = (
1731
+ step.command
1732
+ or raw_step.get("command_source")
1733
+ or raw_step.get("prompt")
1734
+ )
1735
+ if step.kind == "capability_guard":
1736
+ entry_key = str(selected_route.get("entry_command_key") or "")
1737
+ admission_key = str(selected_route.get("admission_command_key") or "")
1738
+ entry_command = commands.get(entry_key)
1739
+ admission_command = commands.get(admission_key)
1740
+ discovery_command = raw_step.get("candidate_discovery_command_template")
1741
+ authority = (
1742
+ "open public issue; source clues are evidence only"
1743
+ if raw_step.get("candidate_authority") == "public_open_tracker_issue"
1744
+ else raw_step.get("candidate_authority")
1745
+ )
1746
+ step_lines.extend(
1747
+ [
1748
+ f"{index}. `{step.step_id}` ({step.kind})",
1749
+ f" - authority: {authority}",
1750
+ ]
1751
+ )
1752
+ if discovery_command:
1753
+ step_lines.append(
1754
+ f" - discover: `{str(discovery_command).splitlines()[0]}`"
1755
+ )
1756
+ preflight = raw_step.get("candidate_preflight")
1757
+ if isinstance(preflight, dict):
1758
+ required_evidence = " + ".join(
1759
+ str(field)
1760
+ for field in preflight.get("required_evidence_fields") or []
1761
+ )
1762
+ step_lines.append(
1763
+ " - preflight: refresh "
1764
+ f"{raw_step.get('authority_refresh_required')}; "
1765
+ f"provide {required_evidence}; "
1766
+ f"{preflight.get('decision_rule')}"
1767
+ )
1768
+ step_lines.extend(
1769
+ [
1770
+ f" - qualify: `{command_summary(entry_command)}`",
1771
+ f" - proceed: `{command_summary(admission_command)}`",
1772
+ ]
1773
+ )
1774
+ continue
1775
+ step_label = f"{index}. `{step.step_id}` ({step.kind}): "
1776
+ step_lines.append(step_label + str(step.purpose))
1777
+ if command:
1778
+ rendered_command = (
1779
+ actionable_shell_command(command)
1780
+ if step.step_id == "connect_if_needed"
1781
+ else str(command).splitlines()[0]
1782
+ )
1783
+ step_lines.append(f" - command/source: `{rendered_command}`")
1784
+ preserve = transaction.get("preserve_todos_policy")
1785
+ preserve = preserve if isinstance(preserve, dict) else {}
1786
+ identity_gate = transaction.get("identity_selection_gate")
1787
+ identity_gate = identity_gate if isinstance(identity_gate, dict) else {}
1788
+ identity_gate_lines = ""
1789
+ if identity_gate:
1790
+ fresh_registration = identity_gate.get("fresh_agent_registration")
1791
+ fresh_lines = []
1792
+ if isinstance(fresh_registration, dict):
1793
+ fresh_lines = [
1794
+ "- **default: register a fresh agent**",
1795
+ f" - preview: `{fresh_registration.get('preview_command')}`",
1796
+ f" - apply: `{fresh_registration.get('execute_command')}`",
1797
+ (
1798
+ " - rerun: "
1799
+ f"`{fresh_registration.get('rerun_start_goal_command')}`"
1800
+ ),
1801
+ ]
1802
+ choices = [
1803
+ f"- explicit takeover `{choice.get('agent_id')}`: "
1804
+ f"`{choice.get('rerun_start_goal_command')}`"
1805
+ for choice in identity_gate.get("choices") or []
1806
+ if isinstance(choice, dict)
1807
+ ]
1808
+ identity_gate_lines = (
1809
+ "\n## Agent Identity Gate\n\n"
1810
+ f"{identity_gate.get('reason')}\n\n"
1811
+ + "\n".join([*fresh_lines, *choices])
1812
+ + "\n"
1813
+ )
1814
+ goal_gate = transaction.get("goal_selection_gate")
1815
+ goal_gate = goal_gate if isinstance(goal_gate, dict) else {}
1816
+ goal_gate_lines = ""
1817
+ if goal_gate:
1818
+ choices = [
1819
+ f"- `{choice.get('goal_id')}` status=`{choice.get('status')}`: "
1820
+ f"`{choice.get('rerun_command')}`"
1821
+ for choice in goal_gate.get("choices") or []
1822
+ if isinstance(choice, dict)
1823
+ ]
1824
+ goal_gate_lines = (
1825
+ "\n## Goal Selection Gate\n\n"
1826
+ f"{goal_gate.get('reason')}\n\n"
1827
+ + "\n".join(choices)
1828
+ + "\n"
1829
+ )
1830
+ host_gate = transaction.get("host_surface_selection_gate")
1831
+ host_gate = host_gate if isinstance(host_gate, dict) else {}
1832
+ host_gate_lines = ""
1833
+ if host_gate:
1834
+ choices = [
1835
+ f"- `{choice.get('host_surface')}`: {choice.get('description')} "
1836
+ f"\n `{choice.get('rerun_command')}`"
1837
+ for choice in host_gate.get("choices") or []
1838
+ if isinstance(choice, dict)
1839
+ ]
1840
+ host_gate_lines = (
1841
+ "\n## Host Surface Gate\n\n"
1842
+ f"{host_gate.get('reason')}\n\n"
1843
+ + "\n".join(choices)
1844
+ + "\n"
1845
+ )
1846
+ return f"""# Guided Start Goal
1847
+
1848
+ - project: `{payload.get("project")}`
1849
+ - goal_id: `{payload.get("goal_id")}`
1850
+ - goal_text: `{payload.get("goal_text")}`
1851
+
1852
+ Preview only; follow ordered commands to mutate.
1853
+
1854
+ ## Ordered Transaction
1855
+
1856
+ {chr(10).join(step_lines)}
1857
+ {host_gate_lines}
1858
+ {goal_gate_lines}
1859
+ {identity_gate_lines}
1860
+
1861
+ ## Todo Preservation
1862
+
1863
+ - bootstrap: `{preserve.get("force_bootstrap_default")}`; reconnect: {preserve.get("before_destructive_reconnect")}; scope change: {preserve.get("preferred_scope_change")}
1864
+ """
1865
+
1866
+
1867
+ def render_loopx_bootstrap_command_pack_message(payload: dict[str, Any]) -> str:
1868
+ connection = payload.get("project_connection")
1869
+ connection = connection if isinstance(connection, dict) else {}
1870
+ commands = payload.get("commands")
1871
+ commands = commands if isinstance(commands, dict) else {}
1872
+ next_step = payload.get("recommended_next_step")
1873
+ next_step = next_step if isinstance(next_step, dict) else {}
1874
+ requires_confirmation = bool(next_step.get("requires_user_confirmation"))
1875
+ project = payload.get("project")
1876
+ goal_id = payload.get("goal_id")
1877
+ goal_text = payload.get("goal_text")
1878
+ state = connection.get("connection_state")
1879
+ reason = connection.get("reason")
1880
+ alias = connection.get("canonical_project_alias")
1881
+ alias = alias if isinstance(alias, dict) else {}
1882
+ alias_note = (
1883
+ f"\nInput project: `{connection.get('input_project')}`\n"
1884
+ f"Canonical route: `{alias.get('canonical_project')}` via `{alias.get('source_registry')}`\n"
1885
+ if alias.get("applied")
1886
+ else ""
1887
+ )
1888
+ goal_start_contract = payload.get("goal_start_contract")
1889
+ goal_start_contract = goal_start_contract if isinstance(goal_start_contract, dict) else {}
1890
+ selected_capability_route = goal_start_contract.get(
1891
+ "selected_capability_route"
1892
+ )
1893
+ selected_capability_route = (
1894
+ selected_capability_route
1895
+ if isinstance(selected_capability_route, dict)
1896
+ else {}
1897
+ )
1898
+ issue_fix_action = ""
1899
+ if selected_capability_route.get("capability_id") == "issue-fix":
1900
+ issue_fix_action = f"""
1901
+
1902
+ The explicit capability route selects issue-fix. Preview its capability-owned admission:
1903
+
1904
+ ```bash
1905
+ {commands.get("issue_fix_workflow_plan_template", "")}
1906
+ ```
1907
+
1908
+ Persist candidate preflight. Non-proceed: write its successor/no-follow-up; skip feasibility. Proceed: run feasibility and write its successor:
1909
+
1910
+ ```bash
1911
+ {commands.get("issue_fix_feasibility_template", "")}
1912
+ ```
1913
+
1914
+ Private repro material, issue body/comment reads, external comments, PR creation, merge, publish, destructive git, and production actions stay explicit gates.
1915
+
1916
+ After a PR exists and external-review-request authority is active, request the default top requestable non-author reviewer and require post-write verification:
1917
+
1918
+ ```bash
1919
+ {commands.get("issue_fix_reviewer_request_template", "")}
1920
+ ```
1921
+
1922
+ After a PR exists, reconcile compact public PR state through the capability-owned lifecycle command:
1923
+
1924
+ ```bash
1925
+ {commands.get("issue_fix_pr_lifecycle_template", "")}
1926
+ ```"""
1927
+ onboarding = payload.get("onboarding_hint")
1928
+ onboarding = onboarding if isinstance(onboarding, dict) else {}
1929
+ activation = payload.get("host_loop_activation")
1930
+ activation = activation if isinstance(activation, dict) else {}
1931
+ identity_gate = activation.get("identity_selection_gate")
1932
+ identity_gate = identity_gate if isinstance(identity_gate, dict) else {}
1933
+
1934
+ if identity_gate:
1935
+ choices = "\n".join(
1936
+ f"- explicit takeover `{choice.get('agent_id')}`: rerun with "
1937
+ f"`--agent-id {choice.get('agent_id')}`"
1938
+ for choice in identity_gate.get("choices") or []
1939
+ if isinstance(choice, dict)
1940
+ )
1941
+ fresh_registration = identity_gate.get("fresh_agent_registration")
1942
+ fresh_registration = (
1943
+ fresh_registration if isinstance(fresh_registration, dict) else {}
1944
+ )
1945
+ if fresh_registration:
1946
+ action = f"""Resolve agent identity before planning writes or host-loop activation.
1947
+ No unscoped heartbeat or quota command is advertised for a new agent connection.
1948
+
1949
+ Reason: {identity_gate.get("reason")}
1950
+
1951
+ Default fresh-agent registration:
1952
+ ```bash
1953
+ {fresh_registration.get("preview_command") or ""}
1954
+ {fresh_registration.get("execute_command") or ""}
1955
+ ```
1956
+
1957
+ Only with explicit takeover intent, choose one existing identity:
1958
+ {choices}
1959
+
1960
+ Rerun `{payload.get("canonical_cli_command")} --agent-id <selected-agent-id>`
1961
+ after fresh registration or exact takeover selection before continuing."""
1962
+ else:
1963
+ action = f"""Select one registered agent lane before planning writes or host-loop activation.
1964
+ No unscoped heartbeat or quota command is advertised for this multi-agent goal.
1965
+
1966
+ Reason: {identity_gate.get("reason")}
1967
+
1968
+ Identity-aware choices:
1969
+ {choices}
1970
+
1971
+ Rerun `{payload.get("canonical_cli_command")} --agent-id <registered-agent-id>`
1972
+ with the selected identity before continuing."""
1973
+ elif goal_text:
1974
+ action = f"""This is an explicit goal-start invocation. Connect project-local LoopX state if needed:
1975
+
1976
+ ```bash
1977
+ {commands.get("goal_start_connect_if_needed", "")}
1978
+ ```
1979
+
1980
+ Then plan before writing todos. Preserve relative priority by write order:
1981
+
1982
+ ````text
1983
+ {commands.get("goal_start_plan_prompt", "")}
1984
+ ````
1985
+
1986
+ Write the planned todos with `loopx todo add` in the exact planned order. Same-priority items use that write order as the tie-breaker.
1987
+ {issue_fix_action}
1988
+
1989
+ After todo writeback:
1990
+
1991
+ ```bash
1992
+ {commands.get("goal_start_refresh_state", "")}
1993
+ {commands.get("goal_start_host_loop_activation", "")}
1994
+ {commands.get("goal_start_quota_should_run", "")}
1995
+ ```
1996
+
1997
+ Host loop activation is part of setup, not a nice-to-have:
1998
+ - agent_type: `{payload.get("agent_type")}`
1999
+ - host_surface: `{activation.get("host_surface")}`
2000
+ - activation_method: `{activation.get("activation_method")}`
2001
+
2002
+ If the host loop is already proven current, skip the mutation. If it is missing,
2003
+ unknown, or stale, use the command above to obtain `task_body` and activate the
2004
+ right host loop: Codex App automation, Codex CLI `/goal <task_body>`, Claude
2005
+ Code `/loop`, OpenCode bridge, or the custom host-loop gate.
2006
+ If this session cannot mutate that
2007
+ host surface, report the exact gate; do not claim autonomous setup complete.
2008
+ Use `{commands.get("goal_start_agent_onboard_recheck", "")}` only when
2009
+ activation state is missing/unknown/stale or the agent type changed."""
2010
+ elif requires_confirmation:
2011
+ action = f"""First show this dry-run preview, then ask me before running the mutation:
2012
+
2013
+ ```bash
2014
+ {commands.get("bootstrap_dry_run_preview", "")}
2015
+ ```
2016
+
2017
+ If I confirm, run:
2018
+
2019
+ ```bash
2020
+ {commands.get("bootstrap_after_user_confirmation", "")}
2021
+ ```"""
2022
+ else:
2023
+ action = f"""Start with the current LoopX status and do not reconnect:
2024
+
2025
+ ```bash
2026
+ {commands.get("status", "")}
2027
+ ```
2028
+
2029
+ Only after I ask for a recurring loop surface, generate the heartbeat body:
2030
+
2031
+ ```bash
2032
+ {commands.get("heartbeat_prompt", "")}
2033
+ ```"""
2034
+
2035
+ return f"""Handle `{CANONICAL_SLASH_COMMAND}` for this project with explicit mutation boundaries.
2036
+
2037
+ Project: `{project}`
2038
+ Goal id: `{goal_id}`
2039
+ Detected state: `{state}` ({reason})
2040
+ {alias_note}
2041
+
2042
+ Rules:
2043
+ - This command pack preview is read-only. Do not run bootstrap/connect, create heartbeat automation, or spend quota while only previewing it.
2044
+ - Bare `/loopx` is read/status-first: if the project is not fully connected, ask for explicit user confirmation before any command that writes `.loopx/` or `.codex/goals/`.
2045
+ - `/loopx <goal text>` is explicit goal-start intent: it may create project-local LoopX state, but it must run the profile-appropriate planning checkpoint before writing todos, then activate the correct host loop if missing/stale.
2046
+ - Same-priority todos are ranked by planner order, then by `todo add` write order; preserve the order exactly.
2047
+ - If the project is connected, reuse the existing state and show the status/gate/todo snapshot.
2048
+
2049
+ Goal-start contract: `{goal_start_contract.get("schema_version")}`
2050
+
2051
+ Suggested new-user note:
2052
+
2053
+ ```text
2054
+ {onboarding.get("suggested_user_note", "")}
2055
+ ```
2056
+
2057
+ {action}
2058
+
2059
+ For ongoing work after the project is connected, use the quota guard:
2060
+
2061
+ ```bash
2062
+ {commands.get("quota_guard", "")}
2063
+ ```
2064
+ """
2065
+
2066
+
2067
+ def render_loopx_bootstrap_command_pack_markdown(payload: dict[str, Any]) -> str:
2068
+ connection = payload.get("project_connection")
2069
+ connection = connection if isinstance(connection, dict) else {}
2070
+ next_step = payload.get("recommended_next_step")
2071
+ next_step = next_step if isinstance(next_step, dict) else {}
2072
+ safety = payload.get("safety_contract")
2073
+ safety = safety if isinstance(safety, dict) else {}
2074
+ commands = payload.get("commands")
2075
+ commands = commands if isinstance(commands, dict) else {}
2076
+ onboarding = payload.get("onboarding_hint")
2077
+ onboarding = onboarding if isinstance(onboarding, dict) else {}
2078
+ slash_catalog = payload.get("available_slash_commands")
2079
+ slash_catalog = slash_catalog if isinstance(slash_catalog, dict) else {}
2080
+ goal_start = payload.get("goal_start_contract")
2081
+ goal_start = goal_start if isinstance(goal_start, dict) else {}
2082
+ activation = payload.get("host_loop_activation")
2083
+ activation = activation if isinstance(activation, dict) else {}
2084
+ ordering = goal_start.get("priority_ordering")
2085
+ ordering = ordering if isinstance(ordering, dict) else {}
2086
+ return f"""# /loopx Bootstrap Command Pack
2087
+
2088
+ Canonical slash command: `{payload.get("slash_command")}`
2089
+ Supported forms: `/loopx`, `/loopx <goal text>`
2090
+
2091
+ ## Detected Project State
2092
+
2093
+ - project: `{payload.get("project")}`
2094
+ - input_project: `{connection.get("input_project")}`
2095
+ - goal_id: `{payload.get("goal_id")}`
2096
+ - agent_type: `{payload.get("agent_type")}`
2097
+ - goal_text: `{payload.get("goal_text") or ""}`
2098
+ - connection_state: `{connection.get("connection_state")}`
2099
+ - reason: `{connection.get("reason")}`
2100
+ - registry: `{connection.get("registry")}`
2101
+ - state_file: `{connection.get("state_file")}`
2102
+ - canonical_project_alias: `{(connection.get("canonical_project_alias") or {}).get("kind") if isinstance(connection.get("canonical_project_alias"), dict) else None}`
2103
+
2104
+ ## Recommended Next Step
2105
+
2106
+ - kind: `{next_step.get("kind")}`
2107
+ - requires_user_confirmation: `{next_step.get("requires_user_confirmation")}`
2108
+ - summary: {next_step.get("summary")}
2109
+
2110
+ ## New User Command Hint
2111
+
2112
+ ````text
2113
+ {onboarding.get("suggested_user_note", "")}
2114
+ ````
2115
+
2116
+ - CLI help: `{(slash_catalog.get("help") or {}).get("cli_command") if isinstance(slash_catalog.get("help"), dict) else "loopx slash-commands"}`
2117
+
2118
+ ## Paste Message
2119
+
2120
+ ````text
2121
+ {payload.get("message", "")}
2122
+ ````
2123
+
2124
+ ## Goal Start Contract
2125
+
2126
+ - schema: `{goal_start.get("schema_version")}`
2127
+ - planner_required_before_todo_write: `{(goal_start.get("planner") or {}).get("required_before_todo_write") if isinstance(goal_start.get("planner"), dict) else None}`
2128
+ - same_priority_tie_breaker: `{ordering.get("same_priority_tie_breaker")}`
2129
+ - prompt_constraint: {ordering.get("prompt_constraint")}
2130
+ - host_loop_required_after_todo_writeback: `{(goal_start.get("activation") or {}).get("host_loop_required_after_todo_writeback") if isinstance(goal_start.get("activation"), dict) else None}`
2131
+
2132
+ ## Host Loop Activation
2133
+
2134
+ - host_surface: `{activation.get("host_surface")}`
2135
+ - activation_method: `{activation.get("activation_method")}`
2136
+ - entry_command_hint: `{activation.get("entry_command_hint")}`
2137
+ - activation_input_command: `{activation.get("activation_input_command")}`
2138
+ - recheck_command: `{commands.get("goal_start_agent_onboard_recheck")}`
2139
+
2140
+ ## Key Commands
2141
+
2142
+ ```bash
2143
+ {commands.get("status", "")}
2144
+ ```
2145
+
2146
+ ```bash
2147
+ {commands.get("bootstrap_dry_run_preview", "")}
2148
+ ```
2149
+
2150
+ ```bash
2151
+ {commands.get("goal_start_connect_if_needed", "")}
2152
+ ```
2153
+
2154
+ ```bash
2155
+ {commands.get("issue_fix_workflow_plan_template", "")}
2156
+ ```
2157
+
2158
+ ## Safety Contract
2159
+
2160
+ - read_only: `{payload.get("read_only")}`
2161
+ - writes_registry: `{safety.get("writes_registry")}`
2162
+ - writes_state_file: `{safety.get("writes_state_file")}`
2163
+ - creates_heartbeat: `{safety.get("creates_heartbeat")}`
2164
+ - spends_quota: `{safety.get("spends_quota")}`
2165
+ - explicit_goal_start_may_write_project_local_state: `{safety.get("explicit_goal_start_may_write_project_local_state")}`
2166
+ - explicit_goal_start_must_activate_host_loop: `{safety.get("explicit_goal_start_must_activate_host_loop")}`
2167
+ """