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.
- delegate_agent_cli-0.32.0/CHANGELOG.md +2610 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/CONTRIBUTING.md +8 -7
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/MANIFEST.in +1 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/PKG-INFO +89 -26
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/README.md +84 -25
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/bin/delegate-profile-shim +134 -7
- delegate_agent_cli-0.32.0/bin/delegate.py +31 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/config.example.json +21 -2
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/agent-setup.md +13 -4
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/cli-reference.md +886 -170
- delegate_agent_cli-0.32.0/docs/configuration.md +1220 -0
- delegate_agent_cli-0.32.0/docs/delegate-workflows.md +784 -0
- delegate_agent_cli-0.32.0/docs/development.md +104 -0
- delegate_agent_cli-0.32.0/docs/live-runtime.md +158 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/publishing-checklist.md +30 -8
- delegate_agent_cli-0.32.0/docs/security-model.md +806 -0
- delegate_agent_cli-0.32.0/docs/troubleshooting.md +1040 -0
- delegate_agent_cli-0.32.0/docs/worktrees.md +573 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/pyproject.toml +10 -1
- delegate_agent_cli-0.32.0/src/delegate_agent/__init__.py +24 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/account_binding.py +88 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/argv_builders.py +283 -81
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/argv_utils.py +2 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/auth_health.py +295 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/auto_resume.py +227 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/bundled_models.py +13 -9
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/capability_commands.py +91 -4
- delegate_agent_cli-0.32.0/src/delegate_agent/child_failures.py +189 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/cli.py +1062 -470
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/cli_parser.py +1233 -271
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/command_help.py +990 -290
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/config.py +494 -23
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/constants.py +55 -1
- delegate_agent_cli-0.32.0/src/delegate_agent/degraded.py +450 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/describe_payload.py +313 -209
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/errors.py +14 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/failover_state.py +10 -3
- delegate_agent_cli-0.32.0/src/delegate_agent/followup_command.py +543 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/harness_discovery.py +349 -60
- delegate_agent_cli-0.32.0/src/delegate_agent/harness_enabled.py +120 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/harness_events.py +2568 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/inspection_commands.py +410 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/isolation.py +73 -1
- delegate_agent_cli-0.32.0/src/delegate_agent/lane_health.py +705 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/lane_slice.py +156 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/mail.py +324 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/mail_core.py +186 -72
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/mail_push.py +46 -12
- delegate_agent_cli-0.32.0/src/delegate_agent/model_discovery.py +770 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/notify.py +237 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/outcome.py +279 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/outside_cwd_changes.py +143 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/pending_tool.py +80 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/private_io.py +193 -38
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profile_guard.py +6 -8
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profiles.py +134 -22
- delegate_agent_cli-0.32.0/src/delegate_agent/prompt_instructions.py +84 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/prompt_transport.py +17 -4
- delegate_agent_cli-0.32.0/src/delegate_agent/provider_errors.py +816 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/reasoning.py +44 -25
- delegate_agent_cli-0.32.0/src/delegate_agent/record_io.py +270 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/redaction.py +88 -3
- delegate_agent_cli-0.32.0/src/delegate_agent/registry_roster.py +279 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/rendering.py +156 -4
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/request_build.py +1577 -454
- delegate_agent_cli-0.32.0/src/delegate_agent/request_models.py +443 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/resume_command.py +152 -66
- delegate_agent_cli-0.32.0/src/delegate_agent/retention.py +671 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/run_context.py +132 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_metadata.py +78 -1
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_output_commands.py +154 -5
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/run_registry.py +571 -173
- delegate_agent_cli-0.32.0/src/delegate_agent/run_scratch.py +554 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/run_status.py +585 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/runner.py +6725 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/safe_workspace.py +427 -30
- delegate_agent_cli-0.32.0/src/delegate_agent/sandbox_bwrap.py +711 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/seatbelt.py +61 -2
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/snapshot_view.py +88 -101
- delegate_agent_cli-0.32.0/src/delegate_agent/stall_watchdog.py +1244 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/stream_capture.py +267 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/structured_output.py +93 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/terminal_states.py +74 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/usage_record.py +67 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/wait_cancel_commands.py +1308 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflow_attempts.py +271 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflow_identity.py +133 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflow_pinning.py +1431 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/__init__.py +12 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/commands.py +2047 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/registry.py +449 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/runtime.py +6997 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/schema.py +401 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/script.py +347 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/stage_guard.py +92 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workflows/status_reasons.py +163 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/workspace_spec.py +636 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_commands.py +72 -15
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_execution.py +405 -115
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_gc.py +934 -61
- delegate_agent_cli-0.32.0/src/delegate_agent/worktree_mgmt.py +1582 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/worktree_procs.py +234 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/worktree_records.py +144 -5
- delegate_agent_cli-0.32.0/src/delegate_agent/worktree_remove.py +868 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/worktree_salvage.py +224 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/worktree_summary.py +406 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/write_guard.py +727 -0
- delegate_agent_cli-0.32.0/src/delegate_agent/write_guard_launch.py +383 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/PKG-INFO +89 -26
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +146 -0
- delegate_agent_cli-0.32.0/src/delegate_agent_cli.egg-info/requires.txt +9 -0
- delegate_agent_cli-0.32.0/tests/test_acceptance_toolchain.py +175 -0
- delegate_agent_cli-0.32.0/tests/test_account_binding.py +99 -0
- delegate_agent_cli-0.32.0/tests/test_appendix_failure_strings.py +141 -0
- delegate_agent_cli-0.32.0/tests/test_auth_health.py +366 -0
- delegate_agent_cli-0.32.0/tests/test_auto_resume.py +457 -0
- delegate_agent_cli-0.32.0/tests/test_bundled_models_lane_r.py +30 -0
- delegate_agent_cli-0.32.0/tests/test_c5_validation.py +502 -0
- delegate_agent_cli-0.32.0/tests/test_call_capture_contract.py +44 -0
- delegate_agent_cli-0.32.0/tests/test_cancel_terminal_override.py +395 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_capability_commands.py +197 -79
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_child_failures.py +38 -12
- delegate_agent_cli-0.32.0/tests/test_cli_ergonomics.py +308 -0
- delegate_agent_cli-0.32.0/tests/test_cli_simplification.py +230 -0
- delegate_agent_cli-0.32.0/tests/test_cli_surface_fixes.py +108 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_codex_pure_sandbox.py +76 -5
- delegate_agent_cli-0.32.0/tests/test_codex_scratch.py +759 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_codex_thread_resilience.py +20 -13
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_command_help.py +151 -93
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_config_commands.py +202 -22
- delegate_agent_cli-0.32.0/tests/test_cross_registry_lookup.py +310 -0
- delegate_agent_cli-0.32.0/tests/test_degraded.py +585 -0
- delegate_agent_cli-0.32.0/tests/test_degraded_runs.py +787 -0
- delegate_agent_cli-0.32.0/tests/test_delegate_audit_shim.py +33 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_help_cli.py +169 -201
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_isolation.py +25 -16
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_parser.py +861 -710
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_delegate_validation.py +710 -141
- delegate_agent_cli-0.32.0/tests/test_describe_models_binary.py +123 -0
- delegate_agent_cli-0.32.0/tests/test_describe_workflow_dsl.py +93 -0
- delegate_agent_cli-0.32.0/tests/test_devin_bounded_output.py +181 -0
- delegate_agent_cli-0.32.0/tests/test_devin_read_only_behavior.py +142 -0
- delegate_agent_cli-0.32.0/tests/test_discovery_contracts.py +191 -0
- delegate_agent_cli-0.32.0/tests/test_docs_parser_conformance.py +497 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_end_to_end_tracking.py +46 -12
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_engine_argv.py +796 -356
- delegate_agent_cli-0.32.0/tests/test_engine_universe.py +35 -0
- delegate_agent_cli-0.32.0/tests/test_execution_argv_and_prompt.py +2295 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_dry_run.py +89 -84
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_failure_cleanup.py +83 -142
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_preflight.py +56 -25
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_execution_worktree_run.py +551 -147
- delegate_agent_cli-0.32.0/tests/test_failover_state.py +173 -0
- delegate_agent_cli-0.32.0/tests/test_followup_after_retry_e2e.py +368 -0
- delegate_agent_cli-0.32.0/tests/test_followup_capture.py +330 -0
- delegate_agent_cli-0.32.0/tests/test_followup_parser.py +124 -0
- delegate_agent_cli-0.32.0/tests/test_followup_refusals.py +340 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_harness_discovery.py +379 -50
- delegate_agent_cli-0.32.0/tests/test_harness_events.py +3038 -0
- delegate_agent_cli-0.32.0/tests/test_harness_json_limits.py +34 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_inspection_commands.py +142 -60
- delegate_agent_cli-0.32.0/tests/test_isolation_plans.py +95 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_kimi_commands.py +36 -10
- delegate_agent_cli-0.32.0/tests/test_lane_a_transport.py +964 -0
- delegate_agent_cli-0.32.0/tests/test_lane_b_lifecycle.py +194 -0
- delegate_agent_cli-0.32.0/tests/test_lane_health.py +733 -0
- delegate_agent_cli-0.32.0/tests/test_lane_known_bad.py +274 -0
- delegate_agent_cli-0.32.0/tests/test_lane_m_mail_defaults.py +220 -0
- delegate_agent_cli-0.32.0/tests/test_lane_r_public_surface.py +86 -0
- delegate_agent_cli-0.32.0/tests/test_lane_s_structured_retry.py +178 -0
- delegate_agent_cli-0.32.0/tests/test_lane_slice.py +139 -0
- delegate_agent_cli-0.32.0/tests/test_launch_input_parity.py +582 -0
- delegate_agent_cli-0.32.0/tests/test_launch_mapping.py +368 -0
- delegate_agent_cli-0.32.0/tests/test_launch_model_resolution.py +276 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_bounds.py +41 -13
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_contract.py +31 -1
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_delivery.py +25 -16
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_eligibility.py +30 -11
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_framing.py +2 -27
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_gating.py +175 -54
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_identity.py +5 -6
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_parser.py +10 -9
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_prune.py +0 -12
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push.py +30 -72
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_adapters.py +37 -13
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_batch.py +4 -6
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_cursor.py +25 -5
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_gating.py +3 -3
- delegate_agent_cli-0.32.0/tests/test_mail_push_inheritance.py +120 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_push_seams.py +53 -24
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_reply.py +2 -4
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_resolution.py +27 -21
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_rules.py +9 -4
- delegate_agent_cli-0.32.0/tests/test_mail_tempdir.py +75 -0
- delegate_agent_cli-0.32.0/tests/test_mail_unread_steering.py +267 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_discovery.py +208 -224
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_selection_wave1a.py +36 -147
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_model_selection_wave1b.py +147 -172
- delegate_agent_cli-0.32.0/tests/test_nested_workflow_threads.py +249 -0
- delegate_agent_cli-0.32.0/tests/test_no_page_ask.py +75 -0
- delegate_agent_cli-0.32.0/tests/test_notify.py +486 -0
- delegate_agent_cli-0.32.0/tests/test_omp_output_capture.py +332 -0
- delegate_agent_cli-0.32.0/tests/test_omp_provider_pin.py +959 -0
- delegate_agent_cli-0.32.0/tests/test_omp_read_only_behavior.py +213 -0
- delegate_agent_cli-0.32.0/tests/test_omp_tool_update_compaction.py +243 -0
- delegate_agent_cli-0.32.0/tests/test_outcome_contract.py +718 -0
- delegate_agent_cli-0.32.0/tests/test_output_cap_off.py +236 -0
- delegate_agent_cli-0.32.0/tests/test_outside_cwd_changes.py +119 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_packaging.py +10 -3
- delegate_agent_cli-0.32.0/tests/test_partial_output_recovery.py +547 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_capability.py +23 -59
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_claude.py +11 -17
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_contract.py +17 -1
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_framer.py +63 -77
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_opencode.py +3 -13
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_parser.py +28 -21
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_records.py +16 -15
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_resolution.py +49 -116
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_size_guard.py +33 -12
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_persona_workflow.py +105 -91
- delegate_agent_cli-0.32.0/tests/test_private_directory_publish.py +75 -0
- delegate_agent_cli-0.32.0/tests/test_private_io_bounded.py +177 -0
- delegate_agent_cli-0.32.0/tests/test_private_io_dir_race.py +57 -0
- delegate_agent_cli-0.32.0/tests/test_proc_harness.py +204 -0
- delegate_agent_cli-0.32.0/tests/test_process_guard.py +149 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_profiles.py +159 -45
- delegate_agent_cli-0.32.0/tests/test_provider_error_docs.py +95 -0
- delegate_agent_cli-0.32.0/tests/test_provider_error_records.py +395 -0
- delegate_agent_cli-0.32.0/tests/test_provider_errors.py +265 -0
- delegate_agent_cli-0.32.0/tests/test_provider_outcomes.py +420 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_pure_call.py +163 -69
- delegate_agent_cli-0.32.0/tests/test_python_version_guard.py +253 -0
- delegate_agent_cli-0.32.0/tests/test_real_binary_contracts.py +499 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_reasoning_capabilities.py +139 -193
- delegate_agent_cli-0.32.0/tests/test_registry_contention.py +279 -0
- delegate_agent_cli-0.32.0/tests/test_registry_lock_guard.py +146 -0
- delegate_agent_cli-0.32.0/tests/test_registry_roster.py +183 -0
- delegate_agent_cli-0.32.0/tests/test_resumable_default.py +538 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_attachment.py +92 -75
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_capture.py +47 -2
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_inheritance.py +279 -29
- delegate_agent_cli-0.32.0/tests/test_resume_parser.py +85 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_projections.py +1 -1
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_refusals.py +8 -1
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_size_guard.py +13 -11
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_stale.py +25 -19
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_resume_trust.py +83 -27
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_retention.py +381 -51
- delegate_agent_cli-0.32.0/tests/test_run_listing_cost.py +98 -0
- delegate_agent_cli-0.32.0/tests/test_run_record_imports.py +46 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_run_registry.py +364 -39
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_runner_capture.py +2450 -276
- delegate_agent_cli-0.32.0/tests/test_runs_deadline.py +191 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_safe_workspace_isolation.py +423 -106
- delegate_agent_cli-0.32.0/tests/test_sandbox_bwrap.py +1492 -0
- delegate_agent_cli-0.32.0/tests/test_scratch_reclaim.py +943 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_setup_commands.py +15 -13
- delegate_agent_cli-0.32.0/tests/test_simplification_integration.py +296 -0
- delegate_agent_cli-0.32.0/tests/test_single_run_record.py +236 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_slash_passthrough.py +28 -16
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_redaction.py +87 -6
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_rendering.py +29 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_run_output.py +367 -26
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_snapshot_view.py +109 -0
- delegate_agent_cli-0.32.0/tests/test_stall_watchdog.py +1454 -0
- delegate_agent_cli-0.32.0/tests/test_stall_watchdog_cursor.py +93 -0
- delegate_agent_cli-0.32.0/tests/test_stall_watchdog_runner.py +196 -0
- delegate_agent_cli-0.32.0/tests/test_status_truth.py +340 -0
- delegate_agent_cli-0.32.0/tests/test_stream_usage_ingest.py +205 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_structured_output.py +72 -0
- delegate_agent_cli-0.32.0/tests/test_terminal_states.py +27 -0
- delegate_agent_cli-0.32.0/tests/test_test_environment.py +44 -0
- delegate_agent_cli-0.32.0/tests/test_test_runner.py +83 -0
- delegate_agent_cli-0.32.0/tests/test_tracked_output_bounds.py +372 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_tracked_timeout.py +38 -81
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_utility_modules.py +37 -21
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wait_cancel_commands.py +750 -114
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wave4_launch_features.py +212 -29
- delegate_agent_cli-0.32.0/tests/test_workflow_attempts.py +566 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_check_keying.py +121 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_commands.py +8068 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_failure_policy.py +233 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_gate_binding.py +300 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_journal_reader.py +322 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_jsonl_cli.py +74 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_key_stability.py +68 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_keyed_steps.py +1125 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_pinning.py +1062 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_profile_identity.py +234 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_provider_stage.py +341 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_repin.py +1264 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_retry_outcomes.py +1490 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_schema.py +339 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_session_fallback.py +413 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_simplification.py +222 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_status_reasons.py +491 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_watchdog.py +541 -0
- delegate_agent_cli-0.32.0/tests/test_workflow_watchdog_unit.py +889 -0
- delegate_agent_cli-0.32.0/tests/test_workspace_spec.py +1489 -0
- delegate_agent_cli-0.32.0/tests/test_worktree_effective_dirt.py +502 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_list_show.py +39 -61
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_prune_gc.py +640 -143
- delegate_agent_cli-0.32.0/tests/test_worktree_reap_orphan.py +722 -0
- delegate_agent_cli-0.32.0/tests/test_worktree_record_bundle.py +95 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_worktree_remove.py +568 -75
- delegate_agent_cli-0.32.0/tests/test_worktree_retirement.py +800 -0
- delegate_agent_cli-0.32.0/tests/test_worktree_safety_policy.py +235 -0
- delegate_agent_cli-0.32.0/tests/test_worktree_salvage.py +416 -0
- delegate_agent_cli-0.32.0/tests/test_worktree_symlink_placeholders.py +191 -0
- delegate_agent_cli-0.32.0/tests/test_write_guard.py +1543 -0
- delegate_agent_cli-0.32.0/tests/test_write_guard_e2e.py +333 -0
- delegate_agent_cli-0.32.0/tests/test_write_guard_live.py +499 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_wsl_guardrails.py +8 -8
- delegate_agent_cli-0.29.1/CHANGELOG.md +0 -1030
- delegate_agent_cli-0.29.1/bin/delegate.py +0 -15
- delegate_agent_cli-0.29.1/docs/configuration.md +0 -749
- delegate_agent_cli-0.29.1/docs/delegate-workflows.md +0 -241
- delegate_agent_cli-0.29.1/docs/development.md +0 -70
- delegate_agent_cli-0.29.1/docs/live-runtime.md +0 -64
- delegate_agent_cli-0.29.1/docs/security-model.md +0 -407
- delegate_agent_cli-0.29.1/docs/troubleshooting.md +0 -528
- delegate_agent_cli-0.29.1/docs/worktrees.md +0 -262
- delegate_agent_cli-0.29.1/src/delegate_agent/__init__.py +0 -5
- delegate_agent_cli-0.29.1/src/delegate_agent/child_failures.py +0 -93
- delegate_agent_cli-0.29.1/src/delegate_agent/harness_events.py +0 -1188
- delegate_agent_cli-0.29.1/src/delegate_agent/inspection_commands.py +0 -187
- delegate_agent_cli-0.29.1/src/delegate_agent/mail.py +0 -199
- delegate_agent_cli-0.29.1/src/delegate_agent/model_discovery.py +0 -370
- delegate_agent_cli-0.29.1/src/delegate_agent/prompt_instructions.py +0 -58
- delegate_agent_cli-0.29.1/src/delegate_agent/request_models.py +0 -326
- delegate_agent_cli-0.29.1/src/delegate_agent/retention.py +0 -366
- delegate_agent_cli-0.29.1/src/delegate_agent/run_status.py +0 -317
- delegate_agent_cli-0.29.1/src/delegate_agent/runner.py +0 -3810
- delegate_agent_cli-0.29.1/src/delegate_agent/wait_cancel_commands.py +0 -652
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/__init__.py +0 -5
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/commands.py +0 -743
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/registry.py +0 -252
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/runtime.py +0 -1669
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/schema.py +0 -177
- delegate_agent_cli-0.29.1/src/delegate_agent/workflows/script.py +0 -203
- delegate_agent_cli-0.29.1/src/delegate_agent/worktree_mgmt.py +0 -790
- delegate_agent_cli-0.29.1/src/delegate_agent/worktree_remove.py +0 -586
- delegate_agent_cli-0.29.1/src/delegate_agent/worktree_summary.py +0 -241
- delegate_agent_cli-0.29.1/src/delegate_agent_cli.egg-info/requires.txt +0 -5
- delegate_agent_cli-0.29.1/tests/test_execution_argv_and_prompt.py +0 -1344
- delegate_agent_cli-0.29.1/tests/test_failover_state.py +0 -105
- delegate_agent_cli-0.29.1/tests/test_harness_events.py +0 -1667
- delegate_agent_cli-0.29.1/tests/test_omp_read_only_behavior.py +0 -88
- delegate_agent_cli-0.29.1/tests/test_resume_parser.py +0 -54
- delegate_agent_cli-0.29.1/tests/test_tracked_output_bounds.py +0 -167
- delegate_agent_cli-0.29.1/tests/test_workflow_commands.py +0 -2811
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/LICENSE +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/SECURITY.md +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/docs/assets/delegate-agent-header.png +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.claude.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.codex.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.cursor.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.droid.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.grok.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.judge.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/examples/task.kimi.json +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/setup.cfg +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/archived_logs.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/command_errors.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/config_commands.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/git_utils.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/json_types.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/log_output.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/personas.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/profile_commands.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/setup_commands.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent/wsl.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_call_text_fixtures.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_child_root_env.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_launch_error_hints.py +0 -0
- {delegate_agent_cli-0.29.1 → delegate_agent_cli-0.32.0}/tests/test_mail_io.py +0 -0
- {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
|