delegate-agent-cli 0.26.0__tar.gz → 0.28.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 (192) hide show
  1. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/CHANGELOG.md +58 -1
  2. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/PKG-INFO +3 -1
  3. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/README.md +2 -0
  4. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/agent-setup.md +1 -1
  5. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/cli-reference.md +11 -4
  6. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/configuration.md +1 -1
  7. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/pyproject.toml +1 -1
  8. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/__init__.py +1 -1
  9. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/argv_builders.py +0 -18
  10. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/cli.py +115 -141
  11. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/cli_parser.py +49 -64
  12. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/command_help.py +17 -4
  13. delegate_agent_cli-0.28.0/src/delegate_agent/failover_state.py +201 -0
  14. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/harness_discovery.py +31 -0
  15. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/inspection_commands.py +26 -1
  16. delegate_agent_cli-0.28.0/src/delegate_agent/mail.py +199 -0
  17. delegate_agent_cli-0.26.0/src/delegate_agent/mail.py → delegate_agent_cli-0.28.0/src/delegate_agent/mail_core.py +148 -593
  18. delegate_agent_cli-0.28.0/src/delegate_agent/mail_push.py +600 -0
  19. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/profiles.py +20 -6
  20. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/request_build.py +12 -17
  21. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/request_models.py +25 -1
  22. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/run_metadata.py +58 -0
  23. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/run_status.py +4 -0
  24. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/runner.py +242 -57
  25. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_execution.py +52 -59
  26. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/PKG-INFO +3 -1
  27. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +4 -0
  28. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_command_help.py +16 -0
  29. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_execution_worktree_run.py +135 -0
  30. delegate_agent_cli-0.28.0/tests/test_failover_state.py +105 -0
  31. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_harness_discovery.py +18 -0
  32. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_inspection_commands.py +91 -0
  33. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_bounds.py +66 -0
  34. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_contract.py +76 -4
  35. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_gating.py +64 -1
  36. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_prune.py +32 -0
  37. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push_adapters.py +2 -4
  38. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_profiles.py +177 -1
  39. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_attachment.py +3 -0
  40. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_runner_capture.py +363 -31
  41. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_utility_modules.py +2 -1
  42. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/CONTRIBUTING.md +0 -0
  43. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/LICENSE +0 -0
  44. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/MANIFEST.in +0 -0
  45. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/SECURITY.md +0 -0
  46. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/bin/delegate-profile-shim +0 -0
  47. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/bin/delegate.py +0 -0
  48. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/config.example.json +0 -0
  49. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/assets/delegate-agent-header.png +0 -0
  50. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/delegate-workflows.md +0 -0
  51. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/development.md +0 -0
  52. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/live-runtime.md +0 -0
  53. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/publishing-checklist.md +0 -0
  54. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/security-model.md +0 -0
  55. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/troubleshooting.md +0 -0
  56. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/docs/worktrees.md +0 -0
  57. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.claude.json +0 -0
  58. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.codex.json +0 -0
  59. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.cursor.json +0 -0
  60. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.droid.json +0 -0
  61. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.grok.json +0 -0
  62. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.judge.json +0 -0
  63. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/examples/task.kimi.json +0 -0
  64. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/setup.cfg +0 -0
  65. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/archived_logs.py +0 -0
  66. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/argv_utils.py +0 -0
  67. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/bundled_models.py +0 -0
  68. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/capability_commands.py +0 -0
  69. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/child_failures.py +0 -0
  70. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/command_errors.py +0 -0
  71. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/config.py +0 -0
  72. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/config_commands.py +0 -0
  73. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/constants.py +0 -0
  74. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/describe_payload.py +0 -0
  75. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/errors.py +0 -0
  76. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/git_utils.py +0 -0
  77. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/harness_events.py +0 -0
  78. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/isolation.py +0 -0
  79. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/json_types.py +0 -0
  80. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/log_output.py +0 -0
  81. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/model_discovery.py +0 -0
  82. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/personas.py +0 -0
  83. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/private_io.py +0 -0
  84. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/profile_commands.py +0 -0
  85. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/profile_guard.py +0 -0
  86. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/prompt_instructions.py +0 -0
  87. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/prompt_transport.py +0 -0
  88. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/reasoning.py +0 -0
  89. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/redaction.py +0 -0
  90. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/rendering.py +0 -0
  91. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/resume_command.py +0 -0
  92. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/retention.py +0 -0
  93. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/run_output_commands.py +0 -0
  94. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/run_registry.py +0 -0
  95. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/safe_workspace.py +0 -0
  96. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/seatbelt.py +0 -0
  97. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/setup_commands.py +0 -0
  98. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/snapshot_view.py +0 -0
  99. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/structured_output.py +0 -0
  100. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/wait_cancel_commands.py +0 -0
  101. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/__init__.py +0 -0
  102. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/commands.py +0 -0
  103. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/registry.py +0 -0
  104. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/runtime.py +0 -0
  105. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/schema.py +0 -0
  106. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/workflows/script.py +0 -0
  107. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_commands.py +0 -0
  108. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_gc.py +0 -0
  109. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_mgmt.py +0 -0
  110. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_records.py +0 -0
  111. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_remove.py +0 -0
  112. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/worktree_summary.py +0 -0
  113. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent/wsl.py +0 -0
  114. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
  115. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
  116. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/requires.txt +0 -0
  117. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
  118. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_capability_commands.py +0 -0
  119. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_child_failures.py +0 -0
  120. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_codex_pure_sandbox.py +0 -0
  121. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_codex_thread_resilience.py +0 -0
  122. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_config_commands.py +0 -0
  123. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_delegate_help_cli.py +0 -0
  124. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_delegate_isolation.py +0 -0
  125. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_delegate_parser.py +0 -0
  126. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_delegate_validation.py +0 -0
  127. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_end_to_end_tracking.py +0 -0
  128. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_engine_argv.py +0 -0
  129. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_execution_argv_and_prompt.py +0 -0
  130. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_execution_dry_run.py +0 -0
  131. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_execution_worktree_failure_cleanup.py +0 -0
  132. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_execution_worktree_preflight.py +0 -0
  133. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_harness_events.py +0 -0
  134. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_kimi_commands.py +0 -0
  135. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_delivery.py +0 -0
  136. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_eligibility.py +0 -0
  137. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_framing.py +0 -0
  138. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_identity.py +0 -0
  139. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_io.py +0 -0
  140. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_parser.py +0 -0
  141. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push.py +0 -0
  142. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push_batch.py +0 -0
  143. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push_cursor.py +0 -0
  144. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push_gating.py +0 -0
  145. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_push_seams.py +0 -0
  146. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_reply.py +0 -0
  147. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_resolution.py +0 -0
  148. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_mail_rules.py +0 -0
  149. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_model_discovery.py +0 -0
  150. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_model_selection_wave1a.py +0 -0
  151. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_model_selection_wave1b.py +0 -0
  152. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_omp_read_only_behavior.py +0 -0
  153. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_packaging.py +0 -0
  154. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_capability.py +0 -0
  155. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_claude.py +0 -0
  156. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_contract.py +0 -0
  157. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_framer.py +0 -0
  158. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_opencode.py +0 -0
  159. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_parser.py +0 -0
  160. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_records.py +0 -0
  161. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_resolution.py +0 -0
  162. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_size_guard.py +0 -0
  163. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_validation.py +0 -0
  164. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_persona_workflow.py +0 -0
  165. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_pure_call.py +0 -0
  166. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_reasoning_capabilities.py +0 -0
  167. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_capture.py +0 -0
  168. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_inheritance.py +0 -0
  169. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_parser.py +0 -0
  170. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_projections.py +0 -0
  171. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_refusals.py +0 -0
  172. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_size_guard.py +0 -0
  173. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_stale.py +0 -0
  174. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_resume_trust.py +0 -0
  175. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_retention.py +0 -0
  176. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_run_registry.py +0 -0
  177. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_safe_workspace_isolation.py +0 -0
  178. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_setup_commands.py +0 -0
  179. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_slash_passthrough.py +0 -0
  180. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_snapshot_redaction.py +0 -0
  181. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_snapshot_rendering.py +0 -0
  182. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_snapshot_run_output.py +0 -0
  183. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_snapshot_view.py +0 -0
  184. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_structured_output.py +0 -0
  185. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_tracked_timeout.py +0 -0
  186. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_wait_cancel_commands.py +0 -0
  187. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_wave4_launch_features.py +0 -0
  188. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_workflow_commands.py +0 -0
  189. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_worktree_list_show.py +0 -0
  190. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_worktree_prune_gc.py +0 -0
  191. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_worktree_remove.py +0 -0
  192. {delegate_agent_cli-0.26.0 → delegate_agent_cli-0.28.0}/tests/test_wsl_guardrails.py +0 -0
