delegate-agent-cli 0.29.1__tar.gz → 0.32.0__tar.gz

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 (380) hide show
  1. delegate_agent_cli-0.32.0/CHANGELOG.md +2610 -0
  2. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/CONTRIBUTING.md +8 -7
  3. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/MANIFEST.in +1 -0
  4. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/PKG-INFO +89 -26
  5. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/README.md +84 -25
  6. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/bin/delegate-profile-shim +134 -7
  7. delegate_agent_cli-0.32.0/bin/delegate.py +31 -0
  8. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/config.example.json +21 -2
  9. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/agent-setup.md +13 -4
  10. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/cli-reference.md +886 -170
  11. delegate_agent_cli-0.32.0/docs/configuration.md +1220 -0
  12. delegate_agent_cli-0.32.0/docs/delegate-workflows.md +784 -0
  13. delegate_agent_cli-0.32.0/docs/development.md +104 -0
  14. delegate_agent_cli-0.32.0/docs/live-runtime.md +158 -0
  15. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/publishing-checklist.md +30 -8
  16. delegate_agent_cli-0.32.0/docs/security-model.md +806 -0
  17. delegate_agent_cli-0.32.0/docs/troubleshooting.md +1040 -0
  18. delegate_agent_cli-0.32.0/docs/worktrees.md +573 -0
  19. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/pyproject.toml +10 -1
  20. delegate_agent_cli-0.32.0/src/delegate_agent/__init__.py +24 -0
  21. delegate_agent_cli-0.32.0/src/delegate_agent/account_binding.py +88 -0
  22. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/argv_builders.py +283 -81
  23. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/argv_utils.py +2 -0
  24. delegate_agent_cli-0.32.0/src/delegate_agent/auth_health.py +295 -0
  25. delegate_agent_cli-0.32.0/src/delegate_agent/auto_resume.py +227 -0
  26. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/bundled_models.py +13 -9
  27. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/capability_commands.py +91 -4
  28. delegate_agent_cli-0.32.0/src/delegate_agent/child_failures.py +189 -0
  29. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/cli.py +1062 -470
  30. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/cli_parser.py +1233 -271
  31. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/command_help.py +990 -290
  32. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/config.py +494 -23
  33. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/constants.py +55 -1
  34. delegate_agent_cli-0.32.0/src/delegate_agent/degraded.py +450 -0
  35. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/describe_payload.py +313 -209
  36. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/errors.py +14 -0
  37. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/failover_state.py +10 -3
  38. delegate_agent_cli-0.32.0/src/delegate_agent/followup_command.py +543 -0
  39. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/harness_discovery.py +349 -60
  40. delegate_agent_cli-0.32.0/src/delegate_agent/harness_enabled.py +120 -0
  41. delegate_agent_cli-0.32.0/src/delegate_agent/harness_events.py +2568 -0
  42. delegate_agent_cli-0.32.0/src/delegate_agent/inspection_commands.py +410 -0
  43. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/isolation.py +73 -1
  44. delegate_agent_cli-0.32.0/src/delegate_agent/lane_health.py +705 -0
  45. delegate_agent_cli-0.32.0/src/delegate_agent/lane_slice.py +156 -0
  46. delegate_agent_cli-0.32.0/src/delegate_agent/mail.py +324 -0
  47. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/mail_core.py +186 -72
  48. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/mail_push.py +46 -12
  49. delegate_agent_cli-0.32.0/src/delegate_agent/model_discovery.py +770 -0
  50. delegate_agent_cli-0.32.0/src/delegate_agent/notify.py +237 -0
  51. delegate_agent_cli-0.32.0/src/delegate_agent/outcome.py +279 -0
  52. delegate_agent_cli-0.32.0/src/delegate_agent/outside_cwd_changes.py +143 -0
  53. delegate_agent_cli-0.32.0/src/delegate_agent/pending_tool.py +80 -0
  54. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/private_io.py +193 -38
  55. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profile_guard.py +6 -8
  56. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profiles.py +134 -22
  57. delegate_agent_cli-0.32.0/src/delegate_agent/prompt_instructions.py +84 -0
  58. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/prompt_transport.py +17 -4
  59. delegate_agent_cli-0.32.0/src/delegate_agent/provider_errors.py +816 -0
  60. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/reasoning.py +44 -25
  61. delegate_agent_cli-0.32.0/src/delegate_agent/record_io.py +270 -0
  62. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/redaction.py +88 -3
  63. delegate_agent_cli-0.32.0/src/delegate_agent/registry_roster.py +279 -0
  64. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/rendering.py +156 -4
  65. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/request_build.py +1577 -454
  66. delegate_agent_cli-0.32.0/src/delegate_agent/request_models.py +443 -0
  67. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/resume_command.py +152 -66
  68. delegate_agent_cli-0.32.0/src/delegate_agent/retention.py +671 -0
  69. delegate_agent_cli-0.32.0/src/delegate_agent/run_context.py +132 -0
  70. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_metadata.py +78 -1
  71. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_output_commands.py +154 -5
  72. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_registry.py +571 -173
  73. delegate_agent_cli-0.32.0/src/delegate_agent/run_scratch.py +554 -0
  74. delegate_agent_cli-0.32.0/src/delegate_agent/run_status.py +585 -0
  75. delegate_agent_cli-0.32.0/src/delegate_agent/runner.py +6725 -0
  76. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/safe_workspace.py +427 -30
  77. delegate_agent_cli-0.32.0/src/delegate_agent/sandbox_bwrap.py +711 -0
  78. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/seatbelt.py +61 -2
  79. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/snapshot_view.py +88 -101
  80. delegate_agent_cli-0.32.0/src/delegate_agent/stall_watchdog.py +1244 -0
  81. delegate_agent_cli-0.32.0/src/delegate_agent/stream_capture.py +267 -0
  82. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/structured_output.py +93 -0
  83. delegate_agent_cli-0.32.0/src/delegate_agent/terminal_states.py +74 -0
  84. delegate_agent_cli-0.32.0/src/delegate_agent/usage_record.py +67 -0
  85. delegate_agent_cli-0.32.0/src/delegate_agent/wait_cancel_commands.py +1308 -0
  86. delegate_agent_cli-0.32.0/src/delegate_agent/workflow_attempts.py +271 -0
  87. delegate_agent_cli-0.32.0/src/delegate_agent/workflow_identity.py +133 -0
  88. delegate_agent_cli-0.32.0/src/delegate_agent/workflow_pinning.py +1431 -0
  89. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/__init__.py +12 -0
  90. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/commands.py +2047 -0
  91. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/registry.py +449 -0
  92. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/runtime.py +6997 -0
  93. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/schema.py +401 -0
  94. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/script.py +347 -0
  95. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/stage_guard.py +92 -0
  96. delegate_agent_cli-0.32.0/src/delegate_agent/workflows/status_reasons.py +163 -0
  97. delegate_agent_cli-0.32.0/src/delegate_agent/workspace_spec.py +636 -0
  98. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_commands.py +72 -15
  99. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_execution.py +405 -115
  100. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_gc.py +934 -61
  101. delegate_agent_cli-0.32.0/src/delegate_agent/worktree_mgmt.py +1582 -0
  102. delegate_agent_cli-0.32.0/src/delegate_agent/worktree_procs.py +234 -0
  103. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_records.py +144 -5
  104. delegate_agent_cli-0.32.0/src/delegate_agent/worktree_remove.py +868 -0
  105. delegate_agent_cli-0.32.0/src/delegate_agent/worktree_salvage.py +224 -0
  106. delegate_agent_cli-0.32.0/src/delegate_agent/worktree_summary.py +406 -0
  107. delegate_agent_cli-0.32.0/src/delegate_agent/write_guard.py +727 -0
  108. delegate_agent_cli-0.32.0/src/delegate_agent/write_guard_launch.py +383 -0
  109. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/PKG-INFO +89 -26
  110. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +146 -0
  111. delegate_agent_cli-0.32.0/src/delegate_agent_cli.egg-info/requires.txt +9 -0
  112. delegate_agent_cli-0.32.0/tests/test_acceptance_toolchain.py +175 -0
  113. delegate_agent_cli-0.32.0/tests/test_account_binding.py +99 -0
  114. delegate_agent_cli-0.32.0/tests/test_appendix_failure_strings.py +141 -0
  115. delegate_agent_cli-0.32.0/tests/test_auth_health.py +366 -0
  116. delegate_agent_cli-0.32.0/tests/test_auto_resume.py +457 -0
  117. delegate_agent_cli-0.32.0/tests/test_bundled_models_lane_r.py +30 -0
  118. delegate_agent_cli-0.32.0/tests/test_c5_validation.py +502 -0
  119. delegate_agent_cli-0.32.0/tests/test_call_capture_contract.py +44 -0
  120. delegate_agent_cli-0.32.0/tests/test_cancel_terminal_override.py +395 -0
  121. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_capability_commands.py +197 -79
  122. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_child_failures.py +38 -12
  123. delegate_agent_cli-0.32.0/tests/test_cli_ergonomics.py +308 -0
  124. delegate_agent_cli-0.32.0/tests/test_cli_simplification.py +230 -0
  125. delegate_agent_cli-0.32.0/tests/test_cli_surface_fixes.py +108 -0
  126. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_codex_pure_sandbox.py +76 -5
  127. delegate_agent_cli-0.32.0/tests/test_codex_scratch.py +759 -0
  128. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_codex_thread_resilience.py +20 -13
  129. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_command_help.py +151 -93
  130. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_config_commands.py +202 -22
  131. delegate_agent_cli-0.32.0/tests/test_cross_registry_lookup.py +310 -0
  132. delegate_agent_cli-0.32.0/tests/test_degraded.py +585 -0
  133. delegate_agent_cli-0.32.0/tests/test_degraded_runs.py +787 -0
  134. delegate_agent_cli-0.32.0/tests/test_delegate_audit_shim.py +33 -0
  135. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_help_cli.py +169 -201
  136. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_isolation.py +25 -16
  137. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_parser.py +861 -710
  138. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_validation.py +710 -141
  139. delegate_agent_cli-0.32.0/tests/test_describe_models_binary.py +123 -0
  140. delegate_agent_cli-0.32.0/tests/test_describe_workflow_dsl.py +93 -0
  141. delegate_agent_cli-0.32.0/tests/test_devin_bounded_output.py +181 -0
  142. delegate_agent_cli-0.32.0/tests/test_devin_read_only_behavior.py +142 -0
  143. delegate_agent_cli-0.32.0/tests/test_discovery_contracts.py +191 -0
  144. delegate_agent_cli-0.32.0/tests/test_docs_parser_conformance.py +497 -0
  145. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_end_to_end_tracking.py +46 -12
  146. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_engine_argv.py +796 -356
  147. delegate_agent_cli-0.32.0/tests/test_engine_universe.py +35 -0
  148. delegate_agent_cli-0.32.0/tests/test_execution_argv_and_prompt.py +2295 -0
  149. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_dry_run.py +89 -84
  150. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_failure_cleanup.py +83 -142
  151. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_preflight.py +56 -25
  152. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_run.py +551 -147
  153. delegate_agent_cli-0.32.0/tests/test_failover_state.py +173 -0
  154. delegate_agent_cli-0.32.0/tests/test_followup_after_retry_e2e.py +368 -0
  155. delegate_agent_cli-0.32.0/tests/test_followup_capture.py +330 -0
  156. delegate_agent_cli-0.32.0/tests/test_followup_parser.py +124 -0
  157. delegate_agent_cli-0.32.0/tests/test_followup_refusals.py +340 -0
  158. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_harness_discovery.py +379 -50
  159. delegate_agent_cli-0.32.0/tests/test_harness_events.py +3038 -0
  160. delegate_agent_cli-0.32.0/tests/test_harness_json_limits.py +34 -0
  161. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_inspection_commands.py +142 -60
  162. delegate_agent_cli-0.32.0/tests/test_isolation_plans.py +95 -0
  163. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_kimi_commands.py +36 -10
  164. delegate_agent_cli-0.32.0/tests/test_lane_a_transport.py +964 -0
  165. delegate_agent_cli-0.32.0/tests/test_lane_b_lifecycle.py +194 -0
  166. delegate_agent_cli-0.32.0/tests/test_lane_health.py +733 -0
  167. delegate_agent_cli-0.32.0/tests/test_lane_known_bad.py +274 -0
  168. delegate_agent_cli-0.32.0/tests/test_lane_m_mail_defaults.py +220 -0
  169. delegate_agent_cli-0.32.0/tests/test_lane_r_public_surface.py +86 -0
  170. delegate_agent_cli-0.32.0/tests/test_lane_s_structured_retry.py +178 -0
  171. delegate_agent_cli-0.32.0/tests/test_lane_slice.py +139 -0
  172. delegate_agent_cli-0.32.0/tests/test_launch_input_parity.py +582 -0
  173. delegate_agent_cli-0.32.0/tests/test_launch_mapping.py +368 -0
  174. delegate_agent_cli-0.32.0/tests/test_launch_model_resolution.py +276 -0
  175. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_bounds.py +41 -13
  176. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_contract.py +31 -1
  177. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_delivery.py +25 -16
  178. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_eligibility.py +30 -11
  179. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_framing.py +2 -27
  180. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_gating.py +175 -54
  181. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_identity.py +5 -6
  182. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_parser.py +10 -9
  183. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_prune.py +0 -12
  184. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push.py +30 -72
  185. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_adapters.py +37 -13
  186. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_batch.py +4 -6
  187. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_cursor.py +25 -5
  188. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_gating.py +3 -3
  189. delegate_agent_cli-0.32.0/tests/test_mail_push_inheritance.py +120 -0
  190. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_seams.py +53 -24
  191. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_reply.py +2 -4
  192. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_resolution.py +27 -21
  193. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_rules.py +9 -4
  194. delegate_agent_cli-0.32.0/tests/test_mail_tempdir.py +75 -0
  195. delegate_agent_cli-0.32.0/tests/test_mail_unread_steering.py +267 -0
  196. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_discovery.py +208 -224
  197. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_selection_wave1a.py +36 -147
  198. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_selection_wave1b.py +147 -172
  199. delegate_agent_cli-0.32.0/tests/test_nested_workflow_threads.py +249 -0
  200. delegate_agent_cli-0.32.0/tests/test_no_page_ask.py +75 -0
  201. delegate_agent_cli-0.32.0/tests/test_notify.py +486 -0
  202. delegate_agent_cli-0.32.0/tests/test_omp_output_capture.py +332 -0
  203. delegate_agent_cli-0.32.0/tests/test_omp_provider_pin.py +959 -0
  204. delegate_agent_cli-0.32.0/tests/test_omp_read_only_behavior.py +213 -0
  205. delegate_agent_cli-0.32.0/tests/test_omp_tool_update_compaction.py +243 -0
  206. delegate_agent_cli-0.32.0/tests/test_outcome_contract.py +718 -0
  207. delegate_agent_cli-0.32.0/tests/test_output_cap_off.py +236 -0
  208. delegate_agent_cli-0.32.0/tests/test_outside_cwd_changes.py +119 -0
  209. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_packaging.py +10 -3
  210. delegate_agent_cli-0.32.0/tests/test_partial_output_recovery.py +547 -0
  211. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_capability.py +23 -59
  212. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_claude.py +11 -17
  213. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_contract.py +17 -1
  214. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_framer.py +63 -77
  215. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_opencode.py +3 -13
  216. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_parser.py +28 -21
  217. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_records.py +16 -15
  218. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_resolution.py +49 -116
  219. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_size_guard.py +33 -12
  220. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_workflow.py +105 -91
  221. delegate_agent_cli-0.32.0/tests/test_private_directory_publish.py +75 -0
  222. delegate_agent_cli-0.32.0/tests/test_private_io_bounded.py +177 -0
  223. delegate_agent_cli-0.32.0/tests/test_private_io_dir_race.py +57 -0
  224. delegate_agent_cli-0.32.0/tests/test_proc_harness.py +204 -0
  225. delegate_agent_cli-0.32.0/tests/test_process_guard.py +149 -0
  226. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_profiles.py +159 -45
  227. delegate_agent_cli-0.32.0/tests/test_provider_error_docs.py +95 -0
  228. delegate_agent_cli-0.32.0/tests/test_provider_error_records.py +395 -0
  229. delegate_agent_cli-0.32.0/tests/test_provider_errors.py +265 -0
  230. delegate_agent_cli-0.32.0/tests/test_provider_outcomes.py +420 -0
  231. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_pure_call.py +163 -69
  232. delegate_agent_cli-0.32.0/tests/test_python_version_guard.py +253 -0
  233. delegate_agent_cli-0.32.0/tests/test_real_binary_contracts.py +499 -0
  234. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_reasoning_capabilities.py +139 -193
  235. delegate_agent_cli-0.32.0/tests/test_registry_contention.py +279 -0
  236. delegate_agent_cli-0.32.0/tests/test_registry_lock_guard.py +146 -0
  237. delegate_agent_cli-0.32.0/tests/test_registry_roster.py +183 -0
  238. delegate_agent_cli-0.32.0/tests/test_resumable_default.py +538 -0
  239. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_attachment.py +92 -75
  240. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_capture.py +47 -2
  241. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_inheritance.py +279 -29
  242. delegate_agent_cli-0.32.0/tests/test_resume_parser.py +85 -0
  243. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_projections.py +1 -1
  244. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_refusals.py +8 -1
  245. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_size_guard.py +13 -11
  246. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_stale.py +25 -19
  247. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_trust.py +83 -27
  248. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_retention.py +381 -51
  249. delegate_agent_cli-0.32.0/tests/test_run_listing_cost.py +98 -0
  250. delegate_agent_cli-0.32.0/tests/test_run_record_imports.py +46 -0
  251. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_run_registry.py +364 -39
  252. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_runner_capture.py +2450 -276
  253. delegate_agent_cli-0.32.0/tests/test_runs_deadline.py +191 -0
  254. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_safe_workspace_isolation.py +423 -106
  255. delegate_agent_cli-0.32.0/tests/test_sandbox_bwrap.py +1492 -0
  256. delegate_agent_cli-0.32.0/tests/test_scratch_reclaim.py +943 -0
  257. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_setup_commands.py +15 -13
  258. delegate_agent_cli-0.32.0/tests/test_simplification_integration.py +296 -0
  259. delegate_agent_cli-0.32.0/tests/test_single_run_record.py +236 -0
  260. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_slash_passthrough.py +28 -16
  261. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_redaction.py +87 -6
  262. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_rendering.py +29 -0
  263. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_run_output.py +367 -26
  264. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_view.py +109 -0
  265. delegate_agent_cli-0.32.0/tests/test_stall_watchdog.py +1454 -0
  266. delegate_agent_cli-0.32.0/tests/test_stall_watchdog_cursor.py +93 -0
  267. delegate_agent_cli-0.32.0/tests/test_stall_watchdog_runner.py +196 -0
  268. delegate_agent_cli-0.32.0/tests/test_status_truth.py +340 -0
  269. delegate_agent_cli-0.32.0/tests/test_stream_usage_ingest.py +205 -0
  270. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_structured_output.py +72 -0
  271. delegate_agent_cli-0.32.0/tests/test_terminal_states.py +27 -0
  272. delegate_agent_cli-0.32.0/tests/test_test_environment.py +44 -0
  273. delegate_agent_cli-0.32.0/tests/test_test_runner.py +83 -0
  274. delegate_agent_cli-0.32.0/tests/test_tracked_output_bounds.py +372 -0
  275. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_tracked_timeout.py +38 -81
  276. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_utility_modules.py +37 -21
  277. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wait_cancel_commands.py +750 -114
  278. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wave4_launch_features.py +212 -29
  279. delegate_agent_cli-0.32.0/tests/test_workflow_attempts.py +566 -0
  280. delegate_agent_cli-0.32.0/tests/test_workflow_check_keying.py +121 -0
  281. delegate_agent_cli-0.32.0/tests/test_workflow_commands.py +8068 -0
  282. delegate_agent_cli-0.32.0/tests/test_workflow_failure_policy.py +233 -0
  283. delegate_agent_cli-0.32.0/tests/test_workflow_gate_binding.py +300 -0
  284. delegate_agent_cli-0.32.0/tests/test_workflow_journal_reader.py +322 -0
  285. delegate_agent_cli-0.32.0/tests/test_workflow_jsonl_cli.py +74 -0
  286. delegate_agent_cli-0.32.0/tests/test_workflow_key_stability.py +68 -0
  287. delegate_agent_cli-0.32.0/tests/test_workflow_keyed_steps.py +1125 -0
  288. delegate_agent_cli-0.32.0/tests/test_workflow_pinning.py +1062 -0
  289. delegate_agent_cli-0.32.0/tests/test_workflow_profile_identity.py +234 -0
  290. delegate_agent_cli-0.32.0/tests/test_workflow_provider_stage.py +341 -0
  291. delegate_agent_cli-0.32.0/tests/test_workflow_repin.py +1264 -0
  292. delegate_agent_cli-0.32.0/tests/test_workflow_retry_outcomes.py +1490 -0
  293. delegate_agent_cli-0.32.0/tests/test_workflow_schema.py +339 -0
  294. delegate_agent_cli-0.32.0/tests/test_workflow_session_fallback.py +413 -0
  295. delegate_agent_cli-0.32.0/tests/test_workflow_simplification.py +222 -0
  296. delegate_agent_cli-0.32.0/tests/test_workflow_status_reasons.py +491 -0
  297. delegate_agent_cli-0.32.0/tests/test_workflow_watchdog.py +541 -0
  298. delegate_agent_cli-0.32.0/tests/test_workflow_watchdog_unit.py +889 -0
  299. delegate_agent_cli-0.32.0/tests/test_workspace_spec.py +1489 -0
  300. delegate_agent_cli-0.32.0/tests/test_worktree_effective_dirt.py +502 -0
  301. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_list_show.py +39 -61
  302. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_prune_gc.py +640 -143
  303. delegate_agent_cli-0.32.0/tests/test_worktree_reap_orphan.py +722 -0
  304. delegate_agent_cli-0.32.0/tests/test_worktree_record_bundle.py +95 -0
  305. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_remove.py +568 -75
  306. delegate_agent_cli-0.32.0/tests/test_worktree_retirement.py +800 -0
  307. delegate_agent_cli-0.32.0/tests/test_worktree_safety_policy.py +235 -0
  308. delegate_agent_cli-0.32.0/tests/test_worktree_salvage.py +416 -0
  309. delegate_agent_cli-0.32.0/tests/test_worktree_symlink_placeholders.py +191 -0
  310. delegate_agent_cli-0.32.0/tests/test_write_guard.py +1543 -0
  311. delegate_agent_cli-0.32.0/tests/test_write_guard_e2e.py +333 -0
  312. delegate_agent_cli-0.32.0/tests/test_write_guard_live.py +499 -0
  313. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wsl_guardrails.py +8 -8
  314. delegate_agent_cli-0.29.1/CHANGELOG.md +0 -1030
  315. delegate_agent_cli-0.29.1/bin/delegate.py +0 -15
  316. delegate_agent_cli-0.29.1/docs/configuration.md +0 -749
  317. delegate_agent_cli-0.29.1/docs/delegate-workflows.md +0 -241
  318. delegate_agent_cli-0.29.1/docs/development.md +0 -70
  319. delegate_agent_cli-0.29.1/docs/live-runtime.md +0 -64
  320. delegate_agent_cli-0.29.1/docs/security-model.md +0 -407
  321. delegate_agent_cli-0.29.1/docs/troubleshooting.md +0 -528
  322. delegate_agent_cli-0.29.1/docs/worktrees.md +0 -262
  323. delegate_agent_cli-0.29.1/src/delegate_agent/__init__.py +0 -5
  324. delegate_agent_cli-0.29.1/src/delegate_agent/child_failures.py +0 -93
  325. delegate_agent_cli-0.29.1/src/delegate_agent/harness_events.py +0 -1188
  326. delegate_agent_cli-0.29.1/src/delegate_agent/inspection_commands.py +0 -187
  327. delegate_agent_cli-0.29.1/src/delegate_agent/mail.py +0 -199
  328. delegate_agent_cli-0.29.1/src/delegate_agent/model_discovery.py +0 -370
  329. delegate_agent_cli-0.29.1/src/delegate_agent/prompt_instructions.py +0 -58
  330. delegate_agent_cli-0.29.1/src/delegate_agent/request_models.py +0 -326
  331. delegate_agent_cli-0.29.1/src/delegate_agent/retention.py +0 -366
  332. delegate_agent_cli-0.29.1/src/delegate_agent/run_status.py +0 -317
  333. delegate_agent_cli-0.29.1/src/delegate_agent/runner.py +0 -3810
  334. delegate_agent_cli-0.29.1/src/delegate_agent/wait_cancel_commands.py +0 -652
  335. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/__init__.py +0 -5
  336. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/commands.py +0 -743
  337. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/registry.py +0 -252
  338. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/runtime.py +0 -1669
  339. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/schema.py +0 -177
  340. delegate_agent_cli-0.29.1/src/delegate_agent/workflows/script.py +0 -203
  341. delegate_agent_cli-0.29.1/src/delegate_agent/worktree_mgmt.py +0 -790
  342. delegate_agent_cli-0.29.1/src/delegate_agent/worktree_remove.py +0 -586
  343. delegate_agent_cli-0.29.1/src/delegate_agent/worktree_summary.py +0 -241
  344. delegate_agent_cli-0.29.1/src/delegate_agent_cli.egg-info/requires.txt +0 -5
  345. delegate_agent_cli-0.29.1/tests/test_execution_argv_and_prompt.py +0 -1344
  346. delegate_agent_cli-0.29.1/tests/test_failover_state.py +0 -105
  347. delegate_agent_cli-0.29.1/tests/test_harness_events.py +0 -1667
  348. delegate_agent_cli-0.29.1/tests/test_omp_read_only_behavior.py +0 -88
  349. delegate_agent_cli-0.29.1/tests/test_resume_parser.py +0 -54
  350. delegate_agent_cli-0.29.1/tests/test_tracked_output_bounds.py +0 -167
  351. delegate_agent_cli-0.29.1/tests/test_workflow_commands.py +0 -2811
  352. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/LICENSE +0 -0
  353. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/SECURITY.md +0 -0
  354. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/assets/delegate-agent-header.png +0 -0
  355. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.claude.json +0 -0
  356. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.codex.json +0 -0
  357. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.cursor.json +0 -0
  358. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.droid.json +0 -0
  359. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.grok.json +0 -0
  360. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.judge.json +0 -0
  361. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.kimi.json +0 -0
  362. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/setup.cfg +0 -0
  363. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/archived_logs.py +0 -0
  364. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/command_errors.py +0 -0
  365. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/config_commands.py +0 -0
  366. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/git_utils.py +0 -0
  367. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/json_types.py +0 -0
  368. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/log_output.py +0 -0
  369. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/personas.py +0 -0
  370. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profile_commands.py +0 -0
  371. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/setup_commands.py +0 -0
  372. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/wsl.py +0 -0
  373. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
  374. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
  375. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
  376. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_call_text_fixtures.py +0 -0
  377. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_child_root_env.py +0 -0
  378. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_launch_error_hints.py +0 -0
  379. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_io.py +0 -0
  380. {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_validation.py +0 -0
@@ -0,0 +1,2610 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.32.0] - 2026-10-01
11
+
12
+ This release adds controls for launching and managing agents and resuming
13
+ workflows: `--force-launch`, `--writable`, `--kill-live`, and `--repin`.
14
+ It also improves progress reports, coordinator mail, failure recovery, and
15
+ write protection, and makes optional local profile tooling work on other
16
+ machines without requiring the maintainer's setup.
17
+
18
+ ### Added
19
+ - **Every work and safe Run carries the lane test rule.** After the operator's
20
+ task, the framed prompt adds a "Delegate lane test rule" section: lanes run
21
+ targeted tests only (the files they changed and their neighbours, through
22
+ `testrun` with worker caps), and the full suite and the project gate stay
23
+ with the coordinator (Trey, 2026-09-30). Call mode, unmoded prompts, and
24
+ slash passthrough are untouched; reframing never repeats it.
25
+ - `runs` and `ps` show how long a running Run has left: a running Run with a
26
+ timeout carries `deadlineAt` (recorded by the runner when its timeout clock
27
+ starts, after workspace setup) and `remainingSeconds`, and the text listing
28
+ prefixes `current` with `12m left`. Terminal Runs carry neither.
29
+ - **A live Run shows the tool call it is waiting on.** While a tool call is in
30
+ flight, `runs` and `snapshot` carry `pendingTool` (`name`, optional
31
+ `target`, `startedAt`, `seconds`; the oldest pending call, redacted like
32
+ `current`), and after a minute `current` reads `waiting on tool <name> for
33
+ 13m`. It is refreshed whenever the pending set changes, tracked even with
34
+ `--stall-minutes 0`, and dropped from terminal records. The stall watchdog
35
+ still never fires while a tool is pending: a hung tool is surfaced, not
36
+ killed.
37
+ - A followup or session resume whose child exits non-zero within 15 seconds
38
+ with no stdout or stderr stays `child_failed`, but the message says the
39
+ saved native session probably could not be loaded and `nextActions` offers
40
+ `delegate resume <handle>`.
41
+ - **Early-stop detection.** A succeeded Run whose last sentence announces a
42
+ next step ("Now let me write my report.") carries `degraded:
43
+ ended_announcing_next_step`, and a work Run that parks on an approval
44
+ question with no changed files carries `degraded: ended_awaiting_input`.
45
+ Status stays `succeeded`; the warning names `delegate resume <handle>`. A
46
+ finished deliverable that ends with "Should I proceed?" is not flagged.
47
+ - **Unread coordinator mail is surfaced at run end.** A terminal work Run
48
+ records `unreadMail` (count, up to three id/sender/subject rows, and an
49
+ `unreadable` count for damaged or non-regular inbox entries) plus a warning
50
+ on the state, envelope, completion report, snapshot, `wait`, and `cancel`
51
+ reply. Messages a push hook already injected count as read. The mail prompt
52
+ suffix now asks lanes to read their inbox before final verification or
53
+ commit. Launch, dry-run, and manifest carry `mailInbox` (host and mail
54
+ root).
55
+ - `followup` and `resume` inherit `--mail-push` from the source Run and accept
56
+ `--no-mail-push`; `followup` also accepts `--mail-push`.
57
+ - **One automatic fresh rerun for transient safe-mode failures.** A `safe`
58
+ Run that fails with `stream_disconnected` or `provider_unavailable`, or a
59
+ `safe` launch the broker refuses (`broker_binding_inactive`) with no child
60
+ output, is rerun once as a new Run recorded under `autoResume` with `kind:
61
+ "rerun"` and the first attempt's error. The first broker refusal defers the
62
+ known-bad lane marker (`laneMarkerDeferred: "broker_binding_retry"`). Work
63
+ Runs are never rerun this way. `providerErrors.autoResume: false` turns it
64
+ off.
65
+ - **`<engine>.enabled: false`** hides a harness from `models`, `describe`,
66
+ `capabilities`, and `capabilities refresh`, and any launch of it fails with
67
+ `harness_disabled` naming the key.
68
+ - **Claude model typos are refused before launch.** A typed `--model` that is
69
+ a family word plus a version (`opus-5.5`, `Sonnet 5`) or names no model
70
+ (`claude-`, an empty `[]`) fails with `invalid_alias` and the closest valid
71
+ values, on the CLI, dry runs, and `run --input-json`. Provider names
72
+ (Bedrock ARNs, Foundry deployments, gateway strings) still launch, and the
73
+ version-typo refusal is skipped when a Bedrock, Vertex, Foundry, or
74
+ `ANTHROPIC_BASE_URL` gateway variable is set.
75
+ - Workflow status says why and what next: a paused workflow carries a `pause`
76
+ object (gate, actions, last failure, rejection text) or a `softPark` reason
77
+ naming `delegate workflow resume <wfId>`; agent journal rows always carry
78
+ label and item, `agent_started` records `timeout` and `deadlineAt`,
79
+ `agent_timeout` names `nextEngine`, and status lists recent timeouts.
80
+ - Codex structured output: a root-array answer wrapped in a one-key object is
81
+ unwrapped on the prompt path and journaled as `agent_output_unwrapped`.
82
+ - Worktree warnings name the files: `dirty_source_auto_included_paths`,
83
+ `dirty_source_included`/`dirty_source_included_paths` for explicit
84
+ `--include-dirty`, `dirty_source_mirrored` for safe worktree launches, and
85
+ `dirtySourcePreview` in dry runs (up to five paths each).
86
+ - `workflow resume` and `workflow status` say when a workflow's pinned runtime
87
+ differs from the live one. The notice names both runtimes (digest, delegate
88
+ version, and the pin or promotion date), and JSON carries the same facts as
89
+ `runtimePin` (`differs`, `pinned`, `live`; on a resume the notice text is
90
+ also in `warnings`). `status` prints no notice for a finished (`succeeded`
91
+ or `dry_run`) workflow, and a pin that cannot be read reports `checked:
92
+ false` with the reason instead of blocking the resume.
93
+ - `--repin` on `workflow resume`, `workflow run --resume`, and `workflow
94
+ approve` is an opt-in that moves a workflow onto the live runtime; a plain
95
+ resume still keeps the pin. It keeps the journal, step keys, frozen script,
96
+ arguments, config, personas, and profile identity, moves the old runtime
97
+ into `runtimeHistory`, and journals one `runtime_repinned` event. The
98
+ identity check still runs first, and the new pin is written aside and
99
+ validated before it replaces the old one. A failed validation, a failed
100
+ launch, or a resume where no supervisor ever starts on the new pin restores
101
+ the old pin byte for byte and journals `runtime_repin_rolled_back`.
102
+ `--repin` is refused with `repin_children_running` while a child run is
103
+ running or still starting, with `invalid_option_combination` on a new run or
104
+ with `--dry-run`, with `workflow_locked` when another resume holds the lock,
105
+ and when the existing pin cannot be verified. `WORKFLOW_KEY_VERSION` remains
106
+ the guard against step-key drift. A script that branches on `capabilities`
107
+ can take a different branch after a repin, because the map then describes
108
+ the live runtime.
109
+ - `workflow check` warns about unkeyed steps in a script that keys others.
110
+ When some `agent()`, `parallel()`, `pipeline()`, or `workflow()` calls pass
111
+ `key=` and others do not, it emits one `keying warning` per primitive kind
112
+ with the source lines of the unkeyed calls (at most eight), because those
113
+ calls still replay by position and prompt and lose settled work when a
114
+ resumed script shifts. A script that keys nothing is left alone, a call with
115
+ a `**kwargs` expansion is assumed to carry its key, and `judges()` and
116
+ `followup()` are never flagged.
117
+ - A run or workflow id that is not in the current workspace is looked up in a
118
+ small roster of the other workspaces Delegate has launched in
119
+ (`~/.delegate/registries.json`, private, at most 256 entries, most recently
120
+ used first; workspaces whose `.delegate` is gone are skipped). `snapshot`
121
+ and `run-output` read a run id found in exactly one other workspace directly
122
+ and report `resolutionKind: "cross_registry"`, `resolvedWorkspace`, and a
123
+ `cross_registry:` warning. `wait`, `cancel`, `resume`, `followup`, and
124
+ `worktree show` never act across workspaces: they fail with
125
+ `unknown_handle`, name the workspace, and put the exact `delegate --cwd
126
+ <workspace> ...` command first in `nextActions`. The workflow read actions
127
+ `status`, `events`, `watch`, `wait`, and `result` read a workflow found in
128
+ exactly one other workspace, and `status`, `wait`, and `result` add
129
+ `resolvedWorkspace`; `approve`, `reject`, `kill`, and `run --resume` fail
130
+ with `workflow_not_found` and the exact command instead. An id found in
131
+ several workspaces is listed, never guessed, and a numbered alias is never
132
+ auto-resolved: the error lists every workspace that has it. Only workspaces
133
+ used for a launch after the roster shipped are known.
134
+ - OMP `tool_execution_update` records whose `args` or `partialResult` is
135
+ oversized are shrunk to a `{"delegateCompacted": true, "originalBytes": N,
136
+ "head": ..., "tail": ...}` stub. The sub-agent `task` tool re-emits its
137
+ whole shared context on every update; `tool_execution_start` and
138
+ `tool_execution_end` carry the full arguments and result once and are never
139
+ touched. `stdoutCapture` (policy `omp-capture-v2`) reports
140
+ `compactedToolUpdateRecords` and `compactedToolUpdateBytes`, the run gets a
141
+ warning, and `--raw` cannot recover the compacted text.
142
+ - Tracked Pi, OMP, and OpenCode runs ingest token `usage` from the stream,
143
+ summed per message or step and not double counted.
144
+ - Run and call envelopes, run summaries, and snapshots carry `servedModel`
145
+ and, when the harness reports one, `servedProvider`: what the child's stream
146
+ says actually answered. They sit beside `modelResolved` (the request),
147
+ repeat inside `modelProvenance`, and are absent when the harness reported no
148
+ model. A Claude call reports only a per-run `modelUsage` total, so its
149
+ `servedModel` is set only when exactly one model produced output; with
150
+ several it is absent and a pinned call warns `pinned_continuity_unverified`.
151
+ An ungrouped `call` is now held to the same continuity rule as a tracked
152
+ run: a pinned call whose stream names another model or provider fails with
153
+ `model_continuity_paused` (text mode prints no answer text for it; JSON
154
+ keeps any text beside the error), and a fungible or panel call carries the
155
+ `model_substitution` warning, provider included.
156
+ - A tracked run whose child ends its turn mid-job is flagged as degraded. A
157
+ headless child ends when its model stops, and background Bash tasks and
158
+ Monitors die with the session, so a Claude work run that said "Waiting on
159
+ the full gate" used to be recorded `succeeded` with `ok: true` while its
160
+ gate never finished. The status stays `succeeded` so the work can be
161
+ adopted, but the run now carries `degraded: true` (present only when true),
162
+ a `degradedReason`, `degradedEvidence` (bounded, redacted lines saying what
163
+ was seen), and a `degraded=...` warning. They appear on the launch envelope,
164
+ in state.json, on `wait` (JSON, `--structural`, and a `degraded:` line in
165
+ text), `snapshot`, `runs` and `ps` (the text table prefixes `current` with
166
+ `[degraded]`; `--structural` omits them), the `run-output
167
+ --completion-report` view, and, for a workflow child, the `agent_child`
168
+ journal event and `agent_meta()` (`degraded`, `degradedReason`). Nothing
169
+ fails a run or a workflow step, and `wait` still exits 0. `degradedReason`
170
+ is `ended_waiting_on_background_work` or
171
+ `background_work_unfinished_at_exit`. The first is a final-message check
172
+ that works for every engine: a short message that is not shaped like a
173
+ finished report and says the child is waiting on, or will act after,
174
+ unfinished work of its own. It ignores waiting on the requester ("I'll
175
+ commit when you approve"), a third party's independent result ("Waiting for
176
+ CI to post its result"), denials, and quoted text such as a tool's output; a
177
+ short report-shaped message matches only an explicit present-tense statement
178
+ that the child's own job is still running; runs with `--output-schema` are
179
+ not text-checked. The second reads Claude Code's `background_tasks_changed`
180
+ snapshot at the result event and catches a finished-looking report that
181
+ abandoned a running task; only Claude emits that event.
182
+ - A provider failure is now data. The failed run's envelope, run state, and
183
+ completion report carry a structured `providerError` (`status`,
184
+ `providerCode`, `message`, `engine`, `signature`, `class`, `hint`); the
185
+ message is bounded, credentials are redacted, and email addresses are
186
+ masked. `class` is `persistent`, `transient`, or `unknown`, and a persistent
187
+ signature is either lane-scoped (credentials, billing, or model access are
188
+ wrong) or request-scoped (this prompt is the problem). One engine-keyed
189
+ signature table classifies by HTTP status first, then provider code, and
190
+ uses text patterns only as the fallback, so `failureReason`, `failureKind`,
191
+ the hint, and the class agree, and an OMP HTTP 400 naming an image count or
192
+ size limit is `request_image_limit`, never an auth failure. The signature
193
+ list is in `docs/troubleshooting.md`. Two new `failureKind` values are
194
+ `lane_known_bad` (a launch refused, below) and `provider_exhausted`
195
+ (workflow only).
196
+ - A persistent, lane-scoped provider failure (rejected credentials, no credit,
197
+ usage limit, no access to the model, missing API key) marks its lane
198
+ known-bad for `providerErrors.knownBadLaneMinutes` (default `15`; `0` turns
199
+ markers off). Until the marker expires, another launch on that lane is
200
+ refused in milliseconds, before any worktree or child exists, with
201
+ `lane_known_bad` and the new exit code `4`; the payload carries `signature`,
202
+ `class`, `hint`, `expiresAt`, `secondsLeft`, and `markedRunId`. The global
203
+ `--force-launch` launches anyway (another persistent failure renews the
204
+ marker), a success clears the marker, and `--dry-run` never refuses.
205
+ `delegate doctor` lists live markers as `knownBadLanes`. Transient,
206
+ request-scoped, and unclassified failures never mark a lane, nor do endings
207
+ Delegate established itself (timeout, stall, output cap, cancel), and a
208
+ Codex usage limit with `codex.fallbackProfile` set stays with the profile
209
+ failover. The `providerErrors` config section is new, and an unknown key in
210
+ it fails as `invalid_provider_errors_config`.
211
+ - A known-bad lane is one engine on one provider, model, and account (the
212
+ Codex failover identity, `CLAUDE_CONFIG_DIR`, or the auth profile), plus the
213
+ credentials the child will see: API keys, tokens, and broker, realm,
214
+ account, and endpoint settings in the environment, and for OpenCode the
215
+ provider keys, base URLs, and `Authorization` headers inside
216
+ `OPENCODE_CONFIG_CONTENT`. They are folded in as a salted hash (the salt is
217
+ `~/.delegate/state/lane-health.salt`, mode 0600), so a bad key on one
218
+ account never refuses a healthy account on the same model, and no key value
219
+ is stored or shown. `doctor` and the refusal print only a short `[credential
220
+ xxxxxxxx]` tag, an account label shaped like an email address is masked, and
221
+ a success clears its marker even when the marker store's lock is stuck.
222
+ - A Codex or Claude work run that fails with a transient provider drop
223
+ (`stream_disconnected` or `provider_unavailable`: Codex's websocket closing
224
+ early, or a 5xx or overloaded Claude reply) and saved its native session is
225
+ continued once, automatically, the way `delegate followup` continues one:
226
+ same session, a new run linked to the first by `followupOf`. The
227
+ continuation's envelope and manifest carry `autoResume` (`automatic`,
228
+ `attempt`, `of`, `trigger`), and the final result is the continuation's.
229
+ There is no second automatic attempt, so a drop in the continuation is
230
+ final. It never applies to safe or call mode, `--pass-through`,
231
+ structured-output runs (the workflow supervisor owns that retry), runs that
232
+ saved no session, or runs in a temporary worktree; a worktree run attaches
233
+ to its own worktree and branch. When the continuation cannot be built the
234
+ first run's result is returned unchanged with `autoResume` set to
235
+ `attempted: false` and a `reason`. It is on by default, and
236
+ `providerErrors.autoResume: false` opts out; workflow children are
237
+ unresumable unless the call passes `resumable=True`, so it reaches them only
238
+ then.
239
+ - Workflow `agent()` returns two new typed failure kinds under
240
+ `on_failure="typed"`: `lane_known_bad` (the child refused to launch because
241
+ its lane is marked known-bad; workflows never pass `--force-launch`) and
242
+ `provider_exhausted` (the call was skipped, with no run and a `run_id` of
243
+ `None`, because its stage already stopped launching on the lane).
244
+ `AgentFailure.provider_error` carries the child's `providerError` so a
245
+ script can branch on the signature instead of parsing prose, and
246
+ `capabilities["providerOutcomes"]` advertises the feature. A stage is one
247
+ `phase()` label and a lane is one engine on one model. When the first
248
+ `providerErrors.stageStopAfter` results (default `3`; `0` turns the stop
249
+ off) of a stage on a lane all fail with the same persistent, lane-scoped
250
+ signature, the rest of that stage's calls on that lane are not launched,
251
+ cells already queued behind the agent cap skip too, and a call with an
252
+ engine fallback chain moves on to its next engine. A success or any
253
+ different result among the first results means the lane is not uniformly
254
+ bad, and transient and request-scoped failures never count. The trip is
255
+ journaled once as `stage_lane_stopped` and each skipped call as
256
+ `agent_lane_skipped`; a skipped call still counts against the workflow's
257
+ agent budget.
258
+ - `delegate capabilities refresh` records per-engine auth health. A successful
259
+ refresh runs the read-only probes named in `providerErrors.authProbes` (by
260
+ default `estate-cursor status` for `cursor` and `estate-omp usage` for
261
+ `omp`) and records what they clearly say as `authHealth`, in its JSON and
262
+ text output and in `~/.delegate/state/auth-health.json`: `ok`, `logged_out`
263
+ (Cursor reports it is not signed in), or `limit_reached` (an OMP quota
264
+ window is at 100%). OMP reports quota per provider and account, so its
265
+ reading also carries `lanes` (`<provider>/account <N>` to `ok`,
266
+ `limit_reached`, or `unknown`); the engine reads `limit_reached` only when
267
+ every lane is exhausted, `partial` when some are, and `unknown` for lanes
268
+ the report does not describe. A probe that is missing, slow, exits non-zero
269
+ without a recognisable message, or prints something unexpected records
270
+ `unknown` with a `reason`; `unknown` is never a failure and never refuses a
271
+ launch, and the probe's raw output is not stored. A subset refresh probes
272
+ only the named engines and keeps the others' last reading, and `delegate
273
+ doctor` shows the last reading as `authHealth`. `authProbes` accepts only
274
+ `cursor` and `omp` (each a command and its arguments, or `null` to turn that
275
+ probe off), and `DELEGATE_AUTH_PROBES=off` (or `0`, `false`, `no`) skips
276
+ every probe.
277
+ - A conformance test requires the parser to accept every documented command
278
+ line. It extracts each `delegate` line from `docs/cli-reference.md` and each
279
+ usage and example line in `COMMAND_SPECS`, expands the usage synopses into
280
+ concrete argv lists (minimal, maximal, each alternative alone, and every
281
+ pair of optional groups), and fails on any the parser refuses, so a synopsis
282
+ that shows mutually exclusive options as independent cannot drift again. A
283
+ separate test runs the real launcher on `mail send --to coordinator -` with
284
+ a piped multi-byte UTF-8 stdin and compares the delivered bytes.
285
+ - The stall watchdog stops runs for named reasons besides idle time. A run
286
+ that streams roughly 100k tokens of model output with no tool activity stops
287
+ as `runaway_output`; only model-output payload characters count, and
288
+ text-stream harnesses such as Devin are exempt. The same tool call failing
289
+ the same way five times in a row, with nothing else completing in between,
290
+ stops as `repeated_tool_failure`; each failure counts in exactly one streak,
291
+ and targets compare whole. A repeated identical call no longer resets the
292
+ idle clock and time spent inside tool calls no longer counts as idle, so a
293
+ fast no-op loop is caught while a slow polling loop is left alone. A changed
294
+ `HEAD` in the execution checkout counts as progress. Every idle stall samples
295
+ the child's process group and records `childActivity` (`cpu_active`,
296
+ `waiting`, or `no_processes`) with a process snapshot, and a pending stall
297
+ kill is re-validated after those blocking diagnostics.
298
+ - A Devin child whose output already ends in a Delegate completion report and
299
+ then goes quiet is stopped as finished (`stoppedAfterCompletion`) instead of
300
+ stalled. Only a `Status: completed` report records exit 0; `failed` or
301
+ `blocked` records a failed run, and a child that echoes the prompt's own
302
+ template line (`Status: completed / blocked / failed`) stalls as before.
303
+ - Tracked launches take `--stall-minutes`, which pins the stall threshold over
304
+ config, the silent-harness default, and `DELEGATE_STALL_MINUTES`. The
305
+ manifest records a pinned value as `stallMinutes`, and `resume` and
306
+ `followup` pass it to the continuation (config and environment defaults are
307
+ still re-resolved). Resume refuses an invalid recorded value and followup
308
+ ignores one, as each already treats `timeoutSeconds`. `describe` lists the
309
+ flag with the other tracked-only launch options.
310
+ - With `DELEGATE_CHILD_NO_PAGE_ASK=1` in the launching environment, each
311
+ tracked child finds a stub `ask` first on its `PATH`. The stub prints a
312
+ refusal and exits 2 (the real `ask`'s relay-down code) instead of paging the
313
+ operator's phone and blocking. It is written into the run's own private temp,
314
+ scratch, or run directory; nothing under `$HOME` is written.
315
+ - An `--isolation none` run whose cwd is strictly inside a git work tree
316
+ records the files it changed elsewhere in that repository as
317
+ `outsideCwdChanges` (repository, count, examples) with a warning. The before
318
+ and after snapshots key each path by status, size, and mtime, skip
319
+ Delegate's own registry, and run git with `--no-optional-locks` so they never
320
+ rewrite the user's index. A repo-root cwd, a non-git cwd, and paths outside
321
+ the repository stay undetected, and the warning says so.
322
+ - Safe and dirty-synced workspace copies name, in a run warning, the paths
323
+ they withhold only because `.git/info/exclude` ignores them. The files are
324
+ still not copied, since `info/exclude` is where private scratch usually
325
+ lives.
326
+ - An omp prompt that names image paths warns that omp will not attach them
327
+ (omp attaches files only from `@path` argv, and Delegate sends the prompt on
328
+ stdin) and points at omp's read tool. The scan runs in linear time.
329
+ - `runs --summary` and `ps --summary` print counts by status, harness, and
330
+ group for every matching run, without rows or manifest loads. Each run is
331
+ counted once across registry roots, the listing's empty-scope and
332
+ status-filter warnings apply, and `--limit` and `--structural` are refused.
333
+ - `wait --json --structural` reduces each run to identity, terminal status,
334
+ result quality, and failure fields, and moves the handle-resolution warnings
335
+ (`bare_handle_stale`, `bare_handle_ambiguous`, `run_target_stale`) to the top
336
+ level. `ok` and the exit code still come from the full view; text output
337
+ ignores the flag.
338
+ - `worktree show` and `worktree remove` accept the worktree path as the
339
+ handle, matched canonically against the records' `executionCwd`; a relative
340
+ path resolves against the `--cwd` workspace. An unknown path fails with
341
+ `unknown_worktree_path` and, like an unknown handle, points at
342
+ `worktree reap --path`. `not_worktree_run` names the run that owns the
343
+ worktree and puts `worktree show` on it first in `nextActions`.
344
+ - A bare harness handle warns `bare_handle_ambiguous`, naming up to five other
345
+ runs, when other runs of that harness share its group or are still running.
346
+ - A cursor model that is a bare family word such as `grok`, and is neither a
347
+ configured `cursor.models` alias nor a catalog selector, resolves to the
348
+ family's newest selector (highest version, non-fast, balanced tier) from the
349
+ discovered catalog, or from the bundled table when discovery has none, with
350
+ a warning. Configured defaults and routes resolve the same way before effort
351
+ routing.
352
+ - Launches warn when the resolved model id is absent from the discovered
353
+ catalog, or from the bundled table when discovery is empty; bundled-table
354
+ warnings fire only for a selector that resembles a listed id. Cursor now
355
+ uses this shared check, so a misspelled id warns without a discovery
356
+ snapshot. A Claude `[1m]` suffix compares by its base, and Claude family
357
+ aliases are exempt. The launch is never refused and the selector never
358
+ rewritten.
359
+ - The `--forbid-commit` implied-worktree note and a missing `codex.profile`
360
+ overlay print to stderr when a run launches, not only in the finalization
361
+ report or `doctor`.
362
+ - A failed safe-mode run whose child reports resolver or reachability errors
363
+ (`getaddrinfo`, `ENOTFOUND`, `EAI_AGAIN`, and similar) warns that safe mode
364
+ may block network access and that research belongs in work mode. Only a
365
+ generic nonzero exit gets the hint; status and failure kind are unchanged.
366
+ - `followup` on a run that a later resume or followup already continued prints
367
+ a note naming that run and the command that continues from it, unless the
368
+ later run shares the source's native session.
369
+ - `describe` and `models --json` report `binary` for every engine, droid
370
+ included. The `models` text view omits a retired droid row that has no
371
+ configured or discovered models and no configured default.
372
+ - Workspace spec for work lanes in a persistent worktree: `--base REF` cuts the
373
+ worktree from REF, `--env NAME=VALUE`/`--env-file PATH` set child variables
374
+ that are recorded privately and re-applied on resume and followup, and
375
+ `--setup CMD` runs in the fresh worktree before the child. A failed setup is
376
+ a typed `workspace_setup_failed` error (`failureKind: workspace_setup`) and no
377
+ child launches. `run --input-json` takes `base`, `env`, and `setup`, and
378
+ workflow `agent()` takes `base=`, `env=`, and `setup=` (capability
379
+ `workspaceSpec`). `workflow run --env/--env-file` records a launch env that
380
+ every resume re-applies.
381
+ - A worktree whose run is not terminal while its launching Delegate process is
382
+ alive is leased: prune, auto-prune, reap, and remove skip it with
383
+ `worktree_leased` even when the child pid is dead.
384
+ - `delegate runs` in a repository's main worktree also lists runs registered in
385
+ its linked worktrees, tagged with `registryWorkspace`.
386
+ - Workflow steps can carry a stable caller-supplied identity. `agent(..., key="...")`
387
+ replays by that key inside the enclosing named scope instead of by position and
388
+ prompt text, so a resumed script that skips settled work or embeds new git heads
389
+ in its prompts still hits its cache. A changed prompt under the same key adopts
390
+ the recorded result and journals `key_prompt_mismatch`. `parallel`, `pipeline`,
391
+ and `workflow` accept `key=` to name their scope. Reusing a key within one run
392
+ raises `WorkflowKeyConflict`. Unkeyed calls keep their positional keys, so
393
+ existing journals replay unchanged.
394
+ - Gate actions: `park_gate(key, result, actions=[...])` pauses for an operator
395
+ decision, and `workflow approve <wfId> --gate KEY --action NAME [--note TEXT]
396
+ [--data JSON]` returns that choice to the script. Undeclared actions are
397
+ refused with the allowed list. A bare `approve` behaves as before. A recorded
398
+ action the resumed script no longer declares is not returned: the gate parks
399
+ again (`gate_action_undeclared`) and asks under the current actions. A second
400
+ live `park_gate()` with the same key in one named scope raises
401
+ `WorkflowKeyConflict`.
402
+ - The workflow `capabilities` global adds `agentKey`, `scopeKey`, and
403
+ `gateActions`.
404
+ - Tracked runs persist the harness-reported token `usage` on the run record, so
405
+ `snapshot`, `run-output`, and `runs --json` expose it without re-reading the
406
+ child's stream (previously it reached only call mode's launch response).
407
+ - A fungible or panel run whose harness reports a served model other than the
408
+ resolved one now carries a `model_substitution` warning naming requested,
409
+ resolved, and served models. Pinned runs already pause on a switch; the
410
+ warning closes the silent case for the default continuity mode.
411
+ - `delegate doctor` warns when a configured `<engine>.defaultModel` (resolved
412
+ through `<engine>.models` aliases first) is absent from the selected profile's
413
+ discovery catalog, naming the nearest discovered selectors. It checks the
414
+ unique targets of configured `<engine>.models` aliases the same way, naming the
415
+ alias key, since a selector an operator wrote down is worth knowing about even
416
+ when no current launch selects it. A cursor launch
417
+ adds the same warning for its selected selector, because cursor-agent resolves
418
+ an unknown selector inside the child. All of them are warnings: an empty or
419
+ missing catalog stays silent, and no configured value is rewritten or refused.
420
+ - `workflow run` warns when it detects it is running inside a systemd unit whose
421
+ `KillMode` will reap the detached supervisor (`control-group`/`mixed`), naming
422
+ the unit and the required `-p KillMode=process`. Previously the unit reported
423
+ success while the workflow was already dead.
424
+
425
+ ### Fixed
426
+ - Missing local profile directories are silently omitted from write-guard
427
+ launcher reopens. Failover state uses `~/.delegate/failover` when the optional
428
+ profile tree is absent, and missing personal profile homes do not read legacy
429
+ cooldown files. Existing profile trees keep their current behavior. The
430
+ development-only `delegate-audit` shim names its optional checkout when absent.
431
+ - `worktree reap` removes linked orphans on Linux again. Its process scan
432
+ refused every removal as `process_scan_unavailable` because Linux hides the
433
+ working directory of the user's own non-dumpable processes (`systemd
434
+ --user`, `ssh-agent`, `sshd-session`), which every login session has. A
435
+ hidden process whose real and effective user and group ids match the
436
+ caller's is now noted in a warning and does not block (the saved ids may
437
+ differ, as for set-group-id `ssh-agent` on Debian); one with other ids (a
438
+ `newgrp` shell) or an unreadable status still refuses. Shells,
439
+ agents, and bubblewrap-sandboxed lanes stay readable and still block
440
+ removal. The test helper that runs fake children also writes the script to
441
+ a file, since Linux caps one argument at 128 KiB.
442
+ - A stale Run's `nextActions` (in `runs` and `snapshot`) now offers `delegate
443
+ resume <handle>` (not for `call` Runs, which cannot resume). The CLI
444
+ reference and troubleshooting guide say what killing a launch command does:
445
+ the launch is the Run's supervisor, the child keeps running on its own until
446
+ it next writes output and then exits, the Run reads `stale`, and `cancel`,
447
+ `resume`, or `followup` recover it. Launch each lane from its own background
448
+ task.
449
+ - The `runs` and `worktree list` text tables head their time-since-activity
450
+ column `idle`; it was labelled `age`, which agents read as run age. JSON is
451
+ unchanged.
452
+ - Parallel Runs launched at the same moment (workflow `parallel()` children,
453
+ a fan-out) no longer fail at random with `unsafe_scratch_directory` ("File
454
+ exists: 'run-scratch'"). Two launches racing to create the shared scratch
455
+ root now both use it; the symlink, non-directory, and foreign-owner checks
456
+ still run on the directory either way.
457
+ - The Claude model-typo refusal is skipped when `CLAUDE_CODE_USE_BEDROCK`,
458
+ `CLAUDE_CODE_USE_VERTEX`, `CLAUDE_CODE_USE_FOUNDRY`, or `ANTHROPIC_BASE_URL`
459
+ comes from `--env` or `--env-file`, not only from the launching
460
+ environment. The env files are read once per launch, so the check and the
461
+ child see the same values.
462
+ - A Run's `current` no longer keeps showing a provider error after the
463
+ harness has moved on. Pi and OMP show `retrying after provider error
464
+ (429)` while they retry and then the new activity; a Codex `turn.started`
465
+ or OpenCode `step_start` after an error replaces it the same way.
466
+ - `--notify` channel pings work against post 0.9.0, which removed `--anyway`
467
+ from its help. The notifier sends without it and retries once with
468
+ `--anyway` only when post refuses the send as `crossed_send`.
469
+ - The setup-command output tail recorded for a worktree Run can no longer
470
+ reconstruct a secret passed through `--env`/`--env-file`: recorded values
471
+ and their fragments are masked, generic redaction runs between masking
472
+ passes, and the whole pass repeats until nothing changes (a tail that never
473
+ settles is replaced by the mask).
474
+ - The Cursor model-family warning names the selector the operator typed and
475
+ the routed selector actually passed to Cursor.
476
+ - Every harness caps its map of tool calls still waiting on a result at 256
477
+ entries (Claude, Kimi, Grok, and Cursor kept them all), and a completion
478
+ report status line may end in a semicolon (`Status: completed;`).
479
+ - `worktree remove` of a parent no longer orphans worktrees of Runs launched
480
+ inside it: clean, merged nested worktrees are removed first, and dirty or
481
+ unmerged ones refuse with `nested_worktrees_block_remove` and a per-nested
482
+ command (`--force` does not reach them). Reap refuses a pool path holding
483
+ nested worktrees (`nested_worktrees_present`), a nested Registry that
484
+ appears mid-removal refuses with `nested_registry_appeared`, and an
485
+ unreadable nested Registry refuses even with `--kill-live`.
486
+ - A Codex workflow stage whose schema has an object with no declared
487
+ properties (including through a local `$ref`) no longer fails every
488
+ attempt: it uses the prompt path instead of strict mode, which closed the
489
+ object to zero keys. A direct `codex --output-schema` with such a schema is
490
+ refused at preflight with `invalid_output_schema` naming the path.
491
+ - A dry-run `workflow resume` no longer cancels or reaps a stale scope child,
492
+ changes status, persists a budget, or records an approval; it only
493
+ journals. `workflow approve` on a failed workflow points at `workflow
494
+ resume`, and on a running one says the gate is not open yet.
495
+ - A relative `--prompt-file` falls back to `--cwd`, and the not-found error
496
+ names both paths tried.
497
+ - The unread-mail scan cannot block on a FIFO named like mail; the shared
498
+ bounded record reader opens non-blocking.
499
+ - Small surface fixes: the Registry writes `.delegate/.gitignore`;
500
+ `--include-dirty` is a warned no-op in safe mode and reports `includeDirty:
501
+ false`; `runs show` names the real readers; a timed-out `wait --json` warns
502
+ and names `--structural`; `no_matching_worktrees` names the Registry it
503
+ searched.
504
+ - A `--mail-push` Codex run no longer dies before the model starts. Delegate
505
+ injected `-c hooks=true`, which Codex 0.157 rejects at config load because
506
+ `hooks` is a table; it now passes `--enable hooks` (the same as `-c
507
+ features.hooks=true`) and does not add it twice when it is already present.
508
+ - `--notify` room pings work against post 0.9.0. The notifier no longer passes
509
+ `--allow-self`, which post now rejects as an unexpected argument, and the
510
+ message-id match accepts post's room ids (which have no microsecond field)
511
+ as well as channel ids, so `messageId` is no longer empty for a room ping. A
512
+ room ping is a workspace fan-out that never reaches its own sender, so
513
+ `--notify` naming your own room reaches the room's other participants and
514
+ not the launching session; the troubleshooting guide now says so.
515
+ - On a Python older than 3.11 (Xcode's 3.9, for example), `bin/delegate.py`
516
+ and the `delegate_agent` package now exit `2` with a message naming the
517
+ interpreter version and executable they found, instead of a raw
518
+ `ImportError` from inside the package. The tracked
519
+ `bin/delegate-profile-shim` picks a 3.11+ interpreter itself (`python3`,
520
+ then `python3.14` down to `python3.11`, then Homebrew's, then
521
+ `/usr/local/bin/python3`), honors a validated `DELEGATE_PYTHON` (an override
522
+ older than 3.11 is refused, not bypassed), and exits `2` with a plain
523
+ message when none is found.
524
+ - The Codex and `post` argv Delegate builds is now tested against the
525
+ installed binaries (`tests/test_real_binary_contracts.py`), which is how the
526
+ two dead flags above shipped. A `codex` or `post` on `PATH` that fails
527
+ `--version`, times out, or cannot register the throwaway room now fails the
528
+ suite with its command, exit code, and output instead of skipping it; a
529
+ class skips only when its binary is absent or
530
+ `DELEGATE_SKIP_REAL_BINARY_CONTRACTS` is truthy, and says why.
531
+ `pytest-xdist` workers now see the real HOME through
532
+ `DELEGATE_TESTS_ORIGINAL_HOME`.
533
+ - A run that fails keeps what the child had produced. A failed, timed-out, or
534
+ (opt-in) capped run's completion report now quotes the child's last
535
+ substantive assistant text, bounded and redacted, under "Partial output
536
+ recovered before the run stopped. This is not a completion report", as a
537
+ cancelled run's already did. Pi, OMP, and OpenCode keep that text across
538
+ turns and steps, so a long review followed by a tool turn and a provider
539
+ error is still recoverable (OpenCode used to clear it at every step). A
540
+ call-mode timeout or output overflow, including a child that had already
541
+ exited before Delegate noticed the overflow, returns the buffered draft as
542
+ `diagnostics` on the error (also flattened into the JSON error):
543
+ `partialText` (redacted and bounded), `stdoutTail`, and `stderrTail`; text
544
+ mode prints the partial text to stderr.
545
+ - `followup` errors now say what is true. A source with no recorded native
546
+ session (launched with `--no-resumable`, before Codex and Claude work runs
547
+ saved their session by default, or as a workflow `agent()` call without
548
+ `resumable=True`) is refused with `session-missing` and pointed at `delegate
549
+ resume <handle>`, no longer told to relaunch with `--resumable`. A session
550
+ that was saved but cannot be found when resumed fails as `session_expired`
551
+ (`failureKind: session_lost`); the message names the usual cause, a launch
552
+ under a different account than the one holding the session, and offers
553
+ `delegate resume`.
554
+ - `resume` and `followup` refuse a known option of that command that appears
555
+ in the prompt tail (`delegate followup x fix it --dry-run`) with
556
+ `option_after_handle` before anything launches, instead of sending it to the
557
+ child as prompt text while the run launches with the defaults. Put `--`
558
+ before the prompt to send such a token as literal text. `followup` accepts
559
+ options on either side of the handle but only before the prompt text, and
560
+ `resume` only before the handle; an option-shaped token that belongs to
561
+ another command keeps the existing warning.
562
+ - A workflow structured retry on Codex or Claude whose resumed session cannot
563
+ be found (`session_lost`, reason `session_expired`) now falls back to a
564
+ fresh relaunch in the same worktree instead of ending, without spending a
565
+ retry; the journal records `agent_structured_retry` with `strategy:
566
+ "relaunch"` and `fellBackFrom: "resume"`. A fresh child redoes the task, so
567
+ the fallback relaunches only over a worktree known to be untouched, and
568
+ otherwise the call is refused (`agent_structured_retry_refused`) as
569
+ `work_changed_session_missing` when an earlier attempt already changed the
570
+ worktree, or `work_state_unverified` when that could not be checked. The
571
+ work summary now records `fileInspectionStatus` next to
572
+ `commitInspectionStatus` (each `verified` or `unverified`), because a failed
573
+ `git status` used to read as zero changed files; `noChanges` is true only
574
+ when both are `verified` and show nothing. In work mode both the prior
575
+ attempt and the resumed attempt must carry a verified summary that reports
576
+ no changes, and a missing summary, or one from a Delegate that predates
577
+ `fileInspectionStatus`, counts as unverified. Safe and call children have no
578
+ summary and keep the fallback.
579
+ - `worktree reap --path P --older-than N --yes --force` now removes a pool
580
+ entry that has no run record but that Git still links; `reap` used to skip
581
+ it as `live_backlink` even with `--force`, and the only way out was `git
582
+ worktree remove --force` by hand. Every check is re-run under the locks
583
+ immediately before removal. The pool scan must have no warning for the entry
584
+ (an entry with broken-looking metadata changed within the last 15 minutes,
585
+ or whose metadata cannot be read, is refused); Git must still list the path
586
+ as a worktree of its source repository; no Registry may hold a record for it
587
+ (`record_owns_path`, including a run that claimed it after planning, or
588
+ `record_in_other_registry` with the `--cwd` to run from); there must be no
589
+ uncommitted work by the definition above (`dirty`, `dirty_unknown`) unless
590
+ `--discard-uncommitted` is passed; no process may have its current directory
591
+ inside the path (`process_cwd_inside`, from one pass over `/proc` or `lsof
592
+ -d cwd`, never `lsof +D`) unless `--kill-live` is passed; and changed ledger
593
+ files are saved first. A process scan that cannot run, or cannot read one of
594
+ your own processes, refuses as `process_scan_unavailable`; other users'
595
+ processes are noted in a warning and do not block. The branch is kept, and
596
+ without `--force` the entry is still skipped as `live_backlink`, now with a
597
+ hint naming `--force`.
598
+ - Persistent worktrees no longer replace committed symlinks with placeholders.
599
+ The replacement showed up as typechanges that the next `git add -A` would
600
+ commit. A symlink committed to the repository is left as Git checked it out,
601
+ absolute or not; only an untracked symlink that points outside the source,
602
+ or at gitignored content, is replaced by a placeholder as it is mirrored in,
603
+ and the launch warning names it. Safe mode is unchanged and still blocks
604
+ every external symlink in its throwaway copy.
605
+ - `worktree show` on a followup, resume, or attached run names the run that
606
+ owns the worktree, following the lineage up through followups and resumes
607
+ (up to 16 hops, with a cycle guard) and putting `delegate worktree show
608
+ <owner>` first in `nextActions`.
609
+ - Two false or misleading model warnings are gone. Cursor labels are compared
610
+ after the context-window token (`256K`, `1M`) is dropped, so
611
+ `grok-4.7-xhigh` served as `Grok 4.7 256K Extra High` is the requested model
612
+ and not a `model_substitution`. A pinned call whose stream named a served
613
+ model is no longer told it "could not be verified"; that warning now fires
614
+ only when the stream was silent.
615
+ - Usage synopses in `--help`, `describe`, and `docs/cli-reference.md` now
616
+ match what the parser accepts; the parser was right in each case. `claude
617
+ call` takes `[--read-only|--pure]`, not both. `runs` and `ps` take
618
+ `[--summary | [--limit N] [--structural]]`, because `--summary` prints
619
+ counts and no rows and is refused with either. `snapshot` and `run-output`
620
+ take `(<handle>|--latest HARNESS)`. `run-output` takes `[(--stdout|--stderr)
621
+ [--raw | [--tail N] [--max-chars N]]]`, with a second usage line,
622
+ `[--no-redact] (--raw | --tail N)`, for the standalone `--raw` and `--tail
623
+ N` forms. `worktree remove` takes `[--keep-branch | [--force-branch]
624
+ [--force]]`.
625
+ - `describe --summary` is now described as the command index plus config
626
+ resolution, launch options, profiles, and workflows, larger than the default
627
+ and `--overview` views and smaller than `--full`, not as compact.
628
+ - The workflow supervisor relays `SIGINT` to its children the way it does
629
+ `SIGTERM` and `SIGHUP`, and journals `supervisor_signalled`. `SIGINT` used
630
+ to reach the interpreter's default handler, which raised `KeyboardInterrupt`
631
+ and marked the workflow failed without cancelling its children; they ran on
632
+ unowned until a later resume sealed them.
633
+ - The `agent_timeout` journal row written when a `followup()` call times out
634
+ now carries `key`, `label`, and `scope`, as the `agent()` timeout row does,
635
+ so a journal with several follow-ups says which step died.
636
+ - The workflow docs no longer say a resume adopts running children. A resume
637
+ cancels every child the previous attempt still had running and relaunches
638
+ that work; adoption covers only children that already finished (or that this
639
+ supervisor lifetime is itself still launching). Waiting on a live orphan and
640
+ taking its result is deferred work, not current behavior.
641
+ - `describe --full` documents the workflow DSL the runtime actually injects.
642
+ Its `globals` list is read from the runtime's new `WORKFLOW_DSL_GLOBALS`,
643
+ which the injector also checks, so it now names `park_gate`, `reject`,
644
+ `soft_park` and its helpers, `structured_attempt`, and `dry_run` (aliases in
645
+ `globalAliases`). `capabilities` is derived from the runtime's capability
646
+ table, adding the `agentKey`, `scopeKey`, `gateActions`, and `workspaceSpec`
647
+ entries the old literal lacked, and is also given structured as
648
+ `capabilityVersions`. The `agent()` signature is rendered from the runtime
649
+ method, so it gains `resumable`, `on_failure`, `key`, `base`, `env`, and
650
+ `setup`; the `pipeline`, `parallel`, and `workflow` entries document `key=`,
651
+ and `judges` documents per-entry dicts.
652
+ - A stdout or stderr line handler that raises (a registry lock timeout while
653
+ persisting progress, a parser bug) no longer kills the drain thread, which
654
+ stopped consuming the child's pipe and could strand the child. The drain
655
+ keeps reading to EOF, logs a `stream.handler_failed` event, and surfaces a
656
+ run warning that retried attempts carry forward.
657
+ - `cancel` no longer fails with a raw `TimeoutError` while another process
658
+ holds the registry lock. When the lock wait runs out it reads the record
659
+ unlocked, re-reads it with any pending finalize WAL overlaid just before
660
+ signalling, and signals only a launched child generation whose start identity
661
+ matches the run; a terminal result refuses as `run_already_terminal` and a
662
+ changed generation as `cancel_target_changed`. It then makes one bounded
663
+ attempt to record the cancelled outcome, reporting `registryLockBypassed`
664
+ with an unrecorded warning if the lock is still held, and refuses with
665
+ `registry_lock_busy` for an unlaunched record, a setup group, or a stale
666
+ seal.
667
+ - A bwrap safe child in a uv project without a `.venv` gets
668
+ `UV_PROJECT_ENVIRONMENT` pointed inside the run's own writable temp
669
+ directory, so `uv run` no longer fails creating `.venv` under the read-only
670
+ workspace bind. An existing `.venv` or an explicit `UV_PROJECT_ENVIRONMENT`
671
+ is left alone.
672
+ - Resume onto codex or claude keeps a source run's explicit `resumable`
673
+ opt-in, so `followup` on the resumed alias works (any other source now takes
674
+ the resumable-by-default launch setting); a cross-engine resume onto an
675
+ engine that cannot keep it drops the opt-in and says so.
676
+ - Resume and followup that reuse the source run's auth profile now say the
677
+ profile was inherited from the source run instead of warning about an
678
+ `--auth-profile` flag the user never typed.
679
+ - The suite resolves the production compact-temp root the way runs do. On
680
+ macOS it named `/var/tmp` where runs record `/private/var/tmp`, so six tests
681
+ failed and every subprocess run's temp directory leaked.
682
+ - A workflow no longer cancels its own live children as stale. Two `agent()`
683
+ calls from plain script threads could share one positional scope, and the
684
+ second call cancelled the first's running child. Stale-scope cancellation now
685
+ targets only children an earlier supervisor lifetime started (`agent_started`
686
+ records the lifetime's `incarnation`).
687
+ - Workflow adoption relaunches instead of waiting on or failing over a key's
688
+ latest child run when that run is cancelled, stale, or never launched
689
+ (`agent_adopt_skipped`).
690
+ - Resume seals a workflow child that never published a pid (stuck at `running`
691
+ or `creating_isolation`) once it has been idle for 300 seconds and its
692
+ recorded launcher (`launcherPid`) is dead or its pid was reused, instead of
693
+ refusing with `workflow_children_unsealed` forever. The runner re-reads the
694
+ record under the registry lock before every process start, the first included,
695
+ and publishes the child's pid only over a record that is neither terminal nor
696
+ cancel-requested, so a sealed launch never gains a child.
697
+ - `workflow run --dry-run` executes the script with its working directory set to
698
+ the `--cwd` workspace, as a real run's supervisor does. A dry run that times
699
+ out leaves the workspace as the working directory, because its abandoned
700
+ script thread may still be resolving relative paths.
701
+ - Persistent-worktree change accounting lists untracked files individually
702
+ (`git status --untracked-files=all`), matching the per-file launch-seeded
703
+ digest map. A seeded untracked directory used to be reported as one collapsed
704
+ entry the seeded filter could never match, so a quiet `work` run claimed a
705
+ change the child never made and reported success, a structured child with
706
+ unparseable output was refused as changed instead of relaunched, and the
707
+ worktree was retained as dirty. `workSummary.changedFiles` and
708
+ `rawChangedFilesCount` count files rather than directories for untracked
709
+ trees.
710
+ - A bare `429`/`rate limit` diagnostic classifies as `usage_limit` only when
711
+ account-context wording (`quota`, `usage`, `billing`, `subscription`,
712
+ `account`, `credit`) appears on the same line within 80 characters of it, in
713
+ either order. An unrelated `memory usage: 82%` line or a wrapped command's
714
+ `usage:` help text no longer pairs with a transient 429, which had marked the
715
+ run a quota failure, suppressed the structured correction retry, and pointed
716
+ operators at credential rotation.
717
+ - Codex work runs recover the last substantive agent message as the completion
718
+ report when the stream never sealed `turn.completed`, instead of classifying a
719
+ complete report as `resultQuality=empty`. A progress preamble is still not
720
+ adopted.
721
+ - `run-output` no longer claims no recoverable final message exists while the
722
+ child wrote stdout; the diagnostic states the byte count and names the command
723
+ that reads it.
724
+ - Workflow child launches that fail before publishing a run record record the
725
+ exit code and a bounded, redacted stderr tail on the attempt outcome and on a
726
+ new `child_stdout_unparsed` event (previously only the JSON decode error of
727
+ empty stdout was kept). `agent_structured_retry` carries the tail too. This
728
+ covers a child that exits `0` after writing empty or non-JSON stdout, on both
729
+ the initial `agent()` launch and `followup`.
730
+ - An empty `runs`/`ps` listing now adds the workspace-scope warning without
731
+ requiring `--group`/`--harness`, so a bare `runs --running` in a directory
732
+ with no Registry no longer prints an empty table that reads as dead lanes.
733
+ `wait --group` on a group stored in another workspace reports the same hint
734
+ and names the searched Registry.
735
+ - `workflow_not_found` errors for `status`, `run --resume`, and id-based verbs
736
+ name the searched workflow root and the `--cwd` form, so "stored elsewhere"
737
+ is distinguishable from "gone". The workflow profile-drift refusal names the
738
+ differing identity keys with their pinned and current values.
739
+ - `models <engine> --summary` points at `delegate help models`, and the focused
740
+ help states that `--summary` takes no engine argument.
741
+ - The linked-worktree registry-lock guard verifies suite ancestry before
742
+ reporting a violation, so a concurrent unrelated Delegate launcher holding the
743
+ same file is no longer reported as a suite escape.
744
+ - Test bootstrap pins `MISE_DATA_DIR`/`MISE_CACHE_DIR` suite-wide, so a
745
+ subprocess-bearing test no longer makes the mise python shim download an
746
+ interpreter into a temporary HOME and pollute stderr.
747
+ - The suite removes the compact child temp directory each tracked run manifest
748
+ records before it tears that temporary registry down, and asserts no test
749
+ leaves a net directory under the production owner root. Previously any test
750
+ that launched a real Delegate subprocess created `/var/tmp/dlg-<uid>/<token>`
751
+ that only `runs prune` could ever remove, and the temporary registry those
752
+ paths were derived from was deleted first. The run's own recorded child is
753
+ settled first: a live child whose command line carries one of the paths its
754
+ manifest names gets a bounded grace to reach its own exit (so a fixture child
755
+ writing through `$TMPDIR` finishes), and only then, or after being reaped, is
756
+ the exact recorded directory removed.
757
+ - `run-output`, `runs`/`ps`, and `snapshot` reconstruct a persisted run's
758
+ `usage` from one allowlisted normalized shape instead of copying the stored
759
+ object, so a record rewritten after the run (a non-isolated child shares the
760
+ workspace) cannot inject unknown keys, an unknown basis, or credential-shaped
761
+ text into a payload or the `usage:` line. A record whose basis is not one a
762
+ producer emits contributes no usage at all.
763
+ - The served-model comparison behind the `model_substitution` warning uses the
764
+ same harness-aware identity rules as the pinned check: OMP's provider-qualified
765
+ `provider/model` observation, a Cursor display name, and a Claude family alias
766
+ are the requested model, not substitutions. A clean OMP lane is no longer
767
+ labelled as substituted.
768
+ - Model warnings redact their model values: `model_substitution`,
769
+ `pinned_continuity_unverified`, and the configured-model/alias catalog warnings
770
+ can carry an operator- or provider-supplied selector, and all of them reach
771
+ `state.json`, `delegate.doctor.v1`, or the completion report. A
772
+ credential-shaped selector is masked instead of persisted.
773
+ - Workflow child launches that fail before publishing JSON carry the same
774
+ evidence on the *initial* `agent()` attempt as on followups: the outcome
775
+ records the exit code and a bounded, redacted stderr tail, and stdout that
776
+ never parsed emits `child_stdout_unparsed`. An exit-zero child whose envelope
777
+ is unusable is now reported as `invalid_envelope` rather than `nonzero_exit`.
778
+ - `workflow run` detects the systemd unit from the cgroup component that owns
779
+ the current process instead of any ancestor `.service` in the path, so an
780
+ ordinary interactive session under `user@<uid>.service` no longer receives the
781
+ severe `KillMode` warning. A unit under the per-user manager is queried through
782
+ `systemctl --user` rather than read as a system-manager lookup failure.
783
+ - The track's child `TMPDIR`/`TMP`/`TEMP` now points at a separate per-run
784
+ short-path directory (`/var/tmp/dlg-<uid>/<token>`, recorded as
785
+ `manifest.tempPath`) instead of the run scratch. The scratch path carries the
786
+ registry hash and run id, so a child binding a Unix socket under it overran
787
+ `sun_path`; the new root is short by construction, stays owner-only, is granted
788
+ as a second writable root in the Codex read-only permissions profile, is bound
789
+ read-write inside the optional bwrap boundary, survives failure and
790
+ cancellation like the scratch, and is removed only by the same run-owned prune
791
+ path. Runs recorded without a `tempPath` prune as before.
792
+ - The completion report carries a `model_substitution` warning and the run's
793
+ normalized token usage in a labelled delegate-authored block above the child's
794
+ text, and `run-output` (JSON and text) projects the persisted usage. A
795
+ substituted lane no longer reads as the requested model's clean work in the
796
+ report artifact, while the child's report text and its
797
+ `completionReportSource` attribution are unchanged.
798
+ - The `dev` extra ships `setuptools` and `wheel`, making the documented
799
+ `python -m build --no-isolation` form work instead of failing with
800
+ `BackendUnavailable`. The isolated build path is unchanged.
801
+
802
+ ### Changed
803
+
804
+ - The work write guard no longer protects `~/Code` or sibling checkouts by
805
+ default (`isolation.writeGuard.codeRoot` now defaults to `null`). Named
806
+ credential stores, profile homes and the installed Delegate runtime retain
807
+ their existing protection and re-open rules. Set `codeRoot` or `add` to opt
808
+ in to checkout protection. Codex's native sandbox retains its own write limits.
809
+ - Work-mode prompts gain two sentences saying nobody can approve during a Run
810
+ and the task is the approval unless the prompt asks only for a plan,
811
+ review, or read-only answer. Safe and call prompts are unchanged.
812
+ - Runs at `xhigh`, `max`, or `ultra` effort default to a 20-minute stall
813
+ window instead of 8, unless `--stall-minutes`, config, or
814
+ `DELEGATE_STALL_MINUTES` sets one; dry run, manifest, and snapshot report
815
+ `stallWindow` with its source.
816
+ - The `broker_binding_inactive` hint says one refusal while siblings launch is
817
+ usually launch-slot contention (relaunch once, with `--force-launch` if the
818
+ lane is marked) and a repeat means the binding is inactive.
819
+ - OMP alias objects with unknown keys name the allowed keys and point effort
820
+ synonyms at `thinking`; `help omp` carries a valid example. The
821
+ `cursor_auth_required` hint names the auth realm the Run used and the
822
+ `--auth-profile` alternative.
823
+ - **The tracked output cap is now off by default.**
824
+ `<engine>.trackedStreamMaxBytes` used to default to 16 MiB (64 MiB for Pi
825
+ and OMP) and stopped a run as `output_limit_exceeded` when a stream passed
826
+ it. It now defaults to `null`: a verbose run is never killed, truncated, or
827
+ hidden from the parser for its size, and `stdout.log` keeps the whole stream
828
+ and is flushed on every write, so its size and modification time follow the
829
+ child. Set a positive integer to opt an engine back into a cap; the
830
+ `output_limit_exceeded` message then names the key to raise or clear. OMP's
831
+ 256 MiB transport and 16 MiB per-record ceilings apply only with an opted-in
832
+ cap, and call mode keeps its own 16 MiB caps. Runaway streams remain the
833
+ stall watchdog's job (`runaway_output`). The 500-line limit in the
834
+ `events.jsonl` mirror was never a limit on `stdout.log`; its
835
+ `stream.lines_truncated` marker now says the child keeps running and
836
+ `stdout.log` keeps the full stream.
837
+ - A Devin answer is held in memory as a bounded excerpt. Devin prints plain
838
+ lines with no message boundaries, so Delegate treats everything it prints as
839
+ one running answer; past 30,000 characters that answer is the first 20,000
840
+ and the last 10,000 with an `[N chars omitted]` marker between them.
841
+ `assistantText`, the completion report, and a failed run's recovered partial
842
+ output read the excerpt, `assistantTextChars` keeps the full length, and
843
+ `stdout.log` keeps the full stream. The answer used to be rebuilt as one
844
+ string on every line, which was quadratic and, with the cap off, held the
845
+ whole run in memory.
846
+ - **Codex and Claude `work` runs are now resumable by default.** They save
847
+ their native session unless the launch says `--no-resumable` (JSON
848
+ `resumable: false`) or the engine config sets `codex.resumable` or
849
+ `claude.resumable` to `false` (both default `true`), so `delegate followup`
850
+ works without remembering `--resumable`. `--resumable` on a launch still
851
+ beats the config key, and `resume` takes the same default and
852
+ `--no-resumable`; a resume source recorded as exactly `true` keeps it, and
853
+ any other source takes the launch default. The default outranks
854
+ `codex.ephemeral` and `claude.noSessionPersistence`, which now apply only to
855
+ runs that are not resumable. Safe runs, call runs, `--pass-through` runs,
856
+ other engines, and workflow `agent()` children (unless the call passes
857
+ `resumable=True`) are unchanged, and `--no-resumable` is a quiet no-op
858
+ there. A succeeded persistent-worktree run that is resumable keeps its
859
+ worktree (`worktreeRetained: "resumable_session"`) instead of retiring it
860
+ when clean, so `followup` and `resume` can re-enter it; a fan-out of these
861
+ runs leaves one retained worktree per succeeded run until `worktree prune
862
+ --merged`, `worktree gc`, or `worktree remove` cleans up. Launch with
863
+ `--no-resumable` when a run's worktree should retire itself.
864
+ - **`--force` no longer overrides a live run on the worktree commands.**
865
+ `worktree remove`, `worktree prune`, and `worktree reap` refuse a worktree
866
+ that a live owner still holds (`run_active`, `run_not_terminal`,
867
+ `process_group_alive`, `worktree_leased`) even with `--force`, and the
868
+ refusal names the new `--kill-live`, the only override, which removes the
869
+ worktree out from under the run. `--kill-live` does not discard uncommitted
870
+ work or force the branch by itself. Removal is also refused for a running
871
+ run recorded in the worktree's own `.delegate/` registry
872
+ (`nested_run_active`) and for a nested registry, or a run in it, that cannot
873
+ be read (`nested_registry_unreadable`), each overridable only by
874
+ `--kill-live`. A skipped entry in `prune` and `reap` JSON carries the same
875
+ hint.
876
+ - Uncommitted work has one definition across `worktree remove`, `prune`,
877
+ `reap`, and completion retirement: what the lane actually changed. Files the
878
+ launch seeded from a dirty source that still match their digest, and the
879
+ ledger paths in `worktrees.retirementIgnoreGlobs` (default `.beads/**` and
880
+ `.papercuts.jsonl`), do not count, so a worktree that `prune` plans is one
881
+ `remove` accepts and a refusal names only the lane's own paths. Ledger edits
882
+ are saved before any removal: changed ledger files are copied and
883
+ byte-compared into `<Registry>/salvage/<worktree>-<UTC timestamp>/`. The
884
+ result reports `salvagePath` and `salvagedPaths`, the text output prints a
885
+ `saved N changed ledger file(s)` line, and completion retirement records
886
+ `worktreeSalvagePath` on the run. Deleted ledger files and the old name of a
887
+ renamed one are recorded in a `MANIFEST.tsv` (status, path, old path) in the
888
+ same directory and reported as `salvageRemovedPaths`. A copy that fails, or
889
+ a `git status` that cannot run, refuses the removal as
890
+ `ledger_salvage_failed`. Delegate never deletes a salvage directory, and a
891
+ source-gone `reap` deletes the path without a copy.
892
+ - **An OMP `provider/model` id you type is now pinned by default.** A
893
+ `provider/model` given as `--model`, input-JSON `model`, a positional raw
894
+ id, or a literal workflow `agent(model=...)` behaves as `--continuity-mode
895
+ pinned` unless you name a mode. Delegate launches it with a private
896
+ `--config` overlay that sets `retry.modelFallback` and
897
+ `retry.usageAwareFallback` to `false`, so OMP's own retry chains cannot move
898
+ the run to another provider (retrying the same model is unaffected, the
899
+ overlay beats your `config.yml`, and a dry run shows `--config <omp config
900
+ overlay>`). If another provider or model is served anyway, the run fails as
901
+ `model_continuity_paused` with a message naming what OMP tried to serve, for
902
+ example `requested opencode-go/glm-5.3, but omp tried to serve
903
+ fireworks/glm-5p3`. A delegate alias (a key of `omp.models`) and
904
+ `omp.defaultModel` stay `fungible`, so multi-subscription failover keeps
905
+ working; the run records and warns (`model_substitution`) which provider
906
+ answered, and `--continuity-mode pinned` on an alias pins it.
907
+ `--continuity-mode fungible` or `panel` on a typed id opts out of the
908
+ overlay. Workflows have no continuity passthrough yet, so there a literal id
909
+ is pinned and an alias is fungible.
910
+ - An `omp` model name that is not an `omp.models` alias and not a
911
+ `provider/model` selector fails with `invalid_alias` once a discovered omp
912
+ catalog exists, unless it is exactly a catalog model id; the error lists the
913
+ configured aliases and the nearest catalog selectors. OMP resolves a bare
914
+ name by fuzzy match against its own catalog and can serve a different
915
+ provider (a retired alias, `kimi`, resolved to `fireworks/kimi-k3`), so
916
+ Delegate refuses instead of passing it through. With no catalog the run
917
+ proceeds with a warning; `delegate capabilities refresh` lets bare names be
918
+ checked.
919
+ - **Claude `work` runs and their followups now run with background tasks
920
+ disabled.** Delegate sets `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` and adds
921
+ `--disallowedTools Monitor`, because a headless child ends when the model
922
+ stops and a background task or Monitor dies with the session. As a long gate
923
+ must then run in the foreground, Delegate also sets
924
+ `BASH_DEFAULT_TIMEOUT_MS` and `BASH_MAX_TIMEOUT_MS` to the run's own
925
+ `--timeout`, never below two hours (a run with no `--timeout` gets two
926
+ hours), so Claude Code's 2-minute default and 10-minute maximum do not cut a
927
+ foreground command off. `claude.disableBackgroundTasks: false` turns all of
928
+ it off. An auth profile's `env` or a workspace `--env` cannot undo these
929
+ variables: Delegate keeps its own values and warns `profile env NAME
930
+ ignored` or `workspace env NAME ignored` when the value differed. Every
931
+ framed `work` and `safe` prompt also carries a two-sentence rule that ending
932
+ the turn ends the run and that long jobs must run in the foreground and
933
+ finish before the final message; verbatim slash pass-through prompts are not
934
+ rewritten.
935
+ - **A finished run's scratch is now reclaimed on its own age.** Scratch, its
936
+ sidecars (for example mail-push engine homes), and the compact child temp
937
+ used to be removed only when the run record was pruned, so finished runs
938
+ kept their disk until then. The ambient retention pass now removes them for
939
+ terminal runs older than `tracking.retention.scratchDays` (default `3`; `0`
940
+ reclaims as soon as a run is terminal), keeps the run record, and stamps
941
+ `scratchReclaimedAt` and `scratchReclaimedBytes` into the run state;
942
+ `snapshot` shows both, and prints a `scratch reclaimed:` line in text.
943
+ `delegate runs reclaim [--older-than DAYS] [--dry-run]` does the same on
944
+ demand and lists sizes. Running, stale, and already-reclaimed runs are
945
+ skipped, and a run that fails is reported without stopping the others.
946
+ Reclaiming applies the recorded-path and ownership checks that pruning uses,
947
+ removes entries one at a time without following symlinks, and refuses a tree
948
+ that holds another owner's entry or crosses onto another filesystem. The
949
+ ambient pass spends at most 20 seconds, counted inside the walk and the
950
+ removal; a run it could not finish gets no marker, is reported as
951
+ `budget_exhausted`, and implicit reclaim then waits ten minutes before
952
+ continuing. `runs reclaim` has no budget or cooldown, and still works when
953
+ `tracking.retention.enabled` is `false`, which stops the ambient pass.
954
+ - `--forbid-commit` now works in every isolation mode, including `--isolation
955
+ none`, which used to be refused; with isolation omitted it still implies
956
+ `--isolation worktree`. Delegate creates run-owned git hooks (`pre-commit`,
957
+ `prepare-commit-msg`, `commit-msg`, and `pre-merge-commit`) that refuse, and
958
+ points `core.hooksPath` at them through one variable,
959
+ `GIT_CONFIG_PARAMETERS`. Codex's default environment filter drops names
960
+ containing `KEY`, `SECRET`, or `TOKEN`, which left the indexed
961
+ `GIT_CONFIG_COUNT` form without its keys and broke every git command;
962
+ `GIT_CONFIG_PARAMETERS` survives it. The post-exit check stays as the
963
+ backstop: it fails the run if commits remain ahead of the creation base (the
964
+ HEAD recorded at launch for `--isolation none`) or if the checkout's own
965
+ HEAD reflog shows a commit made since launch and left behind, on a side
966
+ branch or reset away, for in-place and worktree runs. An unreadable reflog
967
+ with nothing found otherwise leaves the policy unverified, which also fails
968
+ the run. The hooks are a tripwire, not a wall: `git -c
969
+ core.hooksPath=/dev/null commit` or `git commit-tree` bypasses them, and the
970
+ post-exit check can be defeated on purpose too.
971
+ - A mail send that reaches no inbox fails with `mail_not_delivered` (exit 1)
972
+ instead of returning `ok` with exit 0. The message names each recipient's
973
+ outcome and reason and states the eligibility rule, the diagnostics carry the
974
+ `msgId` and ledger rows, and the sent ledger is still written.
975
+ - `--auth-profile` precedence (flag, then environment, then config default)
976
+ now selects the config file as well as the profile: `--auth-profile
977
+ work|personal` with an existing overlay selects `config.NAME.json`, its keys,
978
+ and the child's `AI_PROFILE`, and warns when that replaces an ambient
979
+ `DELEGATE_CONFIG` or a different `AI_PROFILE`. A flag whose overlay is
980
+ missing warns that the environment's config and keys stay in effect, and the
981
+ resolver warns when an inherited detection variable overrides the config's
982
+ `profiles.default`. The profile shim now finds the flag anywhere before `--`,
983
+ keeps the last occurrence, and strips whitespace, as the Python parser does.
984
+ - Errors point at the command that does what was asked. `runs`/`ps` given a
985
+ run id, harness alias, `--id`, or `--alias` point at `snapshot` and
986
+ `run-output`; unknown `show`, `status`, `info`, `inspect`, `logs`, and
987
+ `output` subcommands suggest the per-run commands; `mail send --body`,
988
+ `--message`, and `-m` explain that the body is positional, `--file`, or `-`
989
+ (a bare `-` now reads stdin, as help already promised); and `followup` given
990
+ a resume-only option says the option belongs to `resume` and shows the
991
+ resume form.
992
+ - **Exit-code semantics: a child's exit code 0 no longer means success on its
993
+ own.** One outcome function now decides every run's `ok`, `status`, exit code,
994
+ persisted record, `wait` result, and workflow `agent()` result, so these can
995
+ no longer disagree. A run now fails with a nonzero exit, and `ok: false`, in
996
+ three cases where it used to report success. The first is a tracked child
997
+ that exits 0 without assistant text (`failureKind: no_assistant_text`).
998
+ Before this change the tracked envelope said `ok: true` with exit 0 while
999
+ state.json said `ok: false`; call runs already failed this case and still do,
1000
+ now with the same `failureKind`. The second is a tracked or call child whose
1001
+ provider's last unrecovered error was a quota or 429 refusal
1002
+ (`provider_quota`). The third is a tracked run whose `--expect-file PATH`
1003
+ deliverable is missing (`deliverable_missing`). Scripts that treated exit 0
1004
+ from an empty tracked run as success will now see exit 1. Every failed or
1005
+ cancelled run carries `failureKind`, a closed enum listed in
1006
+ `docs/cli-reference.md`. A missing `--expect-file` deliverable is reported as
1007
+ `deliverable_missing` even when the run also produced no assistant text: the
1008
+ verdict the caller asked for outranks the no-output label, and both fail the
1009
+ run. Summaries from `runs`/`ps`/`wait` carry `failureKind` whenever the record
1010
+ holds the key, `null` included, so a consumer that derives its verdict from a
1011
+ summary agrees with the envelope instead of falling back to the older
1012
+ result-quality veto (a quiet work run whose changes landed succeeded).
1013
+ - **A work run that changed files but ended quietly still succeeds.** A
1014
+ tracked `work` or `followup` run that exits 0 without assistant text, while
1015
+ its work summary shows changed files or commits, is `succeeded` with a
1016
+ `no_assistant_text` warning, and the envelope carries the `workSummary` so an
1017
+ orchestrator can adopt the work. Without changes the same run fails as
1018
+ `no_assistant_text`. Safe and call runs are unaffected. Only persistent or
1019
+ attached worktrees record a work summary, so a quiet run in any other
1020
+ isolation still fails. Pass `--expect-file` for a stricter check.
1021
+ - Provider signals are classified from the final attempt only. On the tracked
1022
+ and call paths, quota, provider-error, and unrecovered-error verdicts read
1023
+ only the last attempt's own error events, last error message, and stderr, so
1024
+ an earlier attempt's 429 no longer labels a later attempt that failed for a
1025
+ different reason, and a final attempt's unrecovered quota error survives the
1026
+ retry merge. The final attempt owns the provider terminal state as well: an
1027
+ earlier attempt's `turn.cancelled`, max-turns stop, or refusal-coded failure
1028
+ no longer decides a merged run whose retry or failover answered with text and
1029
+ exited 0. The call path's empty-success retry now joins the thread-retry and
1030
+ auth-fallback merges, so a first attempt's quota line cannot classify a clean
1031
+ retry as `provider_quota`.
1032
+ - `wait` reports a running record whose runner process is gone (`staleReason`
1033
+ `dead_pid` or `missing_pid`) as `failureKind: runner_lost` instead of
1034
+ `stalled`. `stalled` is kept for the stall watchdog, which workflows retry as
1035
+ transient; a lost runner is not retried.
1036
+ - Workflows: a structured `agent()` call whose work child changed its worktree
1037
+ but returned no valid structured result is retried only by resuming the same
1038
+ session and asking for the structured result alone. When the engine cannot
1039
+ resume, Delegate does not launch a fresh child into that tree; the call fails
1040
+ as `structured_invalid` and the `agent_structured_exhausted` journal event
1041
+ carries the child's `workSummary`. Safe-mode children and work children
1042
+ without changes keep the existing correction retry.
1043
+ - Tracked `safe`/`work` launches accept a repeatable `--expect-file PATH`. After
1044
+ the child exits, Delegate checks the child's process group for members that
1045
+ are still alive and records an `orphanedProcesses` warning before it
1046
+ terminates them.
1047
+ - Call-mode JSON carries `assistantText`, `assistantTextChars`, and
1048
+ `assistantTextTruncated` on every engine, the same fields tracked envelopes
1049
+ use. `text`, `textChars`, and `textTruncated` stay for one release as
1050
+ deprecated aliases.
1051
+ - Workflows: `agent(..., on_failure="typed")` returns a falsy `AgentFailure`
1052
+ when structured retries run out. It carries the last parsed candidate, the
1053
+ attempt count, `failureKind`, the run id, and the served model and provider;
1054
+ the default is still `None`. The new globals are `agent_meta(label)`, which
1055
+ exposes the child's outcome and served model and provider, and
1056
+ `capabilities`, which lets a script detect these features. A failed child no
1057
+ longer erases an earlier attempt's parsed candidate. A child that exits 0
1058
+ without text now receives a structured correction retry. Structured parsing
1059
+ tolerates raw control characters, including inside a prose-wrapped or fenced
1060
+ answer: a candidate the scanner finds is decoded again with the stray
1061
+ characters stripped before a quoted fragment of the damaged document can be
1062
+ returned in its place.
1063
+ - Bundled Codex declarations move to the GPT-6 line. `gpt-6-sol` and
1064
+ `gpt-6-luna` replace the `gpt-5.6-sol`/`gpt-5.6-luna` rows and `gpt-5.6-terra`
1065
+ is dropped outright, verified against live `codex` enumeration on both the
1066
+ work and personal profiles (2026-09-22): Sol carries `low`-`ultra` at a
1067
+ `medium` default, Luna carries `low`-`max` at `medium`. The `pi` and `omp`
1068
+ bundled selectors follow to `openai-codex/gpt-6-sol`, and the Codex discovery
1069
+ fixture mirrors the live payload for the new slug. Doc prose that named
1070
+ `gpt-5.6-sol` as the single bundled `max`-capable Codex model was already
1071
+ stale and now names the bundled set (`gpt-6-astra`, `gpt-6-sol`,
1072
+ `gpt-6-luna`).
1073
+ - Bundled Claude declarations replace `claude-opus-5` with `claude-opus-5-5`,
1074
+ and the pinned-continuity error prose names the new id.
1075
+ - Bundled Grok declarations bumped to 4.7. The Grok CLI now ships `grok-4.7` as
1076
+ its upstream default (bundled rows: `grok-4.7`, `grok-4.6`). Cursor's 4.7
1077
+ ladder drops the `cursor-` prefix the 4.5/4.6 rows carried, so the bundled
1078
+ Cursor rows and the fixed-effort selector table now name `grok-4.7-xhigh` and
1079
+ `grok-4.7-xhigh-fast`; the still-served `cursor-grok-4.6-xhigh*` selectors
1080
+ stay in the fixed-effort table. The Grok discovery fixture mirrors the live
1081
+ `grok models` output, including `grok-4.7-build-fast`.
1082
+ - The skill-review preamble is explicitly bounded: read the served skill index
1083
+ once, read only the skills judged relevant, and do not run discovery CLIs to
1084
+ enumerate skills. The requirement stays mandatory; it no longer reads as an
1085
+ open-ended discovery task.
1086
+ - `workflow reject`'s `agent_rejected` event records `rejectedBy: "coordinator"`,
1087
+ and the workflow DSL `reject(key, reason, by=...)` accepts `seat`,
1088
+ `merge-gate`, or `coordinator`. Emitters that declare nothing keep the legacy
1089
+ event shape, so a missing `rejectedBy` means unknown, not seat failure.
1090
+ - A structured-output resume retry re-renders the target schema into the
1091
+ correction prompt instead of asking the model to recall the shape; both GLM
1092
+ review retries had rebuilt a root-array schema as an object wrapper and failed
1093
+ again.
1094
+
1095
+ ### Security
1096
+ - Native Codex and Claude session files now persist for every work run,
1097
+ because those runs are resumable by default. Codex's rollout under
1098
+ `CODEX_HOME/sessions` and Claude Code's transcript under its `projects`
1099
+ directory hold the prompt as sent, the child's replies, and tool inputs and
1100
+ results (file contents the child read, command output). They live in the
1101
+ harness's own store, outside `.delegate/`, outside Delegate's redaction, and
1102
+ outside `runs prune` and the worktree cleanup commands, and Delegate does
1103
+ not prune them. A profile with a separate `CODEX_HOME` or Claude config
1104
+ directory keeps them in that account's store. Reduce the footprint with
1105
+ `--no-resumable`, `codex.resumable: false`, or `claude.resumable: false`.
1106
+ The untrusted-input boundaries are unchanged: safe runs, call runs (Claude
1107
+ `call --pure` still passes `--no-session-persistence`), `--pass-through`
1108
+ runs, other engines, and workflow children without `resumable=True` never
1109
+ save a session.
1110
+ - **Work runs now have a write guard, on by default on Linux.** Work mode runs
1111
+ the child with the caller's own filesystem rights, so one confused lane (`rm
1112
+ -rf ~`, a stray redirect into a sibling checkout) could destroy things
1113
+ nobody can recreate. The guard is a protect-list, not a home allowlist: a
1114
+ named set of irreplaceable paths becomes read-only and everything else stays
1115
+ writable, and reads are never restricted. By default it protects, each only
1116
+ when it exists, the credential stores `~/.ssh`, `~/.gnupg`, `~/.config/gh`,
1117
+ `~/.config/gcloud`, `~/.aws`, `~/.azure`, `~/.kube`, `~/.netrc`,
1118
+ `~/.git-credentials`, and `~/.password-store`; `~/.ai-profiles`; the
1119
+ installed Delegate runtime (`~/.local/bin/delegate` plus `~/.delegate/src`,
1120
+ `releases`, `bin`, and `config*.json`); and the code root (`~/Code`), so a
1121
+ lane in one checkout cannot write into a sibling. Inside those paths the
1122
+ run's own needs are re-opened: the execution root, the git common directory,
1123
+ the run registry, run scratch and compact temp, mail-push homes, and the
1124
+ selected engine's home. `/tmp`, `TMPDIR`, and home caches such as `~/.cache`
1125
+ are not protected. The guard never applies to safe mode, `--pass-through`
1126
+ runs are not guarded, and it does not stop reads, network use, or use of
1127
+ credentials already in the environment.
1128
+ - Backends and platform defaults for the write guard. On Linux the child runs
1129
+ under bubblewrap (`bwrap --dev-bind / /` with each protected path bound
1130
+ read-only), preflighted before launch; the execution root is bound as a
1131
+ mount of its own so a lane cannot rename its checkout away, a new hard link
1132
+ to a protected file cannot be made, and writes through symlinks to protected
1133
+ paths are refused. **On macOS the Seatbelt guard is opt-in:** with
1134
+ `isolation.writeGuard.macosSeatbelt` at its default `false`, the guard
1135
+ status is `off` with no warning and no refusal, and setting it `true` opts
1136
+ in to the `sandbox-exec` guard, which then wraps every engine except a Codex
1137
+ lane whose own `workspace-write` sandbox is on (a Codex lane with its sandbox
1138
+ bypassed is wrapped, and that combination is not yet live-tested). To keep the `external-sandbox` policy
1139
+ profile but put Codex's own sandbox back for work lanes, set
1140
+ `policy.harness.codex.work.bypassApprovalsAndSandbox` to `false`; Delegate
1141
+ then emits `--sandbox workspace-write` with `--add-dir` roots for the git
1142
+ common directory, registry, scratch, temp, `--writable` paths, and existing
1143
+ home caches.
1144
+ - Configure and inspect the write guard with `isolation.writeGuard`
1145
+ (`enabled`, `onUnavailable`, `macosSeatbelt`, `codeRoot`, `add`, `remove`,
1146
+ `writable`, `homeCaches`; an unknown key or wrong type fails as
1147
+ `invalid_isolation_config`), the `DELEGATE_WRITE_GUARD` environment variable
1148
+ (`off`, `0`, `false`, or `no` disables, `on`, `1`, `true`, or `yes` enables,
1149
+ and it overrides the config), and `--writable PATH` (repeatable, `work`
1150
+ mode, CLI-only), which re-opens an existing path for one run. The plan
1151
+ (backend, protected paths, and each re-open with its reason) is recorded in
1152
+ the run manifest under `writeGuard` and printed by `--dry-run`, and
1153
+ work-mode prompts gain a two-sentence note naming the protected paths so a
1154
+ lane reports a blocked write instead of working around it. When no backend
1155
+ is usable, `isolation.writeGuard.onUnavailable` decides: `warn` (the
1156
+ default) launches unguarded and records a warning, and `refuse` fails the
1157
+ launch with `write_guard_unavailable`. On Linux with `warn`, a bwrap
1158
+ preflight that fails on one unbindable path drops only that path (listed
1159
+ under `writeGuard.unbound`, with a warning) instead of the whole guard; when
1160
+ a protected path was dropped the status is `partial` rather than `enforced`
1161
+ and the warning starts "work write guard is PARTIAL". `refuse` never
1162
+ retries.
1163
+ - Only the selected engine's own home variable (`CODEX_HOME`,
1164
+ `CLAUDE_CONFIG_DIR`, `KIMI_CODE_HOME`, or that engine's default directory)
1165
+ can re-open a directory inside a protected path, and only when it is
1166
+ provably one profile. The home must itself carry an identity file
1167
+ (`.claude.json`, `.credentials.json`, or `auth.json` beside `config.toml`),
1168
+ and a bounded scan below it (three levels, no symlinks, at most 2000
1169
+ directories) must finish and find no other profile's home. A parent of
1170
+ profiles, a home that is itself protected, and a scan that hits the cap or
1171
+ cannot list a directory are refused: the directory stays read-only, the
1172
+ manifest lists it under `writeGuard.refused` with the reason, and the run
1173
+ gets a warning. An engine Delegate has no home variable for (droid, for one)
1174
+ gets no automatic re-open; name its profile directory in
1175
+ `isolation.writeGuard.writable` or pass `--writable`. Known limits: a second
1176
+ profile nested deeper than three levels is not found; a hard link that
1177
+ already exists between a protected file and a writable name is the same
1178
+ inode, so a write through it changes the protected file; and a protected
1179
+ path that is itself a symlink is protected at its target while the link
1180
+ stays replaceable.
1181
+ - A lane started through an estate launcher (`estate-claude`, `estate-codex`,
1182
+ `estate-omp`, any program named `estate-*`) gets the profiles root
1183
+ (`ESTATE_AI_PROFILES_ROOT`, then `AI_PROFILES_ROOT`, then `~/.ai-profiles`)
1184
+ re-opened, recorded as "estate launcher writes profile state". The launcher
1185
+ picks an account, refreshes its token, and writes session, plugin, and lock
1186
+ state there on every launch, so protecting it stopped `estate-claude` before
1187
+ Claude started. Those lanes can therefore write every profile's files; lanes
1188
+ started any other way keep `~/.ai-profiles` protected, and a Codex lane with
1189
+ its own sandbox on never gets it as a writable root.
1190
+
1191
+ ## [0.31.0] - 2026-09-14
1192
+
1193
+ ### Harness compatibility audit (2026-09-07)
1194
+
1195
+ Eleven audits, one per supported harness plus a shared pass, checked Delegate's
1196
+ assumptions against each vendor's current release. Every finding that could
1197
+ produce a wrong run outcome is fixed below.
1198
+
1199
+ #### Per-engine fixes
1200
+ - Codex: `--search` and `--ask-for-approval` are declared on the interactive TUI
1201
+ and never reached `codex exec`, so `policy.webSearch` was a no-op and the
1202
+ approval policy was never stated. Both now ride `exec` as `-c
1203
+ web_search="live"` and `-c approval_policy="never"`. Codex usage survives a
1204
+ patch, and a preamble is no longer promoted to an answer after one.
1205
+ - Claude: safe and read-only call emit `--permission-prompts none` when
1206
+ discovery has seen the flag, so a prompt is denied rather than hanging. A
1207
+ pinned run judges the served model by Claude's own naming instead of string
1208
+ equality, and `--continuity-mode pinned` refuses an alias that names no family
1209
+ (`best`, `opusplan`, `default`) at preflight.
1210
+ - Cursor: `cursor call --read-only` emits `--mode ask`, which Cursor documents as
1211
+ read-only; safe mode deliberately does not, and keeps relying on the isolated
1212
+ workspace copy and the safe-review prefix. Tool events are parsed from the
1213
+ shape Cursor actually emits, and a pinned run accepts the display name Cursor
1214
+ reports in place of the requested selector.
1215
+ - Grok: a response is sealed on usage rather than on `end`, so a multi-response
1216
+ stream keeps every part. The effort vocabulary is `low, medium, high, xhigh`;
1217
+ `max` was never accepted.
1218
+ - Oh My Pi: work mode pins `--approval-mode yolo` and names its working
1219
+ directory with `--cwd`. An omp selector missing from a fresh account catalog
1220
+ now warns, because omp resolves an unknown id by fuzzy match.
1221
+ - Pi and Oh My Pi: the `--thinking` vocabulary is `off, minimal, low, medium,
1222
+ high, xhigh, max`, and omp additionally accepts `auto`.
1223
+ - Kimi: the goal summary is kept rather than dropped, pass-through runs pin
1224
+ `--output-format text`, and bwrap binds the selected Kimi home.
1225
+ - OpenCode: read-only runs set `OPENCODE_DISABLE_CLAUDE_CODE=1`, and discovery
1226
+ probes with `--pure models --verbose`.
1227
+ - Devin: the read-only argv is documented-compatible with 3000.6.14, but that
1228
+ release's read-only behavior is unproven, so the 3000.4.x gate is retained
1229
+ until `DELEGATE_DEVIN_BEHAVIOR_TEST` passes against it.
1230
+
1231
+ #### Transports
1232
+ - Cursor Agent and Oh My Pi prompts move to stdin, verified live against
1233
+ 2026.09.02-c22c1a3 and 18.1.13. That deletes their argv redaction constants,
1234
+ their membership in the 100 KiB argv guard, and the omp flag-like-prompt
1235
+ rejection, and it takes the prompt out of `/proc/<pid>/cmdline`. Kimi is now
1236
+ the only engine on argv transport and the only one whose prompt Delegate
1237
+ redacts.
1238
+
1239
+ #### Stream parsing
1240
+ - An error event with a `message` or `error.message` now records a `failed`
1241
+ terminal on every harness, and a `result` carrying only `is_error: true` does
1242
+ the same instead of being read as a clean success.
1243
+ - A non-JSON stdout line from kimi, opencode, or pi is no longer discarded in
1244
+ silence: it is counted and sampled, bounded and redacted, while the
1245
+ malformed-tool-output protection that stops a raw envelope becoming an answer
1246
+ is unchanged.
1247
+ - Event types no parser branch handles are counted, so the next vendor rename
1248
+ is visible rather than silent.
1249
+ - Run records and snapshots carry `malformedLines`, `malformedSamples`,
1250
+ `unhandledEventTypes`, and `unhandledEventTypesTruncated`. The block appears
1251
+ only when there is something to report, and it survives a retry or auth
1252
+ fallback instead of being reset with the accumulator. A merged usage record
1253
+ keeps grok's `costUsd`.
1254
+ - The stall watchdog tracks opencode and grok tool lifecycles. Kimi and Devin,
1255
+ whose stdout is silent by design during tool execution, are exempt from the
1256
+ engine-default detector only when the run carries a finite timeout; an
1257
+ explicit `stallMinutes` is always honored.
1258
+
1259
+ #### Structured output
1260
+ - One engine-keyed eligibility helper decides whether a schema can be enforced
1261
+ natively. Claude and Codex both require an explicit object root, and Claude
1262
+ additionally requires the serialized argv value to stay under the Linux
1263
+ argument-length limit. An ineligible workflow schema falls back to
1264
+ prompt-and-parse with the reason journaled; a direct `claude --output-schema`
1265
+ fails at preflight with `schema_not_native` instead of forwarding an argv the
1266
+ API will reject.
1267
+ - In the structured retry loop, an attempt that fails with no assistant text
1268
+ clears native enforcement for the remaining attempts and embeds the original
1269
+ schema in the correction prompt, including on the resumable path.
1270
+
1271
+ #### Deferred, recorded as decisions rather than omissions
1272
+ - Devin's 3000.4.x read-only version gate stays until a behavioral probe passes
1273
+ on 3000.6.x; Devin is not installed on the machine that ran the audit.
1274
+ - Claude's `ultracode` effort is not added. Discovery overrides the static enum
1275
+ with a warning list that omits the level, so an enum edit alone is unreachable
1276
+ and would need a compatibility exception with its own proof.
1277
+ - Usage-limit cooldowns stay Codex-only. Widening the valid-tool set alone
1278
+ changes nothing; the write and check paths are engine-specific.
1279
+ - Followup and resume support for grok, droid, opencode, pi, kimi, and devin is
1280
+ verified possible and additive, but each needs a live round trip to prove and
1281
+ none was run.
1282
+ - Grok stays on its current stream format, and `validate_schema_subset` still
1283
+ rejects `$defs` and `format`.
1284
+
1285
+ ### Workflow resume and stale runs (2026-09-14)
1286
+
1287
+ Found in the dogfood window after the 0.31.0 candidate was promoted: one
1288
+ workflow that lost its supervisor 28 times left 10 children listed as `stale`
1289
+ forever, and every resume that reached one of them failed its thunk with
1290
+ "already terminal (stale)" instead of relaunching.
1291
+
1292
+ - `delegate cancel` seals a `stale` run whose tracked pid is dead as
1293
+ `cancelled`, with `staleReason: dead_pid` on the record and a warning that
1294
+ nothing was signalled, instead of refusing it with `run_already_terminal`.
1295
+ A `stale` run with no pid at all is still refused: under the registry lock
1296
+ that can be a launch that has not published its pid yet. A dead leader
1297
+ whose recorded process group still has members is refused with
1298
+ `run_group_alive`, naming the group, because a dead pid is not proof the
1299
+ run's work stopped and the group id may already belong to someone else.
1300
+ - `workflow run --resume` and `workflow approve` seal the prior attempt's
1301
+ in-flight children before the new supervisor starts, the same way `workflow
1302
+ kill` does, and journal `attempt_superseded` with the lost supervisor's pid,
1303
+ its last status, and the sealed children. The replay then relaunches the
1304
+ agent instead of tripping over the orphan. The seal runs after gate
1305
+ validation and never on `--dry-run`, which launches no replacement.
1306
+ - The workflow supervisor handles `SIGTERM` and `SIGHUP` by requesting the
1307
+ same cooperative cancellation the stall watchdog uses. The signal handler
1308
+ itself only records; a wakeup-pipe relay thread journals
1309
+ `supervisor_signalled` and sets the cancel event in ordinary thread context,
1310
+ so the handler never takes a lock. Admission closes, in-flight children are
1311
+ cancelled, retry worktrees are released, and the supervisor exits through
1312
+ its normal cleanup with `status: failed`, `signal`, `watchdogReason:
1313
+ signal:<NAME>` (a genuine watchdog reason that started the shutdown is
1314
+ kept, and its error text is not replaced by the signal's), and the
1315
+ `cancelled` list on `status.json`. Before any terminal status is chosen or
1316
+ published the supervisor drains the relay, so a signal already delivered
1317
+ to the process is on the record consumers read as final; one that lands
1318
+ after the last child completed is recorded on the `succeeded` status as
1319
+ `signalAfterCompletion`. Each drain is answered only by its own marker,
1320
+ and a drain the relay did not acknowledge in time is published as
1321
+ `signalDrainIncomplete: true` on the terminal status instead of as a
1322
+ settled record, which `workflow wait` and `workflow watch` repeat in every
1323
+ output mode; the workflow lock is released only once the relay can no
1324
+ longer write (the supervisor fences it at exit, waiting without bound
1325
+ in-process and, as the detached supervisor process, ending itself
1326
+ unconditionally while it still holds the lock rather than letting a writer
1327
+ outlive ownership; every exit from the lock context, exceptional or not,
1328
+ fences the relay and hands the lock to a delivery in flight, which closes
1329
+ it when it completes; arming the relay rolls back handlers, wakeup fd, and
1330
+ descriptors when it fails before the reader thread exists, and the read
1331
+ end is owned by whichever of the reader and the rollback claims it first). A repeated signal is recorded, not re-raised. `workflow kill` notes which
1332
+ children were already terminal before it signals and completes its
1333
+ `cancelled` report from the whole group afterwards (`observedIn: registry`
1334
+ on entries it did not cancel itself), so a supervisor sealed by the kill's
1335
+ own SIGTERM, a child admitted just before cancellation closed, or a
1336
+ supervisor cut short by the SIGKILL escalation still yield a full list; the
1337
+ `killed` status drops only the diagnostics the signal itself produced. A signal used to end the supervisor with the lock released,
1338
+ `status.json` still `running`, and no record of why.
1339
+ - A `--continuity-mode pinned` run that completes without any harness model
1340
+ observation carries a `pinned_continuity_unverified` warning naming the
1341
+ harness, on tracked runs and on ungrouped `call` payloads alike. Claude and Oh My Pi were observed reporting the served model in
1342
+ the dogfood window; Codex and Grok streams carry no model field, so on those
1343
+ engines a pinned run is pinned in name only and now says so.
1344
+ - `delegate models` marks a configured binary that does not resolve from the
1345
+ Delegate process (`binaryMissing: true`, `(missing)` in text) instead of
1346
+ printing the configured path as if it were installed. The check is the
1347
+ launch check: `shutil.which` on the configured value, no `~` expansion.
1348
+
1349
+ ### CI and runtime hardening (2026-09-07)
1350
+
1351
+ - Pinned runtime snapshots and workflow attempt directories are published while
1352
+ still writable and sealed to `0o500` only after the rename. macOS `rename(2)`
1353
+ refuses to move a directory that lacks owner write permission, which made
1354
+ every pin-store test fail on the macOS CI runner while Linux passed. A stale
1355
+ temporary snapshot that cannot be removed now raises a typed
1356
+ `runtime_snapshot_collision` error, and the writable pre-pass walks the tree
1357
+ through directory descriptors so a swapped symlink cannot redirect the chmod.
1358
+ - Test process guards read `ps -ww` and pin `COLUMNS=80`; narrow runner
1359
+ terminals truncated the argument column and left children unreaped.
1360
+ - `trackedStreamMaxBytes` is a per-engine config value: 16 MiB by default and
1361
+ 64 MiB for Pi and Oh My Pi. The limit is resolved at request build and
1362
+ pinned into the run context and manifest, so a config edit does not change
1363
+ an already-launched run. Limit errors name the engine and which limit fired.
1364
+ - Harness discovery fingerprints an explicitly configured wrapper whose
1365
+ basename is not another harness's binary name (an `estate-pi` style wrapper
1366
+ now discovers), while still refusing ambiguous basenames and any basename
1367
+ that names a different harness.
1368
+ - Harness event capture no longer duplicates the final assistant text when a
1369
+ completion event repeats the last streamed chunk.
1370
+
1371
+ ### Added
1372
+ - `describe` provides a compact command index; `describe --full` expands the
1373
+ command/config catalog. Help is generated from the same command specifications
1374
+ used to validate supported global options.
1375
+ - `workflow resume` aliases `workflow run --resume`; focused reject help,
1376
+ workflow typo suggestions, and additive error recovery fields reduce guesswork.
1377
+ `workflow watch --jsonl` streams events without retaining the full response.
1378
+ - Workflow pins use immutable per-attempt operational settings with effective
1379
+ values, origins, and digests, and bind the selected profile and credential
1380
+ namespaces.
1381
+
1382
+ ### Fixed
1383
+ - `delegate doctor` warns when `codex.profile` names an overlay file that does
1384
+ not exist. Codex reads the setting as `$CODEX_HOME/<name>.config.toml` and
1385
+ accepts a missing file silently, so a stale profile cost every run its overlay
1386
+ without a word.
1387
+ - A recognized option name typed after the prompt warns that it is being treated
1388
+ as prompt text.
1389
+ - A terminal reason is redacted before it reaches the run record.
1390
+ - Persistent-worktree launches preserve requested continuity and process-group
1391
+ termination grace through the shared request-to-run mapping.
1392
+ - Doctor distinguishes executing, installed, and last-promoted artifacts and
1393
+ verifies the outer launcher chain instead of equating matching version strings.
1394
+ - PI/OMP failed, aborted, and exhausted turns no longer become successful merely
1395
+ because the process exits zero. Later retry/compaction recovery remains supported.
1396
+ - Noisy OMP thinking deltas use bounded diagnostic sampling with explicit capture
1397
+ receipts. Useful output, individual records, and total ingress retain finite caps.
1398
+ - Safe Codex runs can write their designated scratch directory without granting
1399
+ source or metadata write access. Unsupported native permission configuration
1400
+ fails closed rather than falling back to broader workspace permissions.
1401
+ - Workflow replay reads the journal once; watch tails new bytes and handles
1402
+ interrupted final records. Approval/resume handles draining supervisors and
1403
+ rolls back approval when launch publication fails.
1404
+ - Attempt publication atomically refuses an existing destination, including empty
1405
+ directories. Conflicting worktree identity retains files instead of guessing a
1406
+ removal target, and limited run listings avoid probing logs for excluded rows.
1407
+
1408
+ ### Changed
1409
+ - The auto-injected skill-review preamble is behind
1410
+ `tracking.skillReviewPreamble.enabled`, default `false`. Call, slash
1411
+ pass-through, and `--pass-through` prompts never receive it either way.
1412
+ - Workspace mail setup is on by default; global `--no-mail` or
1413
+ `mail.enabled: false` opts out without suppressing `--notify`. Push remains
1414
+ opt-in.
1415
+ - Mail storage failures warn and disable launch-time mail instead of refusing
1416
+ the run; unreachable isolated mailboxes record manifest-only warnings.
1417
+ - The wrapped work prompt gains 303 UTF-8 bytes, which count toward the argv
1418
+ size guard; `--no-mail` avoids that overhead near the boundary.
1419
+ - Droid uses the same `--model <alias-or-model>` grammar as other engines. The
1420
+ positional model-alias form is retired.
1421
+ - Droid custom-model selectors use Factory's documented
1422
+ `custom:<Display-Name>-<index>` form. The previous id-based selectors no longer
1423
+ resolve: re-read `delegate models droid` and update any `droid.models` alias
1424
+ that pinned one.
1425
+ - Workflow resume requires current-format pins, attempt configuration and
1426
+ version-2 structural keys. Legacy formats are refused before child launch;
1427
+ start a new workflow instead of migrating old state. Gate approvals require
1428
+ the matching result hash.
1429
+ - Run progress, finalization and cancellation share one bounded mutable record.
1430
+ Snapshot output is computed from that record; new runs do not maintain a
1431
+ second mutable `snapshot.json`. Keep old and new runtime writers in separate
1432
+ workspace registries during development or cutover.
1433
+ - Routine progress updates recover only their own pending finalization record.
1434
+ Inspection remains lock-free and can observe a valid pending completion.
1435
+ Automatic retention is throttled and is not on the cancellation path.
1436
+ - Nested workflows share runtime state without replaying the journal again.
1437
+ New-agent and followup execution share locked replay and lifecycle decisions,
1438
+ including concurrent rejection and interrupted-result recovery.
1439
+ - Worktree maintenance shares safety predicates while retaining command-specific
1440
+ policies, retirement ignore-globs, and fresh checks before destructive changes.
1441
+ - CLI and input JSON normalize into one launch builder for tracked and call
1442
+ modes, retaining input-specific validation and workflow-session checks.
1443
+ Invalid JSON instruction modes return usage errors; Droid raw model IDs no
1444
+ longer become spurious worktree-planning aliases.
1445
+ - Shared metadata projections, typed isolation plans and retirement inputs, and
1446
+ a read-only record module reduce duplicated policy and circular imports.
1447
+ - Unit tests use owning modules while CLI contracts retain entrypoint coverage.
1448
+ Acceptance selects the pinned Ruff toolchain. Pytest uses private temporary
1449
+ state and ownership-checked process cleanup; runner parity retains complete
1450
+ logs and cancellation regressions.
1451
+
1452
+ ### Fixed
1453
+ - Claude `--output-schema` is accepted in tracked `safe`/`work` modes, not only
1454
+ `call`, and is passed natively as `--json-schema`, recorded in the manifest,
1455
+ and inherited on resume. Unblocks structured Claude review lanes such as
1456
+ deslop's `--runner delegate --lane claude`.
1457
+ - Workflow `schema=` validation now matches Claude's schema preflight: empty or
1458
+ duplicate `enum` values (JSON equality, integers beyond 2**53 and non-string
1459
+ object keys refused), repeated `required` or `type` entries are rejected
1460
+ before launch, and runtime enum membership uses the same JSON equality.
1461
+ Claude workflow children receive every supported schema natively.
1462
+ - Worktree retirement no longer treats the shared `.beads/` and
1463
+ `.papercuts.jsonl` ledgers as lane work, so a run that filed a papercut or
1464
+ closed a bead can retire its worktree instead of stranding it. Configurable
1465
+ via `worktrees.retirementIgnoreGlobs`.
1466
+ - `worktree prune` (and the auto-prune that runs at completion) no longer
1467
+ selects a worktree whose owning Run is still alive, reporting `run_active`,
1468
+ `run_not_terminal`, or `process_group_alive` instead. `--force` overrides.
1469
+ - `workflow run --dry-run` can no longer hang indefinitely on a script that
1470
+ waits for a human gate: scripts now receive a `dry_run` global, dry-run item
1471
+ threads are disposable, and `workflows.dryRunTimeoutSeconds` (default 300)
1472
+ bounds the run with a `dry_run_timeout` error.
1473
+
1474
+ ### Added
1475
+ - `delegate doctor` (read-only, `delegate.doctor.v1`) reports the live runtime
1476
+ digest against the last promotion stamp and warns when the installed runtime
1477
+ changed without a promotion, when the installed launcher drifted, and which
1478
+ workflow supervisors are still pinned to older runtimes. `delegate promote
1479
+ --actor WHO --source TEXT [--runtime-digest HEX]` writes the stamp
1480
+ (`~/.delegate/last-promotion.json`) under a lock, reading the live digest
1481
+ inside it.
1482
+ - Structured-output retries now resume in place when the harness supports it,
1483
+ retaining a safe temporary workspace across attempts and reaping it from
1484
+ durable child snapshots on timeout, kill, crash, or supervisor resume.
1485
+
1486
+ - `delegate workflow run --notify room:<name>|channel:<name>` rings a detached
1487
+ supervisor's owner when it pauses at a checkpoint, fails, succeeds, or times
1488
+ an agent out. The target survives resume and dry-run, and a notification that
1489
+ cannot be delivered is recorded as a `notify_degraded` journal event without
1490
+ changing the workflow's outcome.
1491
+
1492
+ ### Fixed
1493
+ - `agent_timeout` and `agent_structured_retry` journal rows carry the task key
1494
+ and label, so which lane died no longer has to be inferred by cross-referencing
1495
+ `agent_started` timestamps.
1496
+ - A persistent-worktree run warns at completion when its base is N commits behind
1497
+ the source branch — the child never saw work that landed after it was
1498
+ dispatched.
1499
+ - Parse-time option errors name `delegate dry-run`, which already validated an
1500
+ invocation without launching it. The hint appears only for launch-shaped
1501
+ commands, never when the caller has already typed `dry-run`, and a correction
1502
+ for a dry-run stays a dry-run instead of handing back a live launch.
1503
+ - `workflow approve` now accumulates approvals (`approvedKeys` in `approval.json`) instead of overwriting the single `gateKey`, so a resume that replays an earlier approved gate no longer re-pauses the run there.
1504
+ - Workflow `agent(schema=...)` on Codex no longer dies before launch when the
1505
+ schema has optional fields or a typed `additionalProperties` map: native
1506
+ `--output-schema` is used only for strict-compatible schemas, everything else
1507
+ falls back to the prompt-and-parse path the other engines use.
1508
+ - `parse_json_tolerant` now returns the last JSON value that validates against
1509
+ the schema instead of decoding from the first `{`/`[` in the text, so a
1510
+ markdown completion report with decoy brackets (`[T1]`, `{run, exit, note}`)
1511
+ no longer burns structured-output retries.
1512
+ - Workflow child failures report the child's JSON `error`/`message`/`runId`
1513
+ instead of only stderr (which was often just the persona preface).
1514
+ - `workflow run --resume` treats a key whose retries were exhausted as
1515
+ retryable: a finished child run is adopted, otherwise the agent re-runs,
1516
+ instead of replaying the cached failure straight back into the same gate.
1517
+
1518
+ - The workflow journal no longer sorts event keys: a structured result's key
1519
+ order is part of the data (scripts embed prior results via `repr()` in later
1520
+ prompts, which the agent cache key hashes), so a sorted replay missed every
1521
+ downstream key after a resume and re-ran the whole wave.
1522
+
1523
+ ### Added
1524
+
1525
+ - Workflow schema subset: `additionalProperties` may be a schema, typing a map
1526
+ with unknown keys.
1527
+
1528
+ ## [0.30.0] - 2026-08-22
1529
+
1530
+ ### Added
1531
+
1532
+ - Added an opt-in bubblewrap safe backend for eligible Linux safe runs. Set
1533
+ `isolation.safeBackend` to `"bwrap"` or use `DELEGATE_SAFE_BACKEND` to run
1534
+ zero-copy against the real workspace, bound read-only inside a bubblewrap
1535
+ boundary with gitignore-parity masks. The workspace `.delegate/` registry is
1536
+ hidden except for the current run's writable scratch, and `$HOME` is a private
1537
+ tmpfs where only the selected engine's config home is made writable by
1538
+ default. `isolation.bwrapBinds` adds explicit `{path, mode}` host paths. Each
1539
+ run preflights its final mount plan and launches with the exact probed binary.
1540
+ The backend fails closed when bubblewrap is unavailable, an untracked symlink
1541
+ could expose a host path, parity needs more than 2000 masks, a submodule is
1542
+ initialized, a writable bind covers or sits inside the workspace, or
1543
+ `--pass-through` is requested. Linked Git worktrees are supported. See the
1544
+ [security model](docs/security-model.md#zero-copy-safe-isolation-linux-isolationsafebackend-bwrap)
1545
+ and [configuration guide](docs/configuration.md#isolationsafebackend-and-isolationbwrapbinds-linux).
1546
+ - Added `--notify room:<name>|channel:<name>` for one metadata-only completion
1547
+ line through the optional `post` CLI. A missing, refused, or timed-out send
1548
+ degrades to a manifest record without changing the run result. Notifications
1549
+ also fire for child launch failures and persistent-worktree setup failures,
1550
+ and the option works with `resume`; `call` and `--pass-through` reject it.
1551
+ - Cursor dry-run and terminal JSON now include a stable `accountFingerprint`
1552
+ derived from `cursor-agent status --format json`. Raw account fields and
1553
+ tokens are never emitted or persisted; unauthenticated or malformed status
1554
+ output omits the fingerprint so consumers can fail closed.
1555
+
1556
+ ### Changed
1557
+
1558
+ - The dev extra now ships `pytest` and `pytest-xdist`; `scripts/test-parity.sh`
1559
+ checks that the parallel accelerator and the unittest gate agree on executed
1560
+ and skipped counts.
1561
+ - Bundled Grok declarations move to Grok 4.6: `grok-4.6` is the Grok CLI
1562
+ default, and Cursor entries use the canonical `cursor-grok-*` IDs with the
1563
+ full `cursor-grok-4.6` effort ladder (cursor-agent no longer accepts the
1564
+ legacy `grok-4.5-fast-*` style).
1565
+ - Devin runs use the current noninteractive workspace-trust flow.
1566
+ - Release hygiene: CI also runs the suite on macOS (Python 3.12), the
1567
+ repository has one canonical pull-request template, and the sdist ships
1568
+ `scripts/test-parity.sh`.
1569
+
1570
+ ### Fixed
1571
+
1572
+ - `workflow run --resume` turns a completed workflow dry-run into live
1573
+ execution under the same workflow ID. Simulated agent and budget events stay
1574
+ in the journal for audit but never satisfy replay or consume live budget.
1575
+ (Listed under 0.29.1 in earlier drafts; it landed after that tag.)
1576
+ - Workflow child runs keep their identity (workflow ID and child name)
1577
+ through registration, journal events, and snapshots, including children
1578
+ launched in isolated worktrees.
1579
+ - Safe mode never places its scratch copy inside the source workspace. When
1580
+ the system temp directory is the source (for example `delegate ... safe` run
1581
+ from `/tmp`), the copy goes to `$XDG_CACHE_HOME/delegate/safe-workspaces`
1582
+ or `~/.cache/delegate/safe-workspaces`; a source that contains every
1583
+ candidate is refused with `safe_workspace_source_too_broad`. Previously the
1584
+ copy recursed into its own output until `ENAMETOOLONG`.
1585
+ - Safe-mode copies skip directories the caller cannot read (other users'
1586
+ `/tmp/systemd-private-*`, for example) with a bounded warning, and any
1587
+ residual copy failure is reported as `safe_workspace_copy_failed` instead of
1588
+ a traceback.
1589
+
1590
+ ## [0.29.1] - 2026-08-11
1591
+
1592
+ ### Changed
1593
+
1594
+ - The PyPI artifact handoff now uses the official Node 24 upload and download
1595
+ actions, removing the deprecation warnings emitted during the 0.29.0 publish.
1596
+
1597
+ ## [0.29.0] - 2026-08-11
1598
+
1599
+ ### Added
1600
+
1601
+ - `delegate runs` and `delegate ps` now report listing honesty: the JSON
1602
+ payload gains `total` (pre-limit match count) and `truncated`, text mode
1603
+ prints `showing N of M runs (raise --limit to see more)`, and a zero-row
1604
+ result under `--group`/`--harness` explains itself — naming the status
1605
+ filter to drop when `--running`/`--stale`/`--active` emptied the result, or
1606
+ noting the run Registry is workspace-scoped otherwise.
1607
+ - Retained event text now carries truncation metadata on both surfaces: raw
1608
+ `events.jsonl` `stream.line` records and normalized Snapshot `recentEvents`
1609
+ add `truncated: true` plus `textChars` (original length) only when the
1610
+ 500-character bound actually clipped, and the final unterminated child
1611
+ stdout line is now written to `events.jsonl` instead of silently dropped.
1612
+ All child-controlled normalized-event strings (including tool targets,
1613
+ `error`, and `run.completed`) are bounded through the same helper.
1614
+ - The tracked launcher shim template (`bin/delegate-profile-shim`) passes
1615
+ through the read-only workflow actions
1616
+ (`check|status|watch|events|result|wait|list`) without a selected profile,
1617
+ mirroring the Python CLI's guard; a parity test fails on drift.
1618
+ - Tracked Cursor completion JSON now includes the CLI-reported token `usage`
1619
+ object when present.
1620
+
1621
+ ### Changed
1622
+
1623
+ - Devin model discovery now uses the prompt-free, fingerprinted
1624
+ `devin models list --format json` catalog for setup, capability refresh, and
1625
+ one-off live queries. Older or unauthenticated CLIs degrade to a version-only
1626
+ record instead of receiving a prompt-like invalid-model probe.
1627
+ - Child-launch failures with `EPERM` now hint that sandboxed parent shells can
1628
+ forbid launching harness binaries; `prompt_too_large` names the engines
1629
+ whose prompt rides a file/stdin transport, derived from the transport table.
1630
+ - The test suite hardens hermeticity against ambient delegate-lane
1631
+ environment (`DELEGATE_RUN_ID`, mail identity, root-provenance and profile
1632
+ variables), and the documented discovery command is
1633
+ `python3 -m unittest discover -s tests -t .` everywhere, including CI and
1634
+ the contributor wiki.
1635
+ - CI and publishing now use the official Node 24 GitHub Action releases, and
1636
+ the public publishing checklist builds exported source in isolated temporary
1637
+ environments instead of modifying the maintainer's ambient Python install.
1638
+
1639
+ ### Fixed
1640
+
1641
+ - An explicit `DELEGATE_CONFIG` now survives profile selection: the profile
1642
+ shim and profile env resolution load the selected profile's credentials but
1643
+ keep the incoming `DELEGATE_CONFIG` as the runtime-policy config instead of
1644
+ replacing it, and codex quota fallback no longer forwards `DELEGATE_CONFIG`
1645
+ into the fallback child environment.
1646
+ - Tracked runs now stop after an explicit harness terminal event and fail closed
1647
+ when either raw output stream exceeds 16 MiB, preventing a completed or
1648
+ runaway child from filling disk with cumulative stream payloads.
1649
+ - Tracked stream decoding preserves UTF-8 characters split across read chunks;
1650
+ normalized events retain a bounded head/tail with an exact total, and raw
1651
+ `events.jsonl` mirrors at most 500 stdout lines plus a truncation marker so
1652
+ many short lines cannot amplify a bounded child stream into an unbounded
1653
+ event journal or in-memory event list.
1654
+ - Tracked Cursor retries now report cumulative token usage, transient Devin
1655
+ catalog failures retain the last-known-good catalog, and Devin help no longer
1656
+ advertises unsupported reasoning effort.
1657
+ - Slow raw-log archival no longer holds the Registry mutation lock, concurrent
1658
+ ambient retention passes skip instead of waiting, and transient Registry-lock
1659
+ contention can no longer crash a tracked run's stdout drain thread.
1660
+
1661
+ ## [0.28.0] - 2026-08-05
1662
+
1663
+ ### Added
1664
+
1665
+ - Added `delegate runs --structural` and `delegate ps --structural` for
1666
+ content-free local status collection, including lifecycle, model, group,
1667
+ status, timestamp, and root initiator provenance.
1668
+ - Tracked runs now retain a validated root initiator across nested Delegate
1669
+ launches and persistent-worktree execution.
1670
+
1671
+ ### Changed
1672
+
1673
+ - Codex quota fallback is now explicitly configured with
1674
+ `codex.fallbackProfile`, supports arbitrary profile definitions, and keeps
1675
+ temporary blocks by resolved credential identity rather than profile alias.
1676
+ Default work/personal credential homes continue to interoperate with legacy
1677
+ profile launchers without allowing remapped aliases to share state.
1678
+ - Codex-only failover no longer depends on private Claude shim names or hidden
1679
+ runtime controls. Retry and persistent-worktree paths retain the account
1680
+ that is actually serving the run.
1681
+
1682
+ ### Fixed
1683
+
1684
+ - Structural run listings now exclude raw terminal/provider events and apply
1685
+ normal secret redaction to retained fields.
1686
+ - Fallback failures persist the correct account block and provider-reported
1687
+ reset time; a blocked fallback is skipped, and retries no longer return to a
1688
+ blocked primary after a preflight swap.
1689
+ - Failover tests isolate their state from the user's home directory, and
1690
+ `delegate ps --help` now advertises its supported structural view.
1691
+
1692
+ ## [0.27.0] - 2026-08-01
1693
+
1694
+ ### Changed
1695
+
1696
+ - Split the mail module into `mail_core` (mailbox) and `mail_push` (hook
1697
+ protocol) behind a stable `mail` facade; extracted the runner's mail
1698
+ sentinel capture and push finalization; unified the three launch seams'
1699
+ mail preparation in one helper with ownership transfer kept at the seams;
1700
+ `parse_prompt_tail` returns a named, tuple-compatible `PromptTail`.
1701
+ - Mail-disabled launches no longer touch the filesystem for mail (lanes keep
1702
+ their identity and storage materializes lazily on first send); workspace
1703
+ resolution runs once per launch; the discovery cache is memoized per
1704
+ process; the directory retry baseline is captured only when a codex
1705
+ fallback profile is configured; watch sleeps are bounded by the remaining
1706
+ deadline; non-once watches dedupe emitted messages and skip unchanged
1707
+ inboxes; mail bodies stream with a bounded read.
1708
+ - All mail subcommands render prose in human mode (watch keeps its
1709
+ documented NDJSON contract); JSON output is byte-unchanged.
1710
+
1711
+ ### Removed
1712
+
1713
+ - Dead code from the framer migration and mail rounds: unused safe-prefix
1714
+ helpers, the write-only `prompt_framed` field, and unreferenced mail
1715
+ helpers; development-history comments replaced with durable behavior
1716
+ statements.
1717
+
1718
+ ## [0.26.0] - 2026-08-01
1719
+
1720
+ ### Added
1721
+
1722
+ - Added workspace-local Wave 1 pull mail: storage outside run records,
1723
+ lock-serialized per-recipient delivery ledgers, inbox/read/status/watch, and
1724
+ mail-only prune with versioned JSON contracts.
1725
+ - Added strict `mail.enabled` configuration, work-run identity binding, the
1726
+ opt-in `mailPush` plumbing seam, and audited harness-specific scoped or
1727
+ workspace-writable mail behavior.
1728
+ - Added opt-in Wave 2 stop-hook push for audited Claude and Codex launches with
1729
+ bounded Tier-2-framed batches, per-run cursors, launch-scoped settings, and
1730
+ one-time pull-degradation events. Unverified harnesses remain pull-only.
1731
+
1732
+ ### Fixed
1733
+
1734
+ - Mail launch wiring now applies to the actual child argv and matching manifest
1735
+ argv after persistent or attached worktree rewriting. Isolated grants are
1736
+ limited to evidenced harness mechanisms; Cursor no longer receives a new
1737
+ sandbox, non-isolated work launches receive no redundant grant, and Codex
1738
+ follows its effective sandbox policy. Read-only mail commands no longer
1739
+ create a registry, mailbox, lock, or Git exclude entry; status reconciles a
1740
+ published inbox envelope after a crash before its sender-ledger rewrite.
1741
+ - Mail sandbox reporting now derives Codex and Grok classification from the
1742
+ emitted argv: unsandboxed policies are labelled honestly, constrained and
1743
+ unknown isolated policies warn, and only Codex `workspace-write` receives
1744
+ the scoped writable-root grant. Delivery reconciliation now validates the
1745
+ no-follow recipient envelope against the ledger before treating a crash or
1746
+ collision as delivered.
1747
+
1748
+ ## [0.25.0] - 2026-08-01
1749
+
1750
+ ### Added
1751
+
1752
+ - Named personas: `--persona` / `--no-persona` / `--allow-repo-persona` on
1753
+ every engine's safe/work launch (and dry-run), input-json `persona` /
1754
+ `allowRepoPersona` keys, and workflow `agent(persona=...)` with the resolved
1755
+ persona digest pinned into the structural cache key so an edited persona is
1756
+ a cache miss by design.
1757
+ - `delegate personas [--json]` listing (schema `delegate.personas.v1`) with
1758
+ workspace-shadowing metadata and per-file invalid rows; read-only allowlisted
1759
+ in both the profile guard and the shell shim.
1760
+ - Persona transports: claude work uses `--append-system-prompt-file` with a
1761
+ private 0600 file when discovery positively proves current support (probe
1762
+ recognizes both the long and the collapsed `--append-system-prompt[-file]`
1763
+ help spellings); opencode merges a synthetic `delegate-persona` agent into
1764
+ the effective config without clobbering profile keys; every other engine
1765
+ prepends. Safe mode always prepends, with the persona placed before the
1766
+ safe policy so the safety text keeps recency.
1767
+ - `persona.txt` as a private durable run artifact with manifest, snapshot,
1768
+ and runs-summary projection; resume replays recorded persona bytes through
1769
+ the target engine's transport, `--persona` re-resolves, `--no-persona`
1770
+ drops.
1771
+
1772
+ ### Changed
1773
+
1774
+ - The central framer is now the sole prompt composer: cursor/droid/kimi argv
1775
+ builders no longer self-prefix safe policy text, user and persona bytes are
1776
+ joined verbatim, and persistent/attached worktree notes are tracked
1777
+ structurally on the request rather than inferred from prompt content.
1778
+ - Slash-passthrough prompts on persistent or attached worktree runs carry the
1779
+ Delegate-owned worktree and forbid-commit notes ahead of the slash command,
1780
+ matching v0.24.0 behavior; all other slash payloads remain byte-verbatim.
1781
+
1782
+ ### Security
1783
+
1784
+ - Persona resolution walks `.delegate/personas` component-by-component over
1785
+ `O_NOFOLLOW` descriptors anchored at the source workspace or home, refusing
1786
+ symlinked parents and leaves; strict UTF-8, C0 refusal, and a 64 KiB cap.
1787
+ - Resume persona replay reads only the fixed `persona.txt` artifact with a
1788
+ required, verified sha256 digest; manifest data cannot redirect the read.
1789
+ - The claude native persona gate fails closed: probe errors, timeouts, and
1790
+ unrecognized banners fall back to prepend so an older binary never receives
1791
+ an unknown flag. Dry-run never probes.
1792
+ - Workflow persona digests travel across the child seam and both sides fail
1793
+ closed on mismatch without caching.
1794
+
1795
+ ## [0.24.0] - 2026-07-31
1796
+
1797
+ ### Added
1798
+
1799
+ - Added `delegate resume` for relaunching terminal Runs with a bounded,
1800
+ untrusted continuation built from the original prompt and prior result.
1801
+ Resume preserves compatible launch settings, supports explicit cross-engine
1802
+ resumes, and attaches to an existing persistent worktree with a live cleanup
1803
+ lease rather than creating a second worktree.
1804
+ - Added private `prompt.txt` capture for new tracked Runs so their original
1805
+ prompts can be resumed without placing prompt text in the Manifest or
1806
+ Snapshot. Legacy records without that capture fail closed with a clear
1807
+ `resume_prompt_unavailable` error.
1808
+
1809
+ ## [0.23.0] - 2026-07-30
1810
+
1811
+ ### Added
1812
+
1813
+ - Added `delegate runs prune` with a 30-day default age threshold, an explicit `--older-than` override, and `--dry-run` preview output. It prunes terminal Run records and their associated Registry artifacts (per-Run directory, logs, Completion Report, retained raw-log archive) without touching genuinely running Runs. Persistent-worktree Runs are skipped unless their worktree is recorded as removed or missing — unknown or unrecorded worktree status is treated as possibly present, mirroring `worktree gc` — so live worktrees never lose their Registry records. The ambient retention pass is bypassed on the prune command path so a dry run never mutates state.
1814
+
1815
+ ### Fixed
1816
+
1817
+ - Focused unittest invocations (`python3 -m unittest tests.<module>`) no longer fail on the src layout import: `tests/__init__.py` now puts `src` on `sys.path` before any test module import runs.
1818
+
1819
+ ## [0.22.0] - 2026-07-26
1820
+
1821
+ ### Changed
1822
+
1823
+ - Consolidated pure-call validation in `constants.validate_pure_call`, collapsed repeated `attempt`/`call` invocations in `runner.py` into local closures, eliminated `typing.Any` from `src`, and removed defensive `getattr`/`isinstance` hedges where the contract guarantees the type.
1824
+
1825
+ ### Removed
1826
+
1827
+ - Removed the write-only `ReasoningCapability.supported_efforts` field and unused `STATUS_FILTER_ACTIVE`/`STATUS_FILTER_RECENT` constants.
1828
+ - Removed dead back-compat re-exports from `delegate_agent.cli`: `build_kimi_argv`, `build_opencode_argv`, `build_pi_argv`, `prefix_droid_safe_prompt`, `redacted_prompt_argv`, `KIMI_PROMPT_REDACTION`, `_grok_harness_bypass_enabled`, `_resolve_default_model`, and `block_external_symlinks`. These had no known consumers; the supported import surface is the CLI and `delegate --json` contracts.
1829
+
1830
+ ## [0.21.0] - 2026-07-26
1831
+
1832
+ ### Added
1833
+
1834
+ - Added `delegate worktree gc --all`, which scans the machine-wide worktree
1835
+ pool for worktrees whose source repository no longer exists. Such worktrees
1836
+ were previously unreachable by any `gc` invocation, because reaping is driven
1837
+ by the run registry inside each source repository and that registry dies with
1838
+ the repository. The scan adds no catalog or persistent state: it reads each
1839
+ worktree's Git backlink directly, and treats a backlink whose target is gone
1840
+ as the sole orphan signal. The scan removes nothing at all, at any depth: a
1841
+ missing source repository makes a worktree's uncommitted state impossible to
1842
+ inspect, so orphans and empty pool directories alike are reported for
1843
+ deliberate manual cleanup. Because that output invites manual deletion, every
1844
+ uncertainty resolves away from an orphan verdict: a pointer file that cannot
1845
+ be read, a path comparison the filesystem cannot answer, an entry too recently
1846
+ modified to have settled, and a directory whose name does not match the pool's
1847
+ own fingerprint contract are all reported as warnings rather than orphans.
1848
+ That last rule is what keeps a scan of an arbitrary root from labelling
1849
+ somebody else's directories. `--pool PATH` scans a different pool root, which
1850
+ reaches pools stranded by an earlier `worktrees.dataHome`.
1851
+ - `capabilities refresh` and `setup` now name each harness on stderr as it is
1852
+ probed, so a harness that hangs is identifiable rather than anonymous
1853
+ silence. Progress output is suppressed under `--json`.
1854
+
1855
+ ### Changed
1856
+
1857
+ - A launch now fails instead of proceeding when the configured binary for a
1858
+ harness identifies itself as a *different* known harness. Delegate re-probes
1859
+ `--version` when a cached capability record has refused a run, and during
1860
+ `capabilities refresh` and `setup` (see Fixed); when that banner positively
1861
+ names another harness — a Codex path replaced in place by Grok, say — the run
1862
+ stops with `harness_identity_mismatch` and exit code 2, naming the configured
1863
+ harness, the harness that answered, and the selector path.
1864
+ Previously the launch continued against that same binary with the same Codex
1865
+ argv, sandbox flags, and approval policy, and only the cached capability
1866
+ metadata was discarded. This fires solely on a banner that NAMES another known
1867
+ harness, never on uncertainty: a probe that errors, times out, exceeds its
1868
+ output bound, or prints an unbranded banner still fails open and launches on
1869
+ the cached record. An unbranded shape — a bare date-and-hash build ID is the
1870
+ clearest case — is deliberately not identification, because wrapper prefixes
1871
+ are a supported configuration and refusing a legitimate launch costs more than
1872
+ carrying a stale record until the next refresh. The selector is scrubbed of
1873
+ credentials before it reaches the message or the diagnostics, since a wrapper
1874
+ prefix can carry a token inline or after a flag. Dry runs do not probe and are
1875
+ unaffected. The refusal also names the discovery cache file for the active
1876
+ auth profile, in its `cachePath` diagnostic and in a next action, because
1877
+ `capabilities refresh` cannot clear this state: a refresh keeps the
1878
+ last-known-good record whenever a probe fails, which is correct for a flaky
1879
+ probe and wrong here, where the record itself is the problem. Without the
1880
+ path, a wrong identification would refuse every launch with no documented way
1881
+ out short of editing configuration.
1882
+ - A run whose cached capability record is discarded for version drift now says
1883
+ so, naming `delegate capabilities refresh <engine>`. The record is dropped for
1884
+ that run only and the superseded copy stays on disk, so every later launch
1885
+ repeats the drop and loses the same discovery-sourced models and reasoning
1886
+ levels — previously with no indication that a stale cache was the cause.
1887
+ Selector drift stays silent, since `capabilities` already reports it under
1888
+ `driftedHarnesses`.
1889
+
1890
+ ### Fixed
1891
+
1892
+ - Discovery now detects a harness that was upgraded in place. Cached capability
1893
+ records were invalidated only by comparing the configured selector, so an
1894
+ upgrade behind an unchanged selector left stale capabilities cached
1895
+ indefinitely and a newly supported reasoning level was rejected until a manual
1896
+ `capabilities refresh`. Delegate now re-probes `--version` for the single
1897
+ harness it is about to use and compares it against the version already stored
1898
+ in the record, then rebuilds the run against the refreshed picture. The probe
1899
+ runs only once the cached record has already cost the run something, never on
1900
+ the ordinary path, which therefore spawns no extra process at all — and that
1901
+ matters because the probe costs 26-668ms, worst on the Node and Bun harnesses
1902
+ that are already slow to start. Two things trigger it: an explicit
1903
+ `--reasoning-effort` the record refuses, and a `defaultReasoningEffort` the
1904
+ record silently drops. The second is the one most likely to go unnoticed,
1905
+ since a configured default degrades to a warning rather than failing the
1906
+ launch, and it is set once and then never typed again. A probe that cannot
1907
+ repair the default leaves the run exactly as it was: a launch that succeeded
1908
+ is never turned into a failure. The check fails open — a probe that errors,
1909
+ times out, or prints a banner nothing recognizes keeps the cached record, so a
1910
+ failing probe can never prevent a launch. A banner that positively identifies
1911
+ a *different* known harness is the exception, and it aborts the launch rather
1912
+ than merely invalidating the record — see Changed. Each banner is matched
1913
+ against the expected harness's own pattern before anyone else's, so a banner
1914
+ mentioning more than one tool is read as the harness that was asked for
1915
+ instead of whichever pattern happens to be declared earlier. Banners are read
1916
+ with escape sequences stripped, so a colorized version line no longer freezes
1917
+ a record permanently. A cached selector whose binary no longer exists is also
1918
+ treated as drift.
1919
+ - Not covered, deliberately: a harness that *removes* a capability leaves its
1920
+ cached record listing more than the harness now supports, which produces no
1921
+ refusal and so no probe. The child rejects the effort it was handed, which is
1922
+ loud; the one quiet case is Cursor's route table aiming a run at a superseded
1923
+ model id. Catching either would cost a probe on every launch, which is the
1924
+ trade this path exists to refuse. `capabilities refresh` remains the cure.
1925
+ - A dry run never probes the harness for its version. Dry run documents that it
1926
+ neither launches a child runtime nor requires the real child binary, and the
1927
+ drift probe is a child runtime; it now runs only on a real launch, leaving dry
1928
+ run with the two filesystem-local checks.
1929
+ - A discovery cache carrying a newer schema than the running build is no longer
1930
+ discarded and overwritten. It is left intact while the run degrades to
1931
+ probing without persisting, so an older Delegate can no longer destroy a newer
1932
+ cache. Losing that race mid-probe degrades the same way rather than failing the
1933
+ command: `capabilities refresh` and `setup` both report `cacheWriteSkipped`,
1934
+ `setup` additionally leaving `cacheState` at `unchanged`, and each exits
1935
+ successfully, since only persistence was lost. The
1936
+ schema is re-read immediately before the atomic replacement rather than before
1937
+ the snapshot is serialized, which narrows the window in which a newer cache
1938
+ could be published and then overwritten down to the `os.replace` call itself.
1939
+ POSIX offers no compare-and-swap for a rename, so that last window remains.
1940
+ - The test suite no longer writes into the developer's real
1941
+ `~/.delegate/worktrees`. Tests exercising persistent-worktree runs created
1942
+ real pooled worktrees over temporary source repositories and orphaned them
1943
+ permanently, because `worktrees_data_home` falls through to the user's home
1944
+ directory with no seam a test could redirect. `HOME` is now redirected at test
1945
+ collection time, which reaches every such resolver at once.
1946
+
1947
+ ## [0.20.0] - 2026-07-25
1948
+
1949
+ ### Added
1950
+
1951
+ - Added typed child-failure reporting for usage/quota limits (including reset
1952
+ details when present), expired or rejected auth tokens, and Codex thread/state
1953
+ lookup loss. Run state, snapshots, listings, completion envelopes, and
1954
+ synthesized reports now carry the specific error and message. The existing
1955
+ generic public error remains `child_failed`; `usage_limit`, `auth_failed`, and
1956
+ `codex_thread_lost` are additive typed codes. Classification reads only stderr
1957
+ and normalized harness error/terminal events, never assistant/model output.
1958
+ - Added `delegate ps` as the first-class active-run view, equivalent to
1959
+ `delegate runs --active`.
1960
+ - Added `delegate setup` for first-run harness discovery. It fingerprints all
1961
+ supported installed harnesses, records available model/reasoning metadata in
1962
+ a profile-scoped user cache, creates a minimal selector-only config when no
1963
+ config exists, and reports discovery readiness separately from launchability.
1964
+ - Cached `models`/`capabilities` views now project profile discovery with source
1965
+ and evidence metadata. `models <engine> --live` provides a non-persistent
1966
+ one-off probe; `capabilities refresh` persists a full refresh for the selected
1967
+ profile, and `capabilities refresh <engine> [...]` re-probes only the named
1968
+ harnesses while the rest keep their last-known-good records.
1969
+ - Runtime model and reasoning metadata now distinguish the requested model,
1970
+ argv-resolved model, capability-validation model, requested effort, resolved
1971
+ effort, source, evidence strength, and transport.
1972
+
1973
+ ### Changed
1974
+
1975
+ - Codex output schemas are now linted before launch. Delegate recursively
1976
+ supplies missing `additionalProperties: false` on object schemas with a loud
1977
+ warning, rejects partial `required` lists precisely, and passes a normalized
1978
+ temporary copy without modifying the source schema. Object-bearing `allOf`,
1979
+ `patternProperties`, and external or unresolvable `$ref` values fail closed
1980
+ rather than being rewritten unsafely. Workflow Codex stages and direct
1981
+ `--output-schema`/`outputSchema` launches share the same preflight. The
1982
+ normalized copy preserves the source schema's property order, so
1983
+ think-before-answer schemas keep their intended generation order.
1984
+ - On retry-safe paths, Codex thread/state lookup failures now retry once and,
1985
+ only if the same typed failure repeats, retry through an ephemeral
1986
+ `--ignore-user-config` launch. Retry-safe paths are read-only calls and
1987
+ pre-tool attempts whose workspace remains unchanged; work mode also requires
1988
+ a clean captured baseline. Envelopes and events record fallback engagement.
1989
+ - `--prompt-file /dev/stdin` and equivalent stdin descriptors now consume the
1990
+ piped prompt once instead of conflicting with stdin as a second source.
1991
+ - Model and reasoning resolution now prefers explicit CLI/config choices and
1992
+ exact discovered evidence before legacy workspace or bundled fallbacks.
1993
+ Exact negative menus fail closed; partial harness evidence and Cursor inferred
1994
+ routes remain visibly labeled rather than being promoted to model-exact facts.
1995
+ - Discovery refresh is last-known-good per harness. Successful records update
1996
+ independently, failed probes retain the prior record and report staleness,
1997
+ and selector drift invalidates only the affected harness without probing on
1998
+ an ordinary launch.
1999
+ - `capabilities refresh` now writes the selected profile's private discovery
2000
+ cache. The old workspace reasoning cache remains a lower-precedence read-only
2001
+ compatibility source. The cached `capabilities` read reports the discovery
2002
+ cache location in `cachePath`; the previous workspace path, when present, is
2003
+ reported under `legacyWorkspaceCachePath`.
2004
+ - `reasoning.capabilities` config entries are now accepted for `grok` in
2005
+ addition to `codex` and `droid`.
2006
+ - `--auth-profile` is now accepted on cached `capabilities` reads (previously
2007
+ rejected as an invalid option combination) and on `models` and `setup`.
2008
+ - Cursor reasoning-effort routing now defers to a pinned selector when discovery
2009
+ has no same-family route for it: the run proceeds on the pinned model and
2010
+ records a bypass warning. When discovery does carry exact same-family routes,
2011
+ the requested effort still routes to the matching selector, and a family that
2012
+ omits the requested effort still fails closed.
2013
+ - Grok reasoning-effort support is once again governed by the documented CLI
2014
+ enum (low, medium, high, xhigh, max); a bundled `grok-4.5` declaration that
2015
+ narrowed it to low/medium/high was removed, since `grok --help` enumerates no
2016
+ per-model efforts. Config, discovery-exact, and cached grok declarations
2017
+ still take precedence.
2018
+ - Embedded Devin and Kimi `defaultModel` values are now `null`, deferring model
2019
+ selection to each harness. The editable `config init` example may still pin
2020
+ an explicit default.
2021
+ - Claude and Grok `defaultReasoningEffort` config values are now only
2022
+ format-checked at load time instead of validated against the static enum; an
2023
+ unsupported configured default degrades to a launch-time warning so that
2024
+ discovery, not a hardcoded table, decides which levels are accepted.
2025
+
2026
+ ### Security
2027
+
2028
+ - Discovery probes use fingerprinted allowlisted selectors, fixed argv with no
2029
+ shell, closed stdin, neutral temporary working directories, bounded output,
2030
+ timeouts, normalized cache schemas, atomic owner-only writes, and scrubbed
2031
+ model/warning projections. Config and cache source paths remain intentionally
2032
+ visible diagnostics. Automatic Devin discovery remains prompt-free; only the
2033
+ explicitly requested `models devin --live` path uses its bounded prompt-like
2034
+ invalid-model probe.
2035
+ - Setup never overwrites an existing config and refuses unsafe selectors,
2036
+ final-component symlinks, and concurrent config races rather than mixing
2037
+ discovery results across config states.
2038
+
2039
+ ### Fixed
2040
+
2041
+ - Credentials appearing in a child harness quota or reset message are now
2042
+ redacted before they reach `state.json`, `snapshot.json`, the completion
2043
+ report, or the run envelope; Codex reports quota walls as stdout events,
2044
+ which bypassed the stderr-tail redaction. The in-progress activity label is
2045
+ likewise redacted when persisted, matching the progress heartbeat.
2046
+ - A Codex output schema that omits `required` entirely is now repaired to list
2047
+ every property (in declaration order) instead of being rejected, matching how
2048
+ a missing `additionalProperties` is handled. A partial `required` is still an
2049
+ error.
2050
+ - The `primary` attempt banner is written once in the run's stderr log even
2051
+ when several retry paths run in sequence.
2052
+ - `delegate ps` now reports argument errors in its own terms — unknown options,
2053
+ `--limit`, `--harness`, and `--group` failures name `ps` instead of the
2054
+ `runs` command it delegates to, and `ps --recent` gets the same tailored
2055
+ redirect as `--running` and `--stale`.
2056
+ - `delegate capabilities refresh` exits 3 (missing binary) when no supported
2057
+ harness is installed — including when an engine subset such as
2058
+ `capabilities refresh codex` names only uninstalled harnesses — matching
2059
+ `delegate setup` on identical machine state instead of returning the generic
2060
+ usage code 2.
2061
+ - `delegate capabilities` no longer advertises harnesses whose configured
2062
+ selector has drifted from the cached record, on both the cached read and
2063
+ after a refresh — a subset refresh returns the full snapshot, so engines it
2064
+ never probed could otherwise surface stale catalogs the launch path would
2065
+ refuse. Excluded harnesses are named in a new `driftedHarnesses` payload
2066
+ field and in the text output.
2067
+ - Pi catalog rows whose column count does not match the header are skipped
2068
+ instead of being read by shifted column position, which could cache a
2069
+ thinking-capable model as having no reasoning support (unrecoverable, since
2070
+ Pi has no config override) or hand a non-thinking model the full effort enum.
2071
+ - A configured harness binary or argv prefix that no longer resolves while the
2072
+ CLI is still on PATH is now reported as a stale config setting rather than an
2073
+ uninstalled harness, and `delegate setup` names the config key and file to
2074
+ fix instead of telling you to install a CLI you already have.
2075
+ - An unreadable `~/.factory/settings.json` (permissions or I/O error) is
2076
+ reported as a read failure instead of being misreported as invalid JSON.
2077
+ - Two Cursor selectors that normalize to the same route family and effort now
2078
+ drop just the ambiguous routes with a warning, instead of turning the entire
2079
+ Cursor discovery record into an error record.
2080
+ - OpenCode catalog parsing resumes past a malformed entry's whole object, so a
2081
+ `provider/model`-shaped line nested inside the rejected body can no longer be
2082
+ re-read as a real selector.
2083
+ - `capabilities refresh` now hints "global options before the subcommand" for a
2084
+ misplaced global option instead of mislabeling it `invalid_engine`, and a
2085
+ subset refresh whose requested harnesses are all uninstalled reports
2086
+ `requested_harnesses_not_installed` instead of the misleading
2087
+ `no_harnesses_installed`.
2088
+
2089
+ ## [0.19.0] - 2026-07-20
2090
+
2091
+ ### Added
2092
+
2093
+ - Codex `--reasoning-effort max` support for `gpt-5.6-sol`; other Codex models
2094
+ still fail closed unless config or workspace capability-cache overrides opt them in.
2095
+
2096
+ ## [0.18.0] - 2026-07-19
2097
+
2098
+ ### Added
2099
+
2100
+ - `worktree gc --dry-run` now reports `wouldPruneSourceRoots` and classifies
2101
+ un-prunable worktrees with structured orphan reasons (`source_root_missing`,
2102
+ `worktree_metadata_missing`, `branch_missing`, `detached_backlink`), each
2103
+ with a `safeAction`. GC remains non-destructive and never deletes worktree
2104
+ directories.
2105
+ - New `worktrees.poolWarnCount` config knob (default 20): persistent
2106
+ work-mode launches emit a stderr warning when the shared worktree pool
2107
+ holds more worktrees than the threshold. Warn-only; nothing is blocked or
2108
+ deleted.
2109
+
2110
+ ### Changed
2111
+
2112
+ - Text rendering for `worktree gc --dry-run` prints
2113
+ `would prune source roots` instead of a constant zero, and orphan lines now
2114
+ include the worktree path alongside the reason.
2115
+
2116
+ ## [0.17.0] - 2026-07-18
2117
+
2118
+ ### Added
2119
+
2120
+ - Pi is now a first-class `safe`/`work`/`call` engine with stateless JSON
2121
+ execution, stdin prompt transport, model aliases, reasoning-effort mapping,
2122
+ live model discovery, normalized JSON events, and a native read-only policy
2123
+ for safe mode and `call --read-only`.
2124
+ - Oh My Pi is now a first-class `omp` engine with matching mode, model alias,
2125
+ reasoning, discovery, and event support. Its verified 17.0.4 prompt path uses
2126
+ a redacted positional argument because piped stdin exits without processing.
2127
+ - Child processes now receive an authoritative `WORKSPACE_ROOT`; run metadata
2128
+ exposes the same path as `workspaceRoot`, with source and isolated execution
2129
+ roots available through `DELEGATE_SOURCE_ROOT` and
2130
+ `DELEGATE_EXECUTION_ROOT` where applicable.
2131
+
2132
+ ### Changed
2133
+
2134
+ - Repository-local `.delegate/config.json` is no longer loaded automatically.
2135
+ Delegate reports it as an unapplied layer; operators must explicitly select
2136
+ a trusted file with `DELEGATE_CONFIG`.
2137
+ - Stateless calls now preserve child-created files under
2138
+ `.delegate/artifacts/<runId>/` instead of deleting successful deliverables,
2139
+ and report `artifactsPath` plus `preservedArtifacts` in the response.
2140
+ - Unknown launch flags now fail as `unknown_option` before they can be absorbed
2141
+ as prompt text, and corrected-command suggestions are emitted only after the
2142
+ real parser validates them.
2143
+
2144
+ ### Security
2145
+
2146
+ - Oh My Pi safe mode and `omp call --read-only` now add
2147
+ `--approval-mode always-ask`, which denies write and exec tools in headless
2148
+ mode even when project config requests `yolo`. A gated real-binary behavioral
2149
+ test verifies writes and shell commands are denied while reads remain
2150
+ available, and positional prompt guards reject flag- and include-shaped
2151
+ injection prefixes.
2152
+ - Private `.delegate` run, workflow, and cache state I/O now traverses from the
2153
+ workspace anchor with descriptor-relative, no-follow opens, rejecting
2154
+ symlinked path components to prevent symlink-swap races.
2155
+
2156
+ ## [0.16.0] - 2026-07-16
2157
+
2158
+ ### Added
2159
+
2160
+ - `--timeout` is now accepted and enforced on tracked `safe` and `work` runs
2161
+ across engines. It remains rejected with `--pass-through`, and deadline
2162
+ failures keep the historical `call_timeout` error code.
2163
+ - Kimi tool-call activity is normalized into `tool.started`/`tool.completed`
2164
+ events with id correlation; `status` stays unset because Kimi tool results
2165
+ carry no result-status signal.
2166
+
2167
+ ### Changed
2168
+
2169
+ - Persistent-worktree runs that fail after the worktree is realized
2170
+ (child-launch errors, timeouts) now keep `worktreeStatus: present`,
2171
+ `executionCwd`, `branch`, and `worktreeCleanupCommands` in the failed-run
2172
+ record, so the preserved worktree stays inspectable and removable via
2173
+ `delegate worktree show|remove` instead of being orphaned.
2174
+ - The Kimi default model is now `kimi-code/k3`, and the bundled Kimi catalog
2175
+ lists exactly the three real model IDs (`kimi-code/k3`,
2176
+ `kimi-code/kimi-for-coding`, `kimi-code/kimi-for-coding-highspeed`); the
2177
+ stale `kimi-k2.7` entry was removed.
2178
+ - Docs clarifications: Kimi reasoning-effort wording now states that the Kimi
2179
+ CLI exposes no effort flag (k3 supports effort internally via
2180
+ `~/.kimi-code/config.toml`) and that Delegate rejects `--reasoning-effort`
2181
+ for Kimi; the CLI reference notes that `usage: unavailable` in Kimi run JSON
2182
+ is expected because the Kimi CLI emits no usage/token lines in stream-json
2183
+ output.
2184
+ - Kimi work-mode docs restate current behavior: Delegate emits no `--yolo` —
2185
+ Kimi prompt mode auto-approves tool actions, and work mode edits the real
2186
+ workspace by default. Temporary safe isolation or explicit worktree
2187
+ isolation provides a workspace boundary, not a complete host sandbox.
2188
+
2189
+ ## [0.15.0] - 2026-07-16
2190
+
2191
+ ### Added
2192
+
2193
+ - Work-mode worktree isolation now automatically carries tracked edits and
2194
+ untracked, non-ignored files into the new worktree, with tracked/untracked
2195
+ counts in human and JSON warnings and fail-clean teardown on sync errors.
2196
+ - Child environments expose authoritative source/execution root metadata, and
2197
+ Delegate-managed snapshot and worktree cleanup refuses targets that are or
2198
+ contain the source workspace.
2199
+ - Empty successful safe and read-only call results retry once when the prompt
2200
+ can be safely extended; tracked runs retain both attempts and envelopes report
2201
+ `emptyRetry` only when a retry was attempted.
2202
+ - Bare Harness resolution in Snapshot, run-output, and wait now reports the
2203
+ resolved Run, Alias, workspace, and age, with a stale-resolution warning after
2204
+ 24 hours.
2205
+
2206
+ ### Changed
2207
+
2208
+ - `run-output --tail N` now selects stdout when no output stream or Completion
2209
+ Report was requested; stderr remains opt-in.
2210
+ - Devin safe mode now fails during preflight with `unsupported_mode` rather than
2211
+ launching without an enforceable read-only boundary.
2212
+ - Call children use their throwaway cwd as `DELEGATE_SOURCE_ROOT`; the
2213
+ Registry/config workspace is not disclosed to a stateless call.
2214
+
2215
+ ### Fixed
2216
+
2217
+ - Empty-result retries now preserve cumulative duration, byte counts, usage,
2218
+ truncation, stdin diagnostics, timeout budgets, and tracked launch-failure
2219
+ state across primary, authentication-fallback, and retry attempts.
2220
+ - Source-root cleanup guards now handle relative, symlinked, case-variant,
2221
+ unresolved, and malformed paths conservatively without blocking safe cleanup
2222
+ of source descendants.
2223
+ - Dirty worktree sync preserves arbitrary filename bytes, rejects unsyncable
2224
+ dirty submodules with escaped diagnostics, and documents the same behavior
2225
+ consistently across the CLI reference and worktree guidance.
2226
+ - Devin help and discovery surfaces now derive supported modes consistently and
2227
+ reject unknown modes before constructing executable arguments.
2228
+ ## [0.14.0] - 2026-07-15
2229
+
2230
+ ### Added
2231
+
2232
+ - `workflow result --field` for extracting a single field from a workflow
2233
+ result, reliable latest-workflow selection, immutable creation ordering,
2234
+ dry-run visibility, and orphan detection (PR #14).
2235
+ - Schema validation for `agent()` results supports `minLength` and
2236
+ `minItems`, including in retries and dry-run placeholders (PR #14).
2237
+ - Grouped work runs sharing one non-isolated workspace now emit a warning
2238
+ with guidance for commit boundaries and persistent worktrees (PR #13).
2239
+
2240
+ ### Changed
2241
+
2242
+ - Focused call help (`delegate <engine> call --help`) now reflects
2243
+ call-mode option boundaries and documents the grouped-call tracking
2244
+ exception (`--cwd` accepted only with `--group`); explicit `agent` input
2245
+ is rejected on engines that do not support it (PR #13).
2246
+ - Overview, dry-run, agent-help, README, CLI reference, and worktree docs
2247
+ corrected from user feedback (PR #13).
2248
+
2249
+ ### Fixed
2250
+
2251
+ - Structured Codex workflows consume the child-authored completion report
2252
+ (including on resume) and fail closed when it is missing; workflow resume
2253
+ transitions atomically to `starting`, hides stale results, rolls back
2254
+ failed launches, and releases locks on preparation errors (PR #14).
2255
+ - Safe isolation re-roots exact source-workspace paths while preserving
2256
+ slash-command payloads verbatim (PR #14).
2257
+ - `wait`: a run matched by both `--latest HARNESS` and `--group NAME`
2258
+ was emitted twice in the resolved-target list; it now appears once, with
2259
+ first-selection precedence and ordering preserved.
2260
+ - `git_root_for` degrades any `OSError` from the git probe (not just
2261
+ `FileNotFoundError`) to the non-git fallback, so e.g. a `PermissionError`
2262
+ spawning git no longer crashes workspace resolution.
2263
+
2264
+ ### Changed
2265
+
2266
+ - Internal cleanup pass across `src/` and `tests/`: removed dead code (unused
2267
+ protocol types, private helpers, stale fixtures), collapsed redundant
2268
+ exception tuples into their `OSError` base, replaced a hand-rolled
2269
+ path-containment helper with `Path.is_relative_to`, and stripped stale
2270
+ review-artifact comments. Behavior-preserving; the workflow supervisor's
2271
+ broad exception boundary around child-model output is now explicitly
2272
+ commented and regression-tested.
2273
+
2274
+ ## [0.13.1] - 2026-07-09
2275
+
2276
+ ### Added
2277
+
2278
+ - Codex-only `--fast` / `--no-fast` per-run service-tier overrides (and a
2279
+ `fast` boolean in run-input JSON). `--fast` emits `service_tier="fast"` plus
2280
+ `features.fast_mode=true` so the tier cannot be silently dropped by ambient
2281
+ Codex config; `--no-fast` emits the explicit `service_tier="default"`
2282
+ standard-routing sentinel; omitting both inherits Codex configuration. The
2283
+ explicit choice is recorded as `requestedFast` in run metadata. The flag and
2284
+ JSON key fail closed on every other engine, including a bare `"fast": null`.
2285
+
2286
+ ## [0.13.0] - 2026-07-09
2287
+
2288
+ ### Added
2289
+
2290
+ - Added `opencode` as a first-class engine across `safe`, `work`, `call`, and
2291
+ workflow runs. OpenCode drives any provider/model in the models.dev catalog
2292
+ (75+ providers, plus custom/local providers) through one harness. Safe mode
2293
+ and `call --read-only` enforce a deny-all-but-read permission lockdown via
2294
+ `OPENCODE_CONFIG_CONTENT` (merges last, beating hostile repo config; verified
2295
+ live against v1.17.17 including a git-worktree write-barrier test). Live
2296
+ model discovery via `opencode models`, string or `{"model", "variant"}`
2297
+ object aliases that can pin a reasoning variant, `--reasoning-effort` mapped
2298
+ to OpenCode `--variant`, and per-run `--agent` selection with
2299
+ `opencode.defaultAgent` fallback.
2300
+
2301
+ ## [0.12.0] - 2026-07-09
2302
+
2303
+ Three features in one train: Delegate Workflows (multi-agent orchestration with durable resume), per-run model selection + discovery across all seven engines, and the Devin engine. Model selection was built as the inaugural Delegate Workflows dogfood: three implementation waves plus a twelve-round two-lane adversarial review loop driven through `workflow run --resume`.
2304
+
2305
+ ### Added
2306
+
2307
+ - Per-run model selection: every engine accepts `--model <alias-or-id>` (alias
2308
+ from `<engine>.models`, or a raw model ID passed through verbatim). Alias maps
2309
+ are generalized beyond Droid to all engines; Droid keeps its optional
2310
+ positional alias and gains optional `droid.defaultModel`. `delegate models
2311
+ <engine>` merges bundled + config catalogs; `--live` probes cursor/droid/devin
2312
+ when available. Non-droid aliases also appear in `models` / `models --summary`.
2313
+ - Delegate Workflows: a Python DSL supervisor for multi-agent fan-out, durable
2314
+ journaling, nested workflow calls, schema-validated `agent()` results,
2315
+ approval gates, resume, kill, saved workflows, and workflow discovery in
2316
+ `describe`/help/docs. Status/list report `stalled` when a supervisor died
2317
+ without finalizing (non-blocking lock probe; `wait`/`watch` exit instead of
2318
+ hanging), and supervisor failures record a traceback tail in the journal,
2319
+ result, and status.
2320
+ - Slash pass-through: launch prompts that intentionally start with a harness
2321
+ slash command can be sent verbatim when the target mode's safety boundary does
2322
+ not depend on Delegate's prompt preamble. `--pass-through` also suppresses the
2323
+ skill preamble and completion-report suffix while preserving safe-mode
2324
+ boundaries.
2325
+ - Added `devin` as a first-class engine for Cognition's Devin CLI across
2326
+ `safe`, `work`, and `call` modes. Devin uses prompt-file transport,
2327
+ config-driven model selection (`devin.defaultModel`, default `swe-1.7`),
2328
+ read-only safe/call enforcement through a Delegate-generated
2329
+ `--agent-config`, and `--permission-mode dangerous` for work/default-call
2330
+ print-mode runs.
2331
+
2332
+ ### Changed
2333
+
2334
+ - Config migration: a `<engine>.models` alias key named after a mode (`safe`,
2335
+ `work`, or `call`) or after its own engine is now a config validation error —
2336
+ rename the alias (aliases naming a *different* engine, like a `droid.models`
2337
+ alias called `grok`, remain valid). Cursor input-JSON `"model"` values that differ from
2338
+ `cursor.defaultModel` are now honored instead of rejected. Droid run-input
2339
+ JSON `"model"` is now alias-or-id like `--model`: a `droid.models` key keeps
2340
+ alias semantics, anything else passes through verbatim to the harness
2341
+ (previously a hard `invalid_alias` error).
2342
+
2343
+ ## [0.11.0] - 2026-07-05
2344
+
2345
+ Profile-guard calibration fix for issue #9: a shell carrying `AI_PROFILE=work|personal` with no matching `~/.delegate/config.<profile>.json` no longer presents a half-configured install as a total CLI outage.
2346
+
2347
+ ### Added
2348
+
2349
+ - `delegate config sync-profiles` materializes missing `~/.delegate/config.<profile>.json` overlays (`work`, `personal`) from the validated base config. It never clobbers an overlay you already edited, validates the merged effective config before any write, and writes each overlay with private-file permissions. `delegate config init` now writes the same overlays alongside the base config. Both share one path convention (`config.profile_config_path`, `config.PROFILE_CONFIG_NAMES`) so the writer and the guard cannot disagree on overlay naming.
2350
+
2351
+ ### Fixed
2352
+
2353
+ - `AI_PROFILE=work|personal` with a missing or unreadable profile overlay no longer hard-blocks every command, including the read-only diagnostics you would reach for to debug it. Recognized-but-configless profiles now block only launch and mutation commands — with remediation text that points at `delegate config sync-profiles` and the `env -u AI_PROFILE` / `DELEGATE_CONFIG=` bypasses — while read-only diagnostics (`profiles`, `runs`, `run-output`, `snapshot`, cached `capabilities`, `worktree show`/`list`, `describe`, `models`, `help`, `version`) pass with a stderr warning. An unrecognized non-empty `AI_PROFILE` now warns and continues on the base account instead of silently falling through.
2354
+
2355
+ ### Security
2356
+
2357
+ - The fail-closed profile-crossover guarantee is now enforced inside the Python CLI (`delegate_agent.cli:main` via the new `delegate_agent.profile_guard`), classifying from the real parsed command rather than positional argv guessing. This closes a gap where the guarantee lived only in the optional shell shim: the pip console script, `python -m delegate_agent.cli`, and `bin/delegate.py` all reach `main` with no shim in front, and previously fell through to the base account on a missing overlay. The guard no-ops when `DELEGATE_CONFIG` is already exported (shim precedence) so the two layers compose without a double check. The tracked `bin/delegate-profile-shim` template applies the same check before Python starts, as an additional early gate; it scans all args for `capabilities refresh` so a mutation is never misclassified as a read-only probe.
2358
+
2359
+ ### Packaging
2360
+
2361
+ - Published to PyPI as `delegate-agent-cli`: PyPI's separator-stripped name-similarity rule blocked the shorter `delegate-agent` (an existing `DelegateAgent` project collides). The installed console script is still `delegate`; only the `pip install` name changed.
2362
+ - Hardened two tests (`test_execution_argv_and_prompt.py`, `test_wait_cancel_commands.py`) that raced child-process teardown against the isolation and cleanup assertions they were checking, which showed up as intermittent failures on the publish gate.
2363
+
2364
+ ## [0.10.0] - 2026-07-04
2365
+
2366
+ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week of agent usage were mined for friction and failure modes, and the whole Tier 1–3 backlog was built across four decorrelated implementation waves plus live acceptance.
2367
+
2368
+ ### Added
2369
+
2370
+ - `delegate wait` blocks on one or more runs until they reach a terminal state, using effective status so a dead child is a terminal failure rather than a hang. Supports bare-harness and `harness:model` latest selectors, `--group`, an optional timeout, and completion-report output; exits 0 (all succeeded), 1 (any failed/cancelled), or 124 (timeout). Replaces the ~100 hand-rolled polling loops agents wrote in the audit week.
2371
+ - `delegate cancel` signals a run's recorded process group (SIGTERM → 5s grace judged by group liveness → SIGKILL) with layered safety: workspace-scoped resolution, terminal/stale refusal, `pid`/`pgid <= 1` guards, and a `ps`-lstart start-identity check that refuses to signal a pid older than the run (soft-degrades when `ps` is unavailable). A `cancelRequested` marker is stamped under the registry lock before any signal so the runner finalizer can never record a cancelled run as succeeded.
2372
+ - `cancelled` is a first-class terminal status with normalized per-harness `terminalEvent`/`terminalStatus` mapping (e.g. Grok `stopReason: Cancelled` overrides an exit-0 success). Cancelled and failed runs without a child report now get a synthesized completion report (status, failure reason, redacted stderr tail, harness-appropriate remediation) so `run-output --completion-report` never dead-ends.
2373
+ - Always-numbered aliases (`codex-1`, `cursor-2`, …). Bare harness names become latest-run selectors and `harness:modelAlias` selectors resolve the newest matching run; envelopes and text banners expose `requestedHandle`/`resolvedHandle`/`resolutionKind`, and generated follow-up commands always use the concrete numbered alias. `run-output` gains `--latest`.
2374
+ - `resultQuality` classification on tracked runs (`ok` / `housekeeping_noop` / `empty` / `suspect_short` / `no_assistant_text`), computed at finalization and preferred from stored state at read time — closing the hole where an on-disk Droid "Plan is up-to-date." report surfaced as a clean success. Envelopes always carry `completionReportWritten` and `completionReportSource` (`child` / `delegate_synthesized` / `stdout_recovery`); auth failures classify as `auth_failed` from stderr-only patterns.
2375
+ - `--include-dirty` on worktree work launches syncs uncommitted tracked changes and untracked non-ignored files through the same primitives as the safe-mode snapshot, replacing the stash-launch-pop dance; sync failures tear the worktree down before any child launches.
2376
+ - `--group NAME` tags launches and selects on `runs`, `wait`, and `worktree remove`/`prune`.
2377
+ - A per-run scratch `TMPDIR` is exported to safe and isolated runs after profile env; the codex lane is granted it via `--add-dir`.
2378
+ - `did-you-mean` suggestions on unknown handles, a `list` → `runs` alias, corrected-command text on flag-order errors, and copy-paste command forms on invalid-mode errors.
2379
+
2380
+ ### Changed
2381
+
2382
+ - `--forbid-commit` now implies `--isolation worktree` on both the CLI and JSON paths.
2383
+ - Work-mode `noChanges` and quality warnings ride the top-level `warnings` array (including the runs table). Text `run-output` discloses char truncation like JSON, and `--tail`/`--max-chars` without a stream selection is now rejected instead of silently ignored.
2384
+ - `describe` full output is a strict superset of `--summary`, both derived from `COMMAND_SPECS`.
2385
+
2386
+ ### Fixed
2387
+
2388
+ - Registry first-init race fixed with locked init and unique atomic temp names; `write_json_atomic` cleans up temp files on failure. Run-latest tie-breaks use an explicit `registrationOrdinal` stamped under the registry lock (in-memory insertion order degrades through `save_index` on reload).
2389
+ - Plaintext progress advances every line instead of freezing on the first; `call` mode returns a redacted `stderrTail` on failure and an empty-text warning instead of raw event noise; `droid call` prevalidates model aliases before creating the workspace and cleans up on every failure path.
2390
+
2391
+ ### Security
2392
+
2393
+ - The native boundary read empirically reproduced a leak inherited from the safe-mode mirror: an untracked symlink with an absolute target pointing at the repo's own gitignored secret was recreated verbatim — readable and writable-through in an edit-capable worktree. The shared sync now recreates untracked symlinks only when the link is relative, resolves inside the repo, and the target is not gitignored (batched `git check-ignore -z --stdin`, failing closed to placeholders on unexpected exit codes), hardening safe mode and `--include-dirty` together. The hardlink variant cannot be closed by path-based exclusion and is documented as a caveat.
2394
+
2395
+ ## [0.9.0] - 2026-07-01
2396
+
2397
+ ### Added
2398
+
2399
+ - Stateless `call` mode for every engine (`delegate <engine> call "prompt"`, plus `droid MODEL call`). Call mode sends a one-hop prompt to a model and returns its output without a project tree, run registry, snapshot, or completion report — the generic "call a model, get the answer back" path for agents that don't need repo context. It runs in an empty temporary cwd that is always cleaned up, even on build-time failure.
2400
+ - Call mode is **write-capable by default**, inheriting work-level harness permissions (the equivalent of `work` mode minus a repo). A new `--read-only` flag (and `readOnly` JSON input field) opts into the LLM-as-judge/grader contract: it drops the child to each engine's `safe`-mode read-only capability and prepends a neutralizing preamble telling the model there is nothing to inspect or mutate. `--read-only` applies only to `call` and is rejected with `safe`/`work`. Pairs with Codex `--output-schema` for structured verdicts. See `examples/task.judge.json`.
2401
+ - Call JSON output includes `textChars` and `textTruncated` so callers can detect when bounded assistant text kept only the head and tail of a large response. Human-mode `dry-run` now prints `warning:` lines.
2402
+
2403
+ ### Security
2404
+
2405
+ - Call mode is not a security sandbox. The effective harness policy resolves through the work/safe tiers (default call keeps work-tier web-search/network access; `--read-only` call gets the safe policy), and work-mode approval/sandbox bypass never leaks into call mode. On engines without a native read-only sandbox (Cursor, Droid, Kimi) the neutralizing preamble is the only restriction under `--read-only`; `docs/security-model.md` documents the boundary.
2406
+
2407
+ ## [0.8.1] - 2026-07-01
2408
+
2409
+ ### Fixed
2410
+
2411
+ - Launch and `dry-run` commands now accept `--json` in the launch option tail before inline prompt text begins, so agent callers can append it after flags such as `--prompt-file` without tripping the misplaced-global guard. A later `--json` after prompt text still fails closed as ambiguous flag-like prompt text.
2412
+
2413
+ ## [0.8.0] - 2026-06-29
2414
+
2415
+ ### Added
2416
+
2417
+ - First-class `delegate grok {safe,work}` for xAI Grok Build CLI: prompt-file transport, tracked `streaming-json` snapshots, safe isolation required, worktree `--cwd` rewrite, harness-scoped bypass at `policy.harness.grok.work.bypassApprovalsAndSandbox`, and Grok `--effort` reasoning mapping. Safe mode pairs Delegate's isolated worktree copy with Grok's kernel-enforced `--sandbox read-only` profile, and the streaming `error` event is surfaced into the snapshot. Grok `--output-schema` is unsupported in this release because Grok `--json-schema` forces final JSON output, which breaks tracked streaming snapshots.
2418
+ - `delegate config init` command to write an editable starter config from an installed package, so users no longer need a source checkout just to copy `config.example.json`.
2419
+
2420
+ ### Changed
2421
+
2422
+ - WSL setup is now documented explicitly: install Python/Git/child CLIs inside WSL, prefer `/home/<user>/...`, and convert Windows paths with `wslpath -u`.
2423
+
2424
+ ### Fixed
2425
+
2426
+ - Windows-style paths now fail with actionable WSL guidance instead of turning into confusing POSIX relative paths, and WSL runs fail loudly when `git` resolves to Windows `git.exe`. Workspaces under `/mnt/<drive>` now emit a warning about WSL filesystem performance and private-file semantics.
2427
+
2428
+ ## [0.7.0] - 2026-06-29
2429
+
2430
+ ### Added
2431
+
2432
+ - Profile-aware auth and environment switching. A new top-level `profiles` config block (`detectFrom`, `default`, `definitions.<name>.env`) lets one session run under a chosen credential/environment profile and have every spawned harness inherit it. The active profile is detected from an environment variable (`profiles.detectFrom`, e.g. `DELEGATE_PROFILE`/`AI_PROFILE`) or pinned explicitly with the new global `--auth-profile NAME` flag. Delegate resolves the profile once per request and injects its env into every child across tracked, pass-through, safe-isolation, and persistent-worktree paths. Profile `env` holds non-secret routing pointers only — secret-shaped keys are rejected at config load with `secret_in_profile_env`.
2433
+ - `delegate profiles` command (with `--json`): read-only introspection of the resolved profile, its source (`flag`, a detection variable name, or `default`), and the non-secret env keys it injects. It never mutates config.
2434
+ - `codex.fallbackProfile`: when a Codex run hits a classified usage limit on a clean work-mode baseline with no tool events, Delegate retries once under the fallback profile's account (same env, `CODEX_HOME` swapped). A fallback that resolves to the same account is a no-op. Completions record `codexAuthFallback` metadata.
2435
+ - Codex `--output-schema FILE` flag and `outputSchema` run-input field for structured final output. Codex-only; OpenAI enforces the JSON Schema on Codex's final message. Relative paths resolve against the launch cwd and are locked absolute before isolation. When set, the completion-report prompt injection is suppressed so the schema owns the final message. Other engines reject it with `unsupported_output_schema`, and `delegate --json describe` advertises `engineCapabilities.<engine>.outputSchema` for feature detection.
2436
+ - `delegate --json <command> --help` payloads now include `globalOptions` and `unsupportedGlobalOptions`, so agents can discover which global options (such as `--auth-profile`) apply to a command without parsing usage strings.
2437
+
2438
+ ### Changed
2439
+
2440
+ - Safe-mode runs over a dirty Git tree now inject a bounded changed-file note into the prompt before the per-engine transport split, so the synced working-tree state reaches the child regardless of stdin/prompt-file/argv transport. Documentation across help, `describe`, `agent-help`, README, security-model, and the CLI reference now states plainly that safe mode mirrors uncommitted tracked edits and untracked non-ignored files into the isolated copy.
2441
+ - `--auth-profile` is accepted only where a child auth/env selection actually happens: launches, `dry-run`, `run --input-json`, `delegate profiles`, and `capabilities refresh`. It is rejected for the cached `capabilities` report and for run-inspection, worktree-management, and discovery commands.
2442
+
2443
+ ### Fixed
2444
+
2445
+ - Run retrieval hints (trailer, JSON payload, snapshot, run summary) are now workspace-qualified: the registry is per-workspace, so commands are rendered through `shlex.join` with the source `--cwd`, and the unknown-handle error explains that runs are per-workspace.
2446
+ - `--forbid-commit` and reasoning-effort/model preflight errors are now actionable — they name the corrective flag or config key (`codex.defaultModel` / `droid.models`) and, in a non-Git workspace, explain that no-commit enforcement requires Git rather than demanding an impossible `--isolation worktree`.
2447
+ - The codex usage-limit fallback retry now injects the active profile's full env with only `CODEX_HOME` swapped, instead of dropping the profile's other pointers onto a bare environment.
2448
+ - The internal "codex auth attempt" delimiter is no longer written to a non-Codex run's stderr log when a profile happens to define both a `CODEX_HOME` and a `codex.fallbackProfile`.
2449
+
2450
+ ## [0.6.0] - 2026-06-23
2451
+
2452
+ ### Added
2453
+
2454
+ - Always-on best-effort credential scrubbing on `describe`/`models` discovery output.
2455
+ - Heartbeat opt-in via config: `progress.enabled`, `progress.initialDelaySec`, and `progress.intervalSec`, plus `--no-progress` to override config for one launch.
2456
+ - Foreground launch progress via `--progress`, emitted to stderr so JSON stdout remains machine-readable.
2457
+ - Persistent worktree `workSummary` metadata, including dirty state, changed file counts, diff stat, and child-created commits. `--forbid-commit` now fails persistent worktree work runs if the child creates commits.
2458
+ - `run-output --max-chars` for bounded non-raw stdout/stderr sections, plus `rawOutputBytes` metadata for intentional `--raw` reads.
2459
+
2460
+ ### Changed
2461
+
2462
+ - Removed discovery `--redacted` cosmetic masking; `--summary` remains the compact discovery surface.
2463
+ - `worktree list/show` now distinguish `branchMergedIntoSource` from `mergedIntoSource`; `mergedIntoSource` means the branch is merged and the worktree has no uncommitted changes.
2464
+ - Kimi help and docs now match actual argv behavior: Delegate uses Kimi prompt mode and does not emit `--yolo` with `--prompt`.
2465
+
2466
+ ### Fixed
2467
+
2468
+ - Heartbeat path scrubbing is URL-safe and covers additional container/CI absolute paths without corrupting `https://…` URLs.
2469
+ - Global `--json` inference now applies consistently before more subcommands.
2470
+ - Completion-report recovery now prefers substantive final assistant output over housekeeping/progress output when no explicit completion report exists.
2471
+ - Worktree handle suggestions are scoped to persistent worktrees, and safe-mode prompts more clearly allow read-only investigation and text-only patch proposals.
2472
+ - Shared fake-agent test harness output is quiet by default.
2473
+
2474
+ ## [0.5.0] - 2026-06-18
2475
+
2476
+ ### Added
2477
+
2478
+ - New `claude` engine wrapping Claude Code headless mode (`claude -p`). `delegate claude safe` and `delegate claude work` deliver the prompt on stdin and parse Claude Code's `stream-json` output, the same way the other harnesses are normalized. Requires Claude Code 2.1.x or newer (verified on 2.1.181) for `--effort`, `--permission-mode auto`, and `--no-session-persistence`.
2479
+
2480
+ - Claude safe mode runs in a temporary isolated workspace (detached worktree or directory copy) with `--permission-mode plan`, `--strict-mcp-config`, a Read/Grep/Glob tool set, and a read-only Bash allowlist (`git diff/status/show/log`, `rg`, `grep`, `ls`). Safe mode is added to the engines that require real isolation, so `--isolation none` is rejected for it.
2481
+
2482
+ - Claude work mode uses `claude.workPermissionMode` (default `auto`). Delegate only emits `--permission-mode bypassPermissions` when `policy.harness.claude.work.bypassApprovalsAndSandbox` is explicitly set; `workPermissionMode` itself rejects `bypassPermissions` so a global sandbox profile can never silently broaden Claude's permissions.
2483
+
2484
+ - Reasoning effort for Claude maps directly to Claude Code's native `--effort` (`low`, `medium`, `high`, `xhigh`, `max`), validated before launch and kept independent of the Codex/Droid model-capability cache.
2485
+
2486
+ - New `claude` config section (`binary`, `defaultModel`, `defaultReasoningEffort`, `workPermissionMode`, `noSessionPersistence`, `bare`) with validation, and Claude coverage across `describe`, `models`, `reasoning-capabilities`, and `dry-run`. Tool activity is surfaced as `tool.started` / `tool.completed` events parsed from Claude's `tool_use` / `tool_result` content blocks.
2487
+
2488
+ ## [0.4.0] - 2026-06-15
2489
+
2490
+ ### Changed
2491
+
2492
+ - Safe mode now requires real isolation for Cursor, Droid, and Kimi: `--isolation none` (or `isolation.safe = "none"` in config) is rejected for these engines with `invalid_isolation`, so safe runs always execute in a temporary isolated workspace. **Migration:** remove any `{"isolation": {"safe": "none"}}` override for cursor/droid/kimi and use `auto` or `worktree`. Codex safe still permits `none` because it enforces its own `--sandbox read-only`.
2493
+
2494
+ - `delegate droid safe` now defaults to a temporary isolated worktree instead of running in place in the source tree, matching Cursor, Codex, and Kimi safe.
2495
+
2496
+ - `delegate snapshot` now surfaces `creationContext` (`sourceHeadOid`, `sourceBranch`, `sourceGitCommonDir`, `plannedExecutionCwd`) for persistent-worktree runs, sourced from the run manifest when the snapshot omits it.
2497
+
2498
+ - `run-output` stdout/stderr section `truncated` now reflects whether the tail actually cut content, instead of always reporting `true` for live and archived tails. Parent agents that branch on `truncated` to decide whether to fetch `--raw` should re-check.
2499
+
2500
+ ### Fixed
2501
+
2502
+ - A single corrupt or partially written per-run `state.json` / `manifest.json` no longer aborts whole-registry commands (`runs`, `snapshot`, `run-output`, `worktree list`) or blocks launching new runs. Bulk readers skip the bad file and degrade for that one run, while commands targeting a specific run still fail loud.
2503
+
2504
+ - `delegate kimi work` no longer passes `--yolo` together with `--prompt`; current Kimi CLI rejects that combination, and Kimi prompt mode already auto-approves tool actions.
2505
+
2506
+ ## [0.3.1] - 2026-06-12
2507
+
2508
+ ### Changed
2509
+
2510
+ - Troubleshooting guidance now covers Kimi binary checks, active config layer inspection, safe-mode dry-run limits, pass-through option placement, exact-payload completion-report behavior, and worktree cleanup flags.
2511
+ - Delegate completion-report instructions now tell child agents to put exact operator-requested payloads, such as bare JSON, after the concise parent-facing report instead of wrapping them inside it.
2512
+ - Local planning documents under `docs/plans/` are ignored as private working artifacts.
2513
+
2514
+ ### Fixed
2515
+
2516
+ - `missing_binary` errors now include actionable JSON diagnostics (`configPath`, `configKey`, and optional `suggestedBinaryPath`) for configured child runtimes, including persistent worktree preflight and launch paths.
2517
+ - Launch and dry-run parsing now reject misplaced global completion/pass-through options after the subcommand or mode, matching the documented option placement rules.
2518
+
2519
+ ## [0.3.0] - 2026-06-12
2520
+
2521
+ ### Added
2522
+
2523
+ - Kimi Code harness (`delegate kimi`). Safe mode runs in an isolated temporary workspace with Delegate's read-only safety prompt; work mode emits Kimi `--yolo` by default for edit-capable prompt-mode runs. Delegate intentionally does not use Kimi `--plan` for safe mode. Kimi prompt mode auto-approves tool actions, so safe mode's effective write boundary is the isolated workspace and the safety prompt is advisory. Model selection uses `kimi.defaultModel` config or the `model` field in JSON run input. Reasoning effort is not supported for Kimi in v1.
2524
+
2525
+ ## [0.2.0] - 2026-06-09
2526
+
2527
+ ### Added
2528
+
2529
+ - Provider-aware `--reasoning-effort LEVEL` for Codex, Droid, and Cursor runs (plus `reasoningEffort` in JSON run input). Values are literal and validated against per-model capability declarations resolved from config (`reasoning.capabilities`), a refreshable workspace cache, or bundled fallback data. Explicit requests fail closed with `unsupported_reasoning_effort`; an engine `defaultReasoningEffort` config default that cannot be satisfied is skipped with a recorded warning instead of failing every run.
2530
+
2531
+ - `delegate capabilities` reports the merged reasoning capability matrix; `delegate capabilities refresh` probes `codex debug models` and writes `.delegate/capabilities/reasoning.json` atomically with owner-only permissions. A malformed cache file is ignored at run time and overwritten by the next refresh.
2532
+
2533
+ - Prompt text no longer travels in child argv: Codex prompts are delivered via stdin and Droid prompts via a private temp file. Dry-run payloads and manifests show redaction placeholders plus a `promptTransport` field, and stdin delivery failures surface as a run warning on stderr and in the snapshot.
2534
+
2535
+ - `run-output --completion-report` now recovers the last interim assistant message for dead Droid runs as well as Cursor runs (marked `synthetic`); Codex recovery still requires a completed final turn.
2536
+
2537
+ ### Changed
2538
+
2539
+ - `run-output --stdout`/`--stderr` without `--tail` or `--raw` defaults to a bounded 80-line tail instead of erroring with `missing_tail`. Text output marks tailed sections (`last N lines; full log B bytes`) and synthetic completion reports in the section header; JSON output carries the equivalent flags.
2540
+
2541
+ - `worktree show --latest HARNESS` resolves the most recent persistent worktree for that harness, intentionally ignoring newer non-worktree runs. `worktree list` JSON gains a `summary`; `totalPersistentWorktrees` is registry-wide while `allStatusCounts` is scoped to the `--harness` filter.
2542
+
2543
+ - Run listings probe each run's pid once per entry, so `effectiveStatus` and `staleReason` can no longer disagree about a process that exits mid-listing.
2544
+
2545
+ - `reasoning.capabilities` config keys are restricted to `codex` and `droid` (Cursor uses `cursor.reasoningEffortModels`), and effort strings reject whitespace, double quotes, and backslashes.
2546
+
2547
+ ## [0.1.4] - 2026-06-08
2548
+
2549
+ ### Fixed
2550
+
2551
+ - Child agent processes now receive EOF on stdin instead of inheriting Delegate's own
2552
+ stdin. This prevents Codex runs launched from orchestrators with open stdin pipes
2553
+ from hanging before they emit output.
2554
+
2555
+ ## [0.1.3] - 2026-06-05
2556
+
2557
+ ### Added
2558
+
2559
+ - Codex streaming events are now parsed by the run tracker. `item.started`, `item.completed`, `turn.started`, and `turn.completed` events surface `agent_message` text and `command_execution` tool activity from `codex` runs in snapshots and completion reports.
2560
+
2561
+ - `run-output --completion-report` recovers a completion report from the recorded child stdout stream when `completion-report.md` is absent and the run has finished. Recovered reports are reconstructed with the same event parser used during live tracking, and are marked `synthetic: true` with `source: "stdout.log"` in JSON output. Codex recovery only promotes an `agent_message` once the stream reaches `turn.completed`, so in-progress messages are never treated as a final report.
2562
+
2563
+ - Synthetic completion-report recovery is bounded and best-effort. Delegate reads only a limited stdout tail during recovery, including archived stdout, and reports a clean `missing_completion_report` error when no completed final message is available inside that recovery window.
2564
+
2565
+ - Display-side redaction now covers common credential shapes such as authorization headers, bearer/basic tokens, JWT-like strings, and common secret key-values in snapshots and run-output views.
2566
+
2567
+ - Prompt input from delayed stdin pipes is now accepted when no direct prompt or prompt file is supplied.
2568
+
2569
+ ### Notes
2570
+
2571
+ - Releases before 0.1.3 predate this changelog.
2572
+
2573
+ [Unreleased]: https://github.com/treygoff24/delegate-agent/compare/v0.32.0...HEAD
2574
+ [0.32.0]: https://github.com/treygoff24/delegate-agent/compare/v0.31.0...v0.32.0
2575
+ [0.31.0]: https://github.com/treygoff24/delegate-agent/compare/v0.29.1...v0.31.0
2576
+ [0.30.0]: https://github.com/treygoff24/delegate-agent/compare/v0.29.1...v0.30.0
2577
+ [0.29.1]: https://github.com/treygoff24/delegate-agent/compare/v0.29.0...v0.29.1
2578
+ [0.29.0]: https://github.com/treygoff24/delegate-agent/compare/v0.28.0...v0.29.0
2579
+ [0.28.0]: https://github.com/treygoff24/delegate-agent/compare/v0.27.0...v0.28.0
2580
+ [0.27.0]: https://github.com/treygoff24/delegate-agent/compare/v0.26.0...v0.27.0
2581
+ [0.26.0]: https://github.com/treygoff24/delegate-agent/compare/v0.25.0...v0.26.0
2582
+ [0.25.0]: https://github.com/treygoff24/delegate-agent/compare/v0.24.0...v0.25.0
2583
+ [0.24.0]: https://github.com/treygoff24/delegate-agent/compare/v0.23.0...v0.24.0
2584
+ [0.23.0]: https://github.com/treygoff24/delegate-agent/compare/v0.22.0...v0.23.0
2585
+ [0.22.0]: https://github.com/treygoff24/delegate-agent/compare/v0.21.0...v0.22.0
2586
+ [0.21.0]: https://github.com/treygoff24/delegate-agent/compare/v0.20.0...v0.21.0
2587
+ [0.20.0]: https://github.com/treygoff24/delegate-agent/compare/v0.19.0...v0.20.0
2588
+ [0.19.0]: https://github.com/treygoff24/delegate-agent/compare/v0.18.0...v0.19.0
2589
+ [0.18.0]: https://github.com/treygoff24/delegate-agent/compare/v0.17.0...v0.18.0
2590
+ [0.17.0]: https://github.com/treygoff24/delegate-agent/compare/v0.16.0...v0.17.0
2591
+ [0.16.0]: https://github.com/treygoff24/delegate-agent/compare/v0.15.0...v0.16.0
2592
+ [0.15.0]: https://github.com/treygoff24/delegate-agent/compare/v0.14.0...v0.15.0
2593
+ [0.14.0]: https://github.com/treygoff24/delegate-agent/compare/v0.13.1...v0.14.0
2594
+ [0.13.1]: https://github.com/treygoff24/delegate-agent/compare/v0.13.0...v0.13.1
2595
+ [0.13.0]: https://github.com/treygoff24/delegate-agent/compare/v0.12.0...v0.13.0
2596
+ [0.12.0]: https://github.com/treygoff24/delegate-agent/compare/v0.11.0...v0.12.0
2597
+ [0.11.0]: https://github.com/treygoff24/delegate-agent/compare/v0.10.0...v0.11.0
2598
+ [0.10.0]: https://github.com/treygoff24/delegate-agent/compare/v0.9.0...v0.10.0
2599
+ [0.9.0]: https://github.com/treygoff24/delegate-agent/compare/v0.8.1...v0.9.0
2600
+ [0.8.1]: https://github.com/treygoff24/delegate-agent/compare/v0.8.0...v0.8.1
2601
+ [0.8.0]: https://github.com/treygoff24/delegate-agent/compare/v0.7.0...v0.8.0
2602
+ [0.7.0]: https://github.com/treygoff24/delegate-agent/compare/v0.6.0...v0.7.0
2603
+ [0.6.0]: https://github.com/treygoff24/delegate-agent/compare/v0.5.0...v0.6.0
2604
+ [0.5.0]: https://github.com/treygoff24/delegate-agent/compare/v0.4.0...v0.5.0
2605
+ [0.4.0]: https://github.com/treygoff24/delegate-agent/compare/v0.3.1...v0.4.0
2606
+ [0.3.1]: https://github.com/treygoff24/delegate-agent/compare/v0.3.0...v0.3.1
2607
+ [0.3.0]: https://github.com/treygoff24/delegate-agent/compare/v0.2.0...v0.3.0
2608
+ [0.2.0]: https://github.com/treygoff24/delegate-agent/compare/v0.1.4...v0.2.0
2609
+ [0.1.4]: https://github.com/treygoff24/delegate-agent/compare/v0.1.3...v0.1.4
2610
+ [0.1.3]: https://github.com/treygoff24/delegate-agent/releases/tag/v0.1.3