@@ -5,7 +5,62 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.28.0] - 2026-08-05
9
+
10
+ ### Added
11
+
12
+ - Added `delegate runs --structural` and `delegate ps --structural` for
13
+ content-free local status collection, including lifecycle, model, group,
14
+ status, timestamp, and root initiator provenance.
15
+ - Tracked runs now retain a validated root initiator across nested Delegate
16
+ launches and persistent-worktree execution.
17
+
18
+ ### Changed
19
+
20
+ - Codex quota fallback is now explicitly configured with
21
+ `codex.fallbackProfile`, supports arbitrary profile definitions, and keeps
22
+ temporary blocks by resolved credential identity rather than profile alias.
23
+ Default work/personal credential homes continue to interoperate with legacy
24
+ profile launchers without allowing remapped aliases to share state.
25
+ - Codex-only failover no longer depends on private Claude shim names or hidden
26
+ runtime controls. Retry and persistent-worktree paths retain the account
27
+ that is actually serving the run.
28
+
29
+ ### Fixed
30
+
31
+ - Structural run listings now exclude raw terminal/provider events and apply
32
+ normal secret redaction to retained fields.
33
+ - Fallback failures persist the correct account block and provider-reported
34
+ reset time; a blocked fallback is skipped, and retries no longer return to a
35
+ blocked primary after a preflight swap.
36
+ - Failover tests isolate their state from the user's home directory, and
37
+ `delegate ps --help` now advertises its supported structural view.
38
+
39
+ ## [0.27.0] - 2026-08-01
40
+
41
+ ### Changed
42
+
43
+ - Split the mail module into `mail_core` (mailbox) and `mail_push` (hook
44
+ protocol) behind a stable `mail` facade; extracted the runner's mail
45
+ sentinel capture and push finalization; unified the three launch seams'
46
+ mail preparation in one helper with ownership transfer kept at the seams;
47
+ `parse_prompt_tail` returns a named, tuple-compatible `PromptTail`.
48
+ - Mail-disabled launches no longer touch the filesystem for mail (lanes keep
49
+ their identity and storage materializes lazily on first send); workspace
50
+ resolution runs once per launch; the discovery cache is memoized per
51
+ process; the directory retry baseline is captured only when a codex
52
+ fallback profile is configured; watch sleeps are bounded by the remaining
53
+ deadline; non-once watches dedupe emitted messages and skip unchanged
54
+ inboxes; mail bodies stream with a bounded read.
55
+ - All mail subcommands render prose in human mode (watch keeps its
56
+ documented NDJSON contract); JSON output is byte-unchanged.
57
+
58
+ ### Removed
59
+
60
+ - Dead code from the framer migration and mail rounds: unused safe-prefix
61
+ helpers, the write-only `prompt_framed` field, and unreferenced mail
62
+ helpers; development-history comments replaced with durable behavior
63
+ statements.
9
64
 
10
65
  ## [0.26.0] - 2026-08-01
11
66
 
@@ -862,6 +917,8 @@ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week o
862
917
 
863
918
  - Releases before 0.1.3 predate this changelog.
864
919
 
920
+ [0.28.0]: https://github.com/treygoff24/delegate-agent/compare/v0.27.0...v0.28.0
921
+ [0.27.0]: https://github.com/treygoff24/delegate-agent/compare/v0.26.0...v0.27.0
865
922
  [0.26.0]: https://github.com/treygoff24/delegate-agent/compare/v0.25.0...v0.26.0
866
923
  [0.25.0]: https://github.com/treygoff24/delegate-agent/compare/v0.24.0...v0.25.0
867
924
  [0.24.0]: https://github.com/treygoff24/delegate-agent/compare/v0.23.0...v0.24.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: delegate-agent-cli
3
- Version: 0.26.0
3
+ Version: 0.28.0
4
4
  Summary: A tiny CLI for delegating bounded agent tasks across coding-agent runtimes.
5
5
  Author: Trey Goff
6
6
  License-Expression: MIT
@@ -167,6 +167,8 @@ delegate --json capabilities refresh # refresh the active profile's discovery
167
167
 
168
168
  Discover commands as you go: `delegate <command> --help` prints focused help for any command path, and `delegate --json <command> --help` returns an agent-friendly spec of its usage, arguments, and options. For launch and `dry-run` commands, `--json` and `--isolation` may also appear before inline prompt text begins, for example `delegate codex work --prompt-file task.md --json`. `delegate --json describe` includes a `commands` catalog of the whole surface. Cached `models` and `capabilities` reads launch no child process. `models <engine> --live` performs a one-off probe without updating the cache; rerun `delegate setup` or `delegate capabilities refresh` when ordinary launches should consume newly discovered models or effort levels.
169
169
 
170
+ Codex tracked runs can opt into a one-run quota fallback with `codex.fallbackProfile`; hashed credential namespace is canonical, while default work/personal credential homes also mirror compatible legacy alias keys so existing launchers share blocks. Remapped aliases remain isolated. See [Configuration](docs/configuration.md).
171
+
170
172
  From this development checkout, use `python3 bin/delegate.py ...` instead of an installed `delegate` shim.
171
173
 
172
174
  ### WSL setup notes
@@ -134,6 +134,8 @@ delegate --json capabilities refresh # refresh the active profile's discovery
134
134
 
135
135
  Discover commands as you go: `delegate <command> --help` prints focused help for any command path, and `delegate --json <command> --help` returns an agent-friendly spec of its usage, arguments, and options. For launch and `dry-run` commands, `--json` and `--isolation` may also appear before inline prompt text begins, for example `delegate codex work --prompt-file task.md --json`. `delegate --json describe` includes a `commands` catalog of the whole surface. Cached `models` and `capabilities` reads launch no child process. `models <engine> --live` performs a one-off probe without updating the cache; rerun `delegate setup` or `delegate capabilities refresh` when ordinary launches should consume newly discovered models or effort levels.
136
136
 
137
+ Codex tracked runs can opt into a one-run quota fallback with `codex.fallbackProfile`; hashed credential namespace is canonical, while default work/personal credential homes also mirror compatible legacy alias keys so existing launchers share blocks. Remapped aliases remain isolated. See [Configuration](docs/configuration.md).
138
+
137
139
  From this development checkout, use `python3 bin/delegate.py ...` instead of an installed `delegate` shim.
138
140
 
139
141
  ### WSL setup notes
@@ -7,7 +7,7 @@ This guide covers both human setup and non-interactive setup for agents or CI jo
7
7
  1. Install Delegate from the source repository:
8
8
 
9
9
  ```bash
10
- python3 -m pip install "delegate-agent @ git+https://github.com/treygoff24/delegate-agent.git"
10
+ python3 -m pip install "delegate-agent-cli @ git+https://github.com/treygoff24/delegate-agent.git"
11
11
  ```
12
12
 
13
13
  For a development checkout, prefer:
@@ -1008,12 +1008,12 @@ repo copy or persistent worktree itself.
1008
1008
  Tracked runs return bounded parent-facing output and store local metadata under `.delegate/` in the source workspace.
1009
1009
 
1010
1010
  ```bash
1011
- delegate runs [--active|--running|--stale|--recent] [--harness HARNESS] [--group NAME] [--limit N]
1011
+ delegate runs [--active|--running|--stale|--recent] [--harness HARNESS] [--group NAME] [--limit N] [--structural]
1012
1012
  delegate runs prune [--older-than DAYS] [--dry-run]
1013
1013
  delegate ps [--harness HARNESS] [--group NAME] [--limit N]
1014
1014
  delegate snapshot [--latest HARNESS] [--no-redact] <handle>
1015
1015
  delegate run-output [--latest HARNESS] <handle> [--completion-report] [--stdout] [--stderr] [--tail N] [--max-chars N] [--raw] [--no-redact]
1016
- delegate resume [--engine ENGINE] [--model MODEL] [--reasoning-effort LEVEL] [--timeout SEC] [--dry-run] <handle> [extra instructions...]
1016
+ delegate resume [--engine ENGINE] [--model MODEL] [--reasoning-effort LEVEL] [--fast|--no-fast] [--progress|--no-progress] [--timeout SEC] [--output-schema PATH|--no-output-schema] [--include-dirty] [--persona NAME|--no-persona] [--allow-repo-persona] [--mail-push] [--dry-run] <handle> [extra instructions...]
1017
1017
  delegate wait <handle>... [--latest HARNESS] [--group NAME] [--timeout SEC] [--interval SEC] [--completion-report]
1018
1018
  delegate cancel <handle>...
1019
1019
  ```
@@ -1055,8 +1055,10 @@ creating a Run or writing a prompt record.
1055
1055
  | Include dirty | `includeDirty` | `--include-dirty` | Source and explicit values are creation-only and are dropped for ordinary resume with a note. | Retained only as a drop decision; on a persistent/attached source, explicit `--include-dirty` is rejected because attachment does not create or sync a worktree. |
1056
1056
 
1057
1057
  `delegate runs` defaults to recent runs. `--active` preserves the legacy active view and includes both live `running` runs and `stale` runs. Use `--running` for only live tracked processes and `--stale` for runs recorded as running whose PID is missing or dead. `--active`, `--running`, `--stale`, and `--recent` are mutually exclusive. `--group NAME` filters by launch group and the runs table shows a `group` column when any visible run has one.
1058
+ `--structural` omits content-bearing run fields and emits only identity, lifecycle, model,
1059
+ timestamp, group/mode, and `initiatorRoot` metadata. It is intended for local status collectors.
1058
1060
  `delegate ps` is the shorter first-class form of `delegate runs --active` and
1059
- accepts the same harness, group, and limit selectors.
1061
+ accepts the same harness, group, limit, and structural selectors.
1060
1062
 
1061
1063
  `delegate runs prune` removes old terminal Run records from the workspace Registry so they stop accumulating forever. Only runs whose effective status is terminal (`succeeded`, `failed`, `cancelled`, or `stale` from a dead child) and whose last Registry activity is older than the threshold (default 30 days; override with `--older-than DAYS`) are eligible. Effectively running runs are always skipped, and persistent-worktree runs are skipped unless their worktree is recorded as removed or missing — pruning the record of a live worktree would orphan it from `worktree list`/`show`/`remove`. Pruning deletes the per-Run directory (Snapshot, Manifest, logs, events, Completion Report) and the retained raw-log archive; worktree paths on disk are never touched. `--dry-run` reports what would be removed without changing anything. JSON output uses schema `delegate.runs-prune.v1` with `planned`, `removed`, `skipped` (each entry carries a `reason`), and `errors` sections.
1062
1064
 
@@ -1114,7 +1116,12 @@ Persistent worktree completions also include `branch`, `worktree`, a
1114
1116
  state, changed file count, diff stat, and commits created by the child. When a
1115
1117
  Codex usage-limit fallback fires, the completion payload also includes
1116
1118
  `codexAuthFallback` metadata (reason, the primary and fallback profile names,
1117
- both exit codes, and a redacted primary stderr tail).
1119
+ both exit codes, and a redacted primary stderr tail). The fallback is Codex-only
1120
+ and is enabled only by `codex.fallbackProfile`; Delegate remembers temporary
1121
+ blocks by hashed credential namespace (`CODEX_HOME/auth.json` plus
1122
+ `codex.profile`) as canonical state. Default work/personal credential homes
1123
+ also mirror compatible legacy alias keys so existing launchers share blocks;
1124
+ remapped aliases remain isolated.
1118
1125
 
1119
1126
  Snapshot JSON uses schema `delegate.snapshot.v1` and includes fields such as `alias`, `runId`, `harness`, `status`, `rawStatus`, `effectiveStatus`, `staleReason`, `nextActions`, `cwd`, `executionCwd`, `workspaceRoot`, `assistantText`, `recentEvents`, `warnings`, `exitCode`, reasoning metadata, terminal metadata, and isolation/worktree metadata when applicable. `workspaceRoot` is also exported to the child as `WORKSPACE_ROOT`, so commands can anchor workspace-relative paths after changing directories. Inspection commands do not rewrite a stale run's recorded state; they expose the raw recorded status plus the effective status computed from the current PID check. Run-output and worktree show output include `requestedHandle`, `resolvedHandle`, and `resolutionKind` (`literal`, `latest`, or `latest_model`) when a handle resolves indirectly. For bare harness handles, snapshot, run-output, and wait also report `resolvedRunId`, `resolvedAlias`, `resolvedWorkspace`, `resolvedAge`, and `resolvedAgeSeconds`. Resolutions older than 24 hours add a `bare_handle_stale` warning suggesting `--cwd` or an explicit handle.
1120
1127
 
@@ -336,7 +336,7 @@ Controls local run recording.
336
336
  - `models`: optional map of local aliases to Codex model IDs for `--model` / JSON `model`. Alias keys must not collide with mode names, equal the engine's own name, or start with `-`.
337
337
  - `defaultReasoningEffort`: optional non-empty effort string. When a Codex model resolves (run input or `codex.defaultModel`) and supports the level, Delegate emits a Codex config override; otherwise the run proceeds without reasoning effort and records a warning. An explicit `--reasoning-effort` flag fails closed for unsupported levels, but can target the Codex harness default model when no model is configured.
338
338
  - `profile`: optional Codex CLI config overlay name. It is config-only; JSON run input cannot set it.
339
- - `fallbackProfile`: optional top-level `profiles.definitions` name for one quota-limit retry on tracked Codex runs. The fallback profile must define `env.CODEX_HOME`.
339
+ - `fallbackProfile`: optional top-level `profiles.definitions` name for Codex-only quota fallback. The fallback profile must define `env.CODEX_HOME`. Tracked Codex runs persist temporary usage-limit blocks under `~/.ai-profiles/runtime/failover/`; hashed credential namespace (`CODEX_HOME/auth.json` plus `codex.profile`) is canonical, while default work/personal credential homes also mirror compatible legacy alias keys so existing launchers share blocks. Remapped aliases remain isolated. If both the primary and fallback credential namespaces are blocked, Delegate keeps the primary attempt and does not launch the known-blocked fallback.
340
340
  - `workSandbox`: `read-only`, `workspace-write`, or `danger-full-access` for Codex work mode when full bypass is not enabled.
341
341
  - `ephemeral`: include Codex `--ephemeral` in JSON-streaming runs.
342
342
  - `ignoreUserConfig`: include Codex `--ignore-user-config`.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "delegate-agent-cli"
7
- version = "0.26.0"
7
+ version = "0.28.0"
8
8
  description = "A tiny CLI for delegating bounded agent tasks across coding-agent runtimes."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,5 +1,5 @@
1
1
  """Delegate Agent CLI package."""
2
2
 
3
- VERSION = "0.26.0"
3
+ VERSION = "0.28.0"
4
4
 
5
5
  __all__ = ["VERSION"]
@@ -15,7 +15,6 @@ from delegate_agent import reasoning
15
15
  from delegate_agent.constants import MODE_CALL, MODE_SAFE, MODE_WORK, validate_mode
16
16
  from delegate_agent.errors import DelegateError
17
17
  from delegate_agent.json_types import JsonObject
18
- from delegate_agent.prompt_instructions import SKILL_REVIEW_PREFIX
19
18
  from delegate_agent.prompt_transport import (
20
19
  CURSOR_PROMPT_REDACTION,
21
20
  DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
@@ -108,23 +107,6 @@ def prefix_cursor_safe_prompt(prompt: str) -> str:
108
107
  return _prefix_safe_prompt(prompt, "cursor")
109
108
 
110
109
 
111
- def prefix_kimi_safe_prompt(prompt: str) -> str:
112
- return _prefix_safe_prompt(prompt, "kimi")
113
-
114
-
115
- def prefix_droid_safe_prompt(prompt: str) -> str:
116
- safe_prefix = SAFE_REVIEW_PREFIX_BY_ENGINE["droid"]
117
- if prompt.startswith(safe_prefix):
118
- return prompt
119
- skill_prefix = SKILL_REVIEW_PREFIX
120
- if prompt.startswith(skill_prefix):
121
- insert_at = len(skill_prefix)
122
- if prompt[insert_at:].startswith(safe_prefix):
123
- return prompt
124
- return prompt[:insert_at] + safe_prefix + prompt[insert_at:]
125
- return f"{safe_prefix}{prompt}"
126
-
127
-
128
110
  def _harness_bypass_enabled(config: JsonObject, mode: str, engine: str) -> bool:
129
111
  """Return true only for explicit harness-scoped bypass policy.
130
112
 
@@ -635,6 +635,8 @@ def make_run_context(
635
635
  ),
636
636
  auth_profile=request.auth_profile,
637
637
  fallback_auth_profile=request.fallback_auth_profile,
638
+ codex_failover_identity=request.codex_failover_identity,
639
+ codex_fallback_failover_identity=request.codex_fallback_failover_identity,
638
640
  include_dirty=request.include_dirty,
639
641
  mail_push=request.mail_push,
640
642
  group=request.group,
@@ -675,6 +677,12 @@ def _set_child_root_env(request: Request, source_workspace: ResolvedWorkspace) -
675
677
  request.env_overrides = env
676
678
 
677
679
 
680
+ def _apply_initiator_root(request: Request) -> str | None:
681
+ initiator_root, env = run_metadata.apply_initiator_root_env(request.env_overrides)
682
+ request.env_overrides = env
683
+ return initiator_root
684
+
685
+
678
686
  def _artifact_files(root: Path) -> list[str]:
679
687
  return sorted(str(item) for item in root.rglob("*") if item.is_file() or item.is_symlink())
680
688
 
@@ -783,63 +791,55 @@ def _execute_attached_worktree(
783
791
  workspace_kind=source_workspace.kind,
784
792
  )
785
793
  maybe_run_retention_pass(registry_root, config)
786
- if request.mode == MODE_WORK:
794
+ if request.mode == MODE_WORK and delegate_config.mail_enabled(config):
787
795
  mail.prepare_mail_storage(registry_root)
788
796
  mail.sanitize_inherited_mail_identity(request.env_overrides)
797
+ metadata = {
798
+ "mode": request.mode,
799
+ "model": request.model,
800
+ "modelAlias": request.model_alias,
801
+ "modelResolved": request.model,
802
+ "group": request.group,
803
+ "workflowAgentKey": request.workflow_agent_key,
804
+ "cwd": source_workspace.path,
805
+ "worktreeAttachment": {
806
+ **(iso.attachment or {}),
807
+ "startHeadOid": start_head_oid,
808
+ },
809
+ }
810
+ run_metadata.add_initiator_metadata(
811
+ metadata, run_metadata.resolve_initiator_root(request.env_overrides or {})
812
+ )
789
813
  run_id, alias = run_registry.register_run(
790
814
  registry_root,
791
815
  harness=request.engine,
792
- metadata={
793
- "mode": request.mode,
794
- "model": request.model,
795
- "modelAlias": request.model_alias,
796
- "modelResolved": request.model,
797
- "group": request.group,
798
- "workflowAgentKey": request.workflow_agent_key,
799
- "cwd": source_workspace.path,
800
- "worktreeAttachment": {
801
- **(iso.attachment or {}),
802
- "startHeadOid": start_head_oid,
803
- },
804
- },
816
+ metadata=metadata,
805
817
  )
806
818
  child_env = request.env_overrides or {}
807
819
  if request.mode == MODE_WORK:
808
820
  mail.bind_mail_identity(child_env, run_id, alias)
809
821
  request.env_overrides = child_env
810
- provision: mail.MailPushProvision | None = None
811
- if request.mode == MODE_WORK:
812
- wired_argv, wired_display_argv = mail.wire_work_mail_launch(
813
- request.engine,
814
- execution_request.argv,
815
- execution_request.display_argv,
816
- registry_root,
817
- prompt=request.prompt,
818
- prompt_transport=request.prompt_transport,
819
- stderr=stderr,
820
- isolated_workspace=True,
821
- )
822
- execution_request = dc_replace(
823
- execution_request, argv=wired_argv, display_argv=wired_display_argv
824
- )
825
- if request.mail_push:
826
- provision = mail.provision_mail_push(
827
- request.engine,
828
- execution_request.argv,
829
- execution_request.display_argv,
830
- registry_root,
831
- run_id,
832
- request.env_overrides or {},
833
- profiles.codex_fallback_child_env_overrides(
834
- request.profile_resolution, request.env_overrides or {}
835
- ),
836
- )
837
- if provision.warning is not None:
838
- request.warnings = (*request.warnings, provision.warning)
839
- print(f"delegate mail: WARNING: {provision.warning}", file=stderr)
840
- execution_request = dc_replace(
841
- execution_request, argv=provision.argv, display_argv=provision.display_argv
842
- )
822
+ mail_launch = mail.prepare_work_mail_launch(
823
+ enabled=request.mode == MODE_WORK and delegate_config.mail_enabled(config),
824
+ mail_push=request.mail_push,
825
+ engine=request.engine,
826
+ argv=execution_request.argv,
827
+ display_argv=execution_request.display_argv,
828
+ registry_root=registry_root,
829
+ run_id=run_id,
830
+ env_overrides=request.env_overrides,
831
+ profile_resolution=request.profile_resolution,
832
+ prompt=request.prompt,
833
+ prompt_transport=request.prompt_transport,
834
+ stderr=stderr,
835
+ isolated_workspace=True,
836
+ warnings=request.warnings,
837
+ )
838
+ execution_request = dc_replace(
839
+ execution_request, argv=mail_launch.argv, display_argv=mail_launch.display_argv
840
+ )
841
+ request.warnings = mail_launch.request_warnings
842
+ provision = mail_launch.provision
843
843
  ctx_runner = make_run_context(
844
844
  registry_root,
845
845
  request,
@@ -850,22 +850,10 @@ def _execute_attached_worktree(
850
850
  if provision is not None:
851
851
  ctx_runner = dc_replace(
852
852
  ctx_runner,
853
- env_overrides=(
854
- dict(provision.env)
855
- if provision.warning is not None and provision.env is not None
856
- else ctx_runner.env_overrides
857
- ),
858
- fallback_env_overrides=mail.mail_push_fallback_env_overrides(
859
- provision, ctx_runner.fallback_env_overrides, registry_root, run_id
860
- ),
861
- warnings=tuple(
862
- dict.fromkeys(
863
- (*ctx_runner.warnings, *((provision.warning,) if provision.warning else ()))
864
- )
853
+ **mail_launch.context_updates(
854
+ ctx_runner.env_overrides, ctx_runner.fallback_env_overrides, ctx_runner.warnings
865
855
  ),
866
856
  )
867
- if provision.warning is not None and provision.env is not None:
868
- ctx_runner = dc_replace(ctx_runner, env_overrides=dict(provision.env))
869
857
  attachment = {
870
858
  **(iso.attachment or {}),
871
859
  "startHeadOid": start_head_oid,
@@ -1010,6 +998,7 @@ def execute_request(
1010
998
  stderr: TextIO,
1011
999
  ) -> tuple[int, JsonObject | None]:
1012
1000
  _set_child_root_env(request, source_workspace)
1001
+ initiator_root = _apply_initiator_root(request)
1013
1002
  profiles.strip_mail_identity(request.env_overrides)
1014
1003
  if request.mode == MODE_CALL:
1015
1004
  call_response: tuple[int, JsonObject | None] | None = None
@@ -1037,18 +1026,20 @@ def execute_request(
1037
1026
  workspace_kind=source_workspace.kind,
1038
1027
  )
1039
1028
  maybe_run_retention_pass(registry_root, config)
1029
+ metadata = {
1030
+ "mode": request.mode,
1031
+ "model": request.model,
1032
+ "modelAlias": request.model_alias,
1033
+ "modelResolved": request.model,
1034
+ "group": request.group,
1035
+ "workflowAgentKey": request.workflow_agent_key,
1036
+ "cwd": source_workspace.path,
1037
+ }
1038
+ run_metadata.add_initiator_metadata(metadata, initiator_root)
1040
1039
  run_id, alias = run_registry.register_run(
1041
1040
  registry_root,
1042
1041
  harness=request.engine,
1043
- metadata={
1044
- "mode": request.mode,
1045
- "model": request.model,
1046
- "modelAlias": request.model_alias,
1047
- "modelResolved": request.model,
1048
- "group": request.group,
1049
- "workflowAgentKey": request.workflow_agent_key,
1050
- "cwd": source_workspace.path,
1051
- },
1042
+ metadata=metadata,
1052
1043
  )
1053
1044
  artifact_id = run_id
1054
1045
  ctx_runner = make_run_context(
@@ -1303,25 +1294,27 @@ def execute_request(
1303
1294
  workspace_kind=source_workspace.kind,
1304
1295
  )
1305
1296
  maybe_run_retention_pass(registry_root, config)
1306
- if isolated_request.mode == MODE_WORK:
1297
+ if isolated_request.mode == MODE_WORK and delegate_config.mail_enabled(config):
1307
1298
  mail.prepare_mail_storage(registry_root)
1308
1299
  mail.sanitize_inherited_mail_identity(isolated_request.env_overrides)
1300
+ metadata = {
1301
+ "mode": isolated_request.mode,
1302
+ "model": isolated_request.model,
1303
+ "modelAlias": isolated_request.model_alias,
1304
+ "modelResolved": isolated_request.model,
1305
+ "group": isolated_request.group,
1306
+ "workflowAgentKey": isolated_request.workflow_agent_key,
1307
+ "cwd": (
1308
+ isolated_request.isolation_context.source_workspace
1309
+ if isolated_request.isolation_context is not None
1310
+ else source_workspace.path
1311
+ ),
1312
+ }
1313
+ run_metadata.add_initiator_metadata(metadata, initiator_root)
1309
1314
  run_id, alias = run_registry.register_run(
1310
1315
  registry_root,
1311
1316
  harness=isolated_request.engine,
1312
- metadata={
1313
- "mode": isolated_request.mode,
1314
- "model": isolated_request.model,
1315
- "modelAlias": isolated_request.model_alias,
1316
- "modelResolved": isolated_request.model,
1317
- "group": isolated_request.group,
1318
- "workflowAgentKey": isolated_request.workflow_agent_key,
1319
- "cwd": (
1320
- isolated_request.isolation_context.source_workspace
1321
- if isolated_request.isolation_context is not None
1322
- else source_workspace.path
1323
- ),
1324
- },
1317
+ metadata=metadata,
1325
1318
  )
1326
1319
  child_env = isolated_request.env_overrides or {}
1327
1320
  if isolated_request.mode == MODE_WORK:
@@ -1330,41 +1323,32 @@ def execute_request(
1330
1323
  provision: mail.MailPushProvision | None = None
1331
1324
  mail_push_cleanup_transferred = False
1332
1325
  try:
1333
- if isolated_request.mode == MODE_WORK:
1334
- isolated_request.argv, isolated_request.display_argv = mail.wire_work_mail_launch(
1335
- isolated_request.engine,
1336
- isolated_request.argv,
1337
- isolated_request.display_argv,
1338
- registry_root,
1339
- prompt=isolated_request.prompt,
1340
- prompt_transport=isolated_request.prompt_transport,
1341
- stderr=stderr,
1342
- isolated_workspace=bool(
1343
- isolated_request.isolation_context
1344
- and isolated_request.isolation_context.isolation_lifecycle
1345
- in ("temporary", "persistent", "attached")
1346
- ),
1347
- )
1348
- if isolated_request.mail_push:
1349
- provision = mail.provision_mail_push(
1350
- isolated_request.engine,
1351
- isolated_request.argv,
1352
- isolated_request.display_argv,
1353
- registry_root,
1354
- run_id,
1355
- isolated_request.env_overrides or {},
1356
- profiles.codex_fallback_child_env_overrides(
1357
- isolated_request.profile_resolution,
1358
- isolated_request.env_overrides or {},
1359
- ),
1360
- )
1361
- if provision.warning is not None:
1362
- isolated_request.warnings = (*isolated_request.warnings, provision.warning)
1363
- print(f"delegate mail: WARNING: {provision.warning}", file=stderr)
1364
- isolated_request.argv, isolated_request.display_argv = (
1365
- provision.argv,
1366
- provision.display_argv,
1367
- )
1326
+ mail_launch = mail.prepare_work_mail_launch(
1327
+ enabled=isolated_request.mode == MODE_WORK and delegate_config.mail_enabled(config),
1328
+ mail_push=isolated_request.mail_push,
1329
+ engine=isolated_request.engine,
1330
+ argv=isolated_request.argv,
1331
+ display_argv=isolated_request.display_argv,
1332
+ registry_root=registry_root,
1333
+ run_id=run_id,
1334
+ env_overrides=isolated_request.env_overrides,
1335
+ profile_resolution=isolated_request.profile_resolution,
1336
+ prompt=isolated_request.prompt,
1337
+ prompt_transport=isolated_request.prompt_transport,
1338
+ stderr=stderr,
1339
+ isolated_workspace=bool(
1340
+ isolated_request.isolation_context
1341
+ and isolated_request.isolation_context.isolation_lifecycle
1342
+ in ("temporary", "persistent", "attached")
1343
+ ),
1344
+ warnings=isolated_request.warnings,
1345
+ )
1346
+ isolated_request.argv, isolated_request.display_argv = (
1347
+ mail_launch.argv,
1348
+ mail_launch.display_argv,
1349
+ )
1350
+ isolated_request.warnings = mail_launch.request_warnings
1351
+ provision = mail_launch.provision
1368
1352
  ctx_runner = make_run_context(
1369
1353
  registry_root,
1370
1354
  isolated_request,
@@ -1375,25 +1359,12 @@ def execute_request(
1375
1359
  if provision is not None:
1376
1360
  ctx_runner = dc_replace(
1377
1361
  ctx_runner,
1378
- env_overrides=(
1379
- dict(provision.env)
1380
- if provision.warning is not None and provision.env is not None
1381
- else ctx_runner.env_overrides
1382
- ),
1383
- fallback_env_overrides=mail.mail_push_fallback_env_overrides(
1384
- provision, ctx_runner.fallback_env_overrides, registry_root, run_id
1385
- ),
1386
- warnings=tuple(
1387
- dict.fromkeys(
1388
- (
1389
- *ctx_runner.warnings,
1390
- *((provision.warning,) if provision.warning else ()),
1391
- )
1392
- )
1362
+ **mail_launch.context_updates(
1363
+ ctx_runner.env_overrides,
1364
+ ctx_runner.fallback_env_overrides,
1365
+ ctx_runner.warnings,
1393
1366
  ),
1394
1367
  )
1395
- if provision.warning is not None and provision.env is not None:
1396
- ctx_runner = dc_replace(ctx_runner, env_overrides=dict(provision.env))
1397
1368
  # Evaluate every argument expression BEFORE marking ownership
1398
1369
  # transferred: a raise inside an argument (public_argv below) would
1399
1370
  # otherwise skip both the CLI cleanup and the runner's guard.
@@ -1543,6 +1514,7 @@ def main(
1543
1514
  try:
1544
1515
  parsed = parse_cli(argv)
1545
1516
  global_options = parsed.global_options
1517
+ workspace: ResolvedWorkspace | None = None
1546
1518
  json_mode = global_options.json_mode
1547
1519
  profile_guard.enforce_profile_guard(parsed, stderr=stderr)
1548
1520
  if parsed.subcommand == "help":
@@ -1581,16 +1553,18 @@ def main(
1581
1553
  "call mode does not use --cwd.",
1582
1554
  )
1583
1555
  if global_options.group is not None:
1584
- config_workspace = workspace_path_for_config(global_options.cwd)
1556
+ workspace = resolve_workspace(global_options.cwd)
1557
+ config_workspace = Path(workspace.path)
1585
1558
  else:
1586
1559
  config_workspace = None
1587
1560
  else:
1588
- config_workspace = workspace_path_for_config(global_options.cwd)
1561
+ workspace = resolve_workspace(global_options.cwd)
1562
+ config_workspace = Path(workspace.path)
1589
1563
  config, source = load_config(workspace=config_workspace)
1590
1564
  validate_config(config)
1591
1565
 
1592
1566
  if parsed.subcommand == "personas":
1593
- workspace = resolve_workspace(global_options.cwd)
1567
+ workspace = workspace or resolve_workspace(global_options.cwd)
1594
1568
  return emit_personas(workspace, json_mode=global_options.json_mode, stdout=stdout)
1595
1569
 
1596
1570
  discovery_profile: profiles.ProfileResolution | None = None
@@ -1641,7 +1615,7 @@ def main(
1641
1615
  mail_workspace = mail.resolve_mail_workspace(global_options.cwd)
1642
1616
  workspace = resolve_workspace(str(mail_workspace))
1643
1617
  else:
1644
- workspace = resolve_workspace(global_options.cwd)
1618
+ workspace = workspace or resolve_workspace(global_options.cwd)
1645
1619
 
1646
1620
  if parsed.subcommand == "capabilities":
1647
1621
  command = parsed.capabilities
@@ -1714,7 +1688,7 @@ def main(
1714
1688
  # through the normal request build and execution path.
1715
1689
  parsed = resume_plan.parsed
1716
1690
  global_options = parsed.global_options
1717
- request = request_from_parsed(parsed, config, stdin, stderr)
1691
+ request = request_from_parsed(parsed, config, stdin, stderr, workspace=workspace)
1718
1692
  if resume_plan is not None:
1719
1693
  request = resume_command.apply_resume_to_request(request, resume_plan)
1720
1694
  if request.dry_run: