delegate-agent-cli 0.13.1__tar.gz → 0.14.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.13.1 → delegate_agent_cli-0.14.0}/CHANGELOG.md +47 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/PKG-INFO +13 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/README.md +12 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/cli-reference.md +80 -22
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/security-model.md +29 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/worktrees.md +4 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/pyproject.toml +1 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/__init__.py +1 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/argv_builders.py +76 -5
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/argv_utils.py +9 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/cli.py +40 -7
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/cli_parser.py +81 -3
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/command_help.py +124 -44
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/constants.py +25 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/describe_payload.py +100 -6
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/git_utils.py +1 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/harness_events.py +28 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/isolation.py +1 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/json_types.py +2 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/profiles.py +67 -9
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/reasoning.py +3 -3
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/request_build.py +124 -28
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/request_models.py +6 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/runner.py +421 -29
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/safe_workspace.py +85 -19
- delegate_agent_cli-0.14.0/src/delegate_agent/seatbelt.py +170 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/snapshot_view.py +0 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/wait_cancel_commands.py +50 -23
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/commands.py +131 -34
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/registry.py +77 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/runtime.py +79 -40
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/schema.py +34 -4
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/script.py +3 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_execution.py +9 -48
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_summary.py +1 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/PKG-INFO +13 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +3 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_capability_commands.py +17 -0
- delegate_agent_cli-0.14.0/tests/test_codex_pure_sandbox.py +511 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_command_help.py +85 -11
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_delegate_help_cli.py +72 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_delegate_isolation.py +3 -3
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_delegate_parser.py +144 -20
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_delegate_validation.py +0 -11
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_end_to_end_tracking.py +6 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_engine_argv.py +3 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_execution_argv_and_prompt.py +10 -4
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_execution_dry_run.py +0 -11
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_execution_worktree_failure_cleanup.py +1 -12
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_execution_worktree_preflight.py +0 -4
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_execution_worktree_run.py +0 -8
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_model_discovery.py +2 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_model_selection_wave1a.py +1 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_model_selection_wave1b.py +3 -3
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_profiles.py +64 -0
- delegate_agent_cli-0.14.0/tests/test_pure_call.py +570 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_retention.py +0 -3
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_run_registry.py +0 -2
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_runner_capture.py +0 -8
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_safe_workspace_isolation.py +143 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_wait_cancel_commands.py +130 -59
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_workflow_commands.py +887 -19
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_worktree_list_show.py +0 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_worktree_prune_gc.py +0 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_worktree_remove.py +0 -1
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/CONTRIBUTING.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/LICENSE +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/MANIFEST.in +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/SECURITY.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/bin/delegate-profile-shim +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/bin/delegate.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/config.example.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/agent-setup.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/assets/delegate-agent-header.png +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/configuration.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/development.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/live-runtime.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/publishing-checklist.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/docs/troubleshooting.md +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.claude.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.codex.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.cursor.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.droid.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.grok.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/examples/task.judge.json +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/setup.cfg +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/archived_logs.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/bundled_models.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/capability_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/command_errors.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/config.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/config_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/errors.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/inspection_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/log_output.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/model_discovery.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/private_io.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/profile_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/profile_guard.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/prompt_instructions.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/prompt_transport.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/redaction.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/rendering.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/retention.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/run_metadata.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/run_output_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/run_registry.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/run_status.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/workflows/__init__.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_gc.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_mgmt.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_records.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/worktree_remove.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent/wsl.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/requires.txt +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_config_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_harness_events.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_inspection_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_kimi_commands.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_packaging.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_reasoning_capabilities.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_slash_passthrough.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_snapshot_redaction.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_snapshot_rendering.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_snapshot_run_output.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_snapshot_view.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_utility_modules.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_wave4_launch_features.py +0 -0
- {delegate_agent_cli-0.13.1 → delegate_agent_cli-0.14.0}/tests/test_wsl_guardrails.py +0 -0
|
@@ -5,6 +5,52 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.14.0] - 2026-07-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `workflow result --field` for extracting a single field from a workflow
|
|
13
|
+
result, reliable latest-workflow selection, immutable creation ordering,
|
|
14
|
+
dry-run visibility, and orphan detection (PR #14).
|
|
15
|
+
- Schema validation for `agent()` results supports `minLength` and
|
|
16
|
+
`minItems`, including in retries and dry-run placeholders (PR #14).
|
|
17
|
+
- Grouped work runs sharing one non-isolated workspace now emit a warning
|
|
18
|
+
with guidance for commit boundaries and persistent worktrees (PR #13).
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Focused call help (`delegate <engine> call --help`) now reflects
|
|
23
|
+
call-mode option boundaries and documents the grouped-call tracking
|
|
24
|
+
exception (`--cwd` accepted only with `--group`); explicit `agent` input
|
|
25
|
+
is rejected on engines that do not support it (PR #13).
|
|
26
|
+
- Overview, dry-run, agent-help, README, CLI reference, and worktree docs
|
|
27
|
+
corrected from user feedback (PR #13).
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Structured Codex workflows consume the child-authored completion report
|
|
32
|
+
(including on resume) and fail closed when it is missing; workflow resume
|
|
33
|
+
transitions atomically to `starting`, hides stale results, rolls back
|
|
34
|
+
failed launches, and releases locks on preparation errors (PR #14).
|
|
35
|
+
- Safe isolation re-roots exact source-workspace paths while preserving
|
|
36
|
+
slash-command payloads verbatim (PR #14).
|
|
37
|
+
- `wait`: a run matched by both `--latest HARNESS` and `--group NAME`
|
|
38
|
+
was emitted twice in the resolved-target list; it now appears once, with
|
|
39
|
+
first-selection precedence and ordering preserved.
|
|
40
|
+
- `git_root_for` degrades any `OSError` from the git probe (not just
|
|
41
|
+
`FileNotFoundError`) to the non-git fallback, so e.g. a `PermissionError`
|
|
42
|
+
spawning git no longer crashes workspace resolution.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- Internal cleanup pass across `src/` and `tests/`: removed dead code (unused
|
|
47
|
+
protocol types, private helpers, stale fixtures), collapsed redundant
|
|
48
|
+
exception tuples into their `OSError` base, replaced a hand-rolled
|
|
49
|
+
path-containment helper with `Path.is_relative_to`, and stripped stale
|
|
50
|
+
review-artifact comments. Behavior-preserving; the workflow supervisor's
|
|
51
|
+
broad exception boundary around child-model output is now explicitly
|
|
52
|
+
commented and regression-tested.
|
|
53
|
+
|
|
8
54
|
## [0.13.1] - 2026-07-09
|
|
9
55
|
|
|
10
56
|
### Added
|
|
@@ -304,6 +350,7 @@ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week o
|
|
|
304
350
|
|
|
305
351
|
- Releases before 0.1.3 predate this changelog.
|
|
306
352
|
|
|
353
|
+
[0.14.0]: https://github.com/treygoff24/delegate-agent/compare/v0.13.1...v0.14.0
|
|
307
354
|
[0.13.1]: https://github.com/treygoff24/delegate-agent/compare/v0.13.0...v0.13.1
|
|
308
355
|
[0.13.0]: https://github.com/treygoff24/delegate-agent/compare/v0.12.0...v0.13.0
|
|
309
356
|
[0.12.0]: https://github.com/treygoff24/delegate-agent/compare/v0.11.0...v0.12.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: delegate-agent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: A tiny CLI for delegating bounded agent tasks to Cursor, Droid, OpenAI Codex, Claude Code, Grok Build, or Kimi Code runtimes.
|
|
5
5
|
Author: Trey Goff
|
|
6
6
|
License-Expression: MIT
|
|
@@ -221,8 +221,17 @@ run, use stateless `call` mode:
|
|
|
221
221
|
|
|
222
222
|
```bash
|
|
223
223
|
delegate --json codex call "Summarize this context in three bullets."
|
|
224
|
+
delegate --json claude call --pure --timeout 60 --output-schema result.schema.json < prompt.txt
|
|
224
225
|
```
|
|
225
226
|
|
|
227
|
+
`call --pure` is a hostile-input completion boundary available on Claude only.
|
|
228
|
+
It uses an empty temporary cwd, an allowlisted child environment, no Delegate
|
|
229
|
+
prompt framing, and no session persistence or tools according to the engine
|
|
230
|
+
capability contract. Claude receives the prompt only on stdin and is
|
|
231
|
+
schema-capable via `--output-schema`; `delegate --json describe` reports
|
|
232
|
+
`pureCall`, `structuredOutput`, `noSessionPersistence`, `usageEvents`, and
|
|
233
|
+
`promptStdin` per engine. `--timeout SECONDS` applies to every call-mode engine.
|
|
234
|
+
|
|
226
235
|
For multi-step fan-out or gated review flows, use Delegate Workflows. A workflow
|
|
227
236
|
is a Python script that launches normal Delegate child runs, journals progress,
|
|
228
237
|
can pause on approval gates, and can resume from cached child results:
|
|
@@ -294,6 +303,9 @@ cancelled, and `124` on timeout. `cancel` signals the run's process group
|
|
|
294
303
|
start-identity check against PID reuse; a cancelled run reports `cancelled`
|
|
295
304
|
rather than a false success. Tag a batch of launches with `--group NAME` and
|
|
296
305
|
`wait`, `runs`, and the worktree commands can select the whole group at once.
|
|
306
|
+
Commit between grouped feature waves that edit the same workspace. If features
|
|
307
|
+
need separate review or commits, give each a persistent worktree and integrate
|
|
308
|
+
them separately; `wait --group` warns about shared non-isolated workspaces.
|
|
297
309
|
|
|
298
310
|
## Task design: cluster related work into fewer, richer delegations
|
|
299
311
|
|
|
@@ -188,8 +188,17 @@ run, use stateless `call` mode:
|
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
190
|
delegate --json codex call "Summarize this context in three bullets."
|
|
191
|
+
delegate --json claude call --pure --timeout 60 --output-schema result.schema.json < prompt.txt
|
|
191
192
|
```
|
|
192
193
|
|
|
194
|
+
`call --pure` is a hostile-input completion boundary available on Claude only.
|
|
195
|
+
It uses an empty temporary cwd, an allowlisted child environment, no Delegate
|
|
196
|
+
prompt framing, and no session persistence or tools according to the engine
|
|
197
|
+
capability contract. Claude receives the prompt only on stdin and is
|
|
198
|
+
schema-capable via `--output-schema`; `delegate --json describe` reports
|
|
199
|
+
`pureCall`, `structuredOutput`, `noSessionPersistence`, `usageEvents`, and
|
|
200
|
+
`promptStdin` per engine. `--timeout SECONDS` applies to every call-mode engine.
|
|
201
|
+
|
|
193
202
|
For multi-step fan-out or gated review flows, use Delegate Workflows. A workflow
|
|
194
203
|
is a Python script that launches normal Delegate child runs, journals progress,
|
|
195
204
|
can pause on approval gates, and can resume from cached child results:
|
|
@@ -261,6 +270,9 @@ cancelled, and `124` on timeout. `cancel` signals the run's process group
|
|
|
261
270
|
start-identity check against PID reuse; a cancelled run reports `cancelled`
|
|
262
271
|
rather than a false success. Tag a batch of launches with `--group NAME` and
|
|
263
272
|
`wait`, `runs`, and the worktree commands can select the whole group at once.
|
|
273
|
+
Commit between grouped feature waves that edit the same workspace. If features
|
|
274
|
+
need separate review or commits, give each a persistent worktree and integrate
|
|
275
|
+
them separately; `wait --group` warns about shared non-isolated workspaces.
|
|
264
276
|
|
|
265
277
|
## Task design: cluster related work into fewer, richer delegations
|
|
266
278
|
|
|
@@ -57,6 +57,13 @@ positional prompt input, and Kimi Code prompt mode currently uses `--prompt`,
|
|
|
57
57
|
so those launches still use argv transport; Delegate redacts Cursor and Kimi
|
|
58
58
|
prompt argv in dry-run output and run manifests.
|
|
59
59
|
|
|
60
|
+
Temporary safe isolation also re-roots absolute paths under the source workspace
|
|
61
|
+
when it transports the prompt, so `/source/repo/src/app.py` becomes the matching
|
|
62
|
+
path inside the isolated copy. Paths outside the workspace and prefix lookalikes
|
|
63
|
+
are left unchanged. The safe prompt asks the child to cite workspace-relative
|
|
64
|
+
paths in its report; consumers should not depend on temporary isolation paths.
|
|
65
|
+
Verbatim slash pass-through prompts are not rewritten.
|
|
66
|
+
|
|
60
67
|
For launch and `dry-run` commands, `--json` and `--isolation auto|none|worktree`
|
|
61
68
|
are unambiguous before inline prompt text starts and may appear with launch
|
|
62
69
|
options, such as `delegate codex work --prompt-file task.md --json` or
|
|
@@ -125,6 +132,11 @@ A few boundaries are worth stating explicitly:
|
|
|
125
132
|
create an orchestration manifest; it only enables selectors such as
|
|
126
133
|
`delegate runs --group NAME`, `delegate wait --group NAME`, and worktree
|
|
127
134
|
management filters. Group names must match `[A-Za-z0-9._-]{1,64}`.
|
|
135
|
+
If grouped feature waves run in the same non-isolated workspace, commit between
|
|
136
|
+
waves so later edits do not become interleaved with earlier work. When features
|
|
137
|
+
need separate review or commits, launch each in a persistent worktree and
|
|
138
|
+
integrate them separately; `wait --group` warns when it sees shared same-tree
|
|
139
|
+
work runs.
|
|
128
140
|
|
|
129
141
|
`--auth-profile NAME` selects a top-level `profiles.definitions` entry and
|
|
130
142
|
injects that profile's flat env map into child processes. It overrides ambient
|
|
@@ -139,7 +151,8 @@ auth/env selection happens.
|
|
|
139
151
|
Usage:
|
|
140
152
|
|
|
141
153
|
```bash
|
|
142
|
-
delegate [--json] [--isolation auto|none|worktree] codex {safe,work
|
|
154
|
+
delegate [--json] [--isolation auto|none|worktree] codex {safe,work} [--model <alias-or-model>] [--reasoning-effort LEVEL] [--fast|--no-fast] [--progress] [--forbid-commit] [--prompt-file PATH] [--output-schema FILE] [prompt...]
|
|
155
|
+
delegate [--json] codex call [--read-only] [--model <alias-or-model>] [--reasoning-effort LEVEL] [--fast|--no-fast] [--prompt-file PATH] [--output-schema FILE] [prompt...]
|
|
143
156
|
```
|
|
144
157
|
|
|
145
158
|
- Safe mode reviews your **current working tree** — uncommitted tracked edits and untracked, non-ignored files are mirrored into an isolated throwaway copy (only gitignored paths are excluded), so you can review local changes without committing first or pasting a diff. Codex safe always uses `--sandbox read-only`. Under `--isolation auto`, Codex safe is the only safe harness that may opt out with `--isolation none`, because Codex still keeps its read-only sandbox active.
|
|
@@ -166,7 +179,8 @@ delegate --isolation worktree codex work "Implement the feature in a persistent
|
|
|
166
179
|
Usage:
|
|
167
180
|
|
|
168
181
|
```bash
|
|
169
|
-
delegate [--json] [--isolation auto|none|worktree] claude {safe,work
|
|
182
|
+
delegate [--json] [--isolation auto|none|worktree] claude {safe,work} [--model <alias-or-model>] [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]
|
|
183
|
+
delegate [--json] claude call [--read-only] [--model <alias-or-model>] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]
|
|
170
184
|
```
|
|
171
185
|
|
|
172
186
|
- Safe mode reviews your **current working tree** — uncommitted tracked edits and untracked, non-ignored files are mirrored into an isolated throwaway copy (only gitignored paths are excluded), so you can review local changes without committing first or pasting a diff. Under `--isolation auto`, Claude safe uses `--permission-mode plan`, `--strict-mcp-config`, Read/Grep/Glob, and selected read-only Bash tools such as `git diff`/`git status`.
|
|
@@ -191,7 +205,8 @@ delegate --isolation worktree claude work "Implement the feature in a persistent
|
|
|
191
205
|
Usage:
|
|
192
206
|
|
|
193
207
|
```bash
|
|
194
|
-
delegate [--json] [--isolation auto|none|worktree] grok {safe,work
|
|
208
|
+
delegate [--json] [--isolation auto|none|worktree] grok {safe,work} [--model <alias-or-model>] [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]
|
|
209
|
+
delegate [--json] grok call [--read-only] [--model <alias-or-model>] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]
|
|
195
210
|
```
|
|
196
211
|
|
|
197
212
|
- Safe mode reviews your **current working tree** in an isolated throwaway copy plus Grok read-only controls (`--sandbox read-only`, `--permission-mode dontAsk` by default). Delegate does not use Grok `plan` mode for safe review.
|
|
@@ -274,7 +289,8 @@ delegate --isolation worktree opencode work "Implement the feature in a persiste
|
|
|
274
289
|
Usage:
|
|
275
290
|
|
|
276
291
|
```bash
|
|
277
|
-
delegate [--json] [--isolation auto|none|worktree] kimi {safe,work
|
|
292
|
+
delegate [--json] [--isolation auto|none|worktree] kimi {safe,work} [--model <alias-or-model>] [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]
|
|
293
|
+
delegate [--json] kimi call [--read-only] [--model <alias-or-model>] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]
|
|
278
294
|
```
|
|
279
295
|
|
|
280
296
|
- Safe mode reviews your **current working tree** — uncommitted tracked edits and untracked, non-ignored files are mirrored into an isolated throwaway copy (only gitignored paths are excluded), so you can review local changes without committing first or pasting a diff. Under `--isolation auto`, Kimi safe uses a read-only safety prompt. Delegate intentionally avoids Kimi `--plan` in safe mode. Kimi prompt mode auto-approves tool actions, so the isolation is the effective write boundary; the safety prompt is advisory.
|
|
@@ -308,8 +324,8 @@ delegate [--json] workflow run --resume <wfId> [--budget N]
|
|
|
308
324
|
delegate [--json] workflow status <wfId>
|
|
309
325
|
delegate [--json] workflow events <wfId> [--since SEQ]
|
|
310
326
|
delegate [--json] workflow watch <wfId> [--since SEQ]
|
|
311
|
-
delegate [--json] workflow wait <wfId> [--timeout SEC]
|
|
312
|
-
delegate [--json] workflow result <wfId>
|
|
327
|
+
delegate [--json] workflow wait [<wfId>] [--timeout SEC]
|
|
328
|
+
delegate [--json] workflow result [<wfId>] [--field KEY]
|
|
313
329
|
delegate [--json] workflow approve <wfId>
|
|
314
330
|
delegate [--json] workflow kill <wfId>
|
|
315
331
|
delegate [--json] workflow list
|
|
@@ -319,9 +335,18 @@ delegate [--json] workflow save <script.py> --name NAME
|
|
|
319
335
|
- `check` validates the workflow script, including literal preflight checks for
|
|
320
336
|
unsupported `agent()` combinations.
|
|
321
337
|
- `run` launches a detached supervisor; `--dry-run` renders planned stubs
|
|
322
|
-
without launching child agents or consuming real budget.
|
|
338
|
+
without launching child agents or consuming real budget. Each entry in
|
|
339
|
+
`runTree.calls` includes the resolved `model`, `effort`, `fast`, `isolation`,
|
|
340
|
+
and UTF-8 `promptBytes`; Cursor/Kimi prompts over 102400 bytes add a warning
|
|
341
|
+
before their argv transport limit can fail a real run.
|
|
323
342
|
- `--resume` replays the journal, adopts matching child runs by workflow agent
|
|
324
343
|
key, and continues from missing work.
|
|
344
|
+
- `wait` and `result` accept an explicit workflow ID or, when omitted, resolve
|
|
345
|
+
the latest eligible workflow. JSON output for implicit selection includes the
|
|
346
|
+
selected `wfId` and `resolutionKind: "latest"`.
|
|
347
|
+
- `result --field KEY` extracts a top-level field from an object result. Text
|
|
348
|
+
mode prints strings directly and JSON-encodes other values; JSON mode returns
|
|
349
|
+
a field/value envelope.
|
|
325
350
|
- `approve` releases a paused gate (and resumes). Do not also run
|
|
326
351
|
`run --resume` for the same gate — approve already is that resume. `kill`
|
|
327
352
|
validates the supervisor process group before signaling and always attempts
|
|
@@ -340,6 +365,7 @@ Codes raised as `DelegateError` from workflow commands (`workflows/commands.py`)
|
|
|
340
365
|
| `invalid_workflow_name` | Saved-workflow `--name` is not a simple file stem. |
|
|
341
366
|
| `invalid_workflow_script` | Script failed `check` / load validation. |
|
|
342
367
|
| `missing_workflow` | A verb that needs `<wfId>` was invoked without one. |
|
|
368
|
+
| `missing_workflow_result_field` | `result --field` was invoked without a key. |
|
|
343
369
|
| `missing_workflow_save_args` | `save` needs both `<script.py>` and `--name`. |
|
|
344
370
|
| `missing_workflow_script` | `run`/`check` need `<script.py>` or `--name`. |
|
|
345
371
|
| `unknown_workflow_action` | Unrecognized `workflow` subcommand. |
|
|
@@ -348,6 +374,8 @@ Codes raised as `DelegateError` from workflow commands (`workflows/commands.py`)
|
|
|
348
374
|
| `workflow_not_found` | No workflow directory / status for that `wfId`. |
|
|
349
375
|
| `workflow_not_gated` | `approve` on a workflow that is not paused on a gate. |
|
|
350
376
|
| `workflow_result_missing` | `result` before `result.json` exists. |
|
|
377
|
+
| `workflow_result_field_missing` | The requested top-level result field does not exist. |
|
|
378
|
+
| `workflow_result_not_object` | `--field` was requested for a non-object result. |
|
|
351
379
|
| `workflow_script_not_found` | Resolved script path is missing or not a file. |
|
|
352
380
|
|
|
353
381
|
See [Delegate Workflows](delegate-workflows.md) for the DSL, caps, config, and
|
|
@@ -356,24 +384,26 @@ gate semantics.
|
|
|
356
384
|
### Stateless `call` mode
|
|
357
385
|
|
|
358
386
|
`call` is the one-hop model-call form of Delegate: "work mode minus a repo." It
|
|
359
|
-
gives a child runtime a prompt with no project tree to resolve
|
|
360
|
-
final assistant text,
|
|
361
|
-
|
|
362
|
-
|
|
387
|
+
gives a child runtime a prompt with no project tree to resolve and captures the
|
|
388
|
+
final assistant text, so you can call a model to *do something* (or to *judge
|
|
389
|
+
something*) from anywhere, including a non-git directory. Calls are untracked
|
|
390
|
+
by default; grouped calls are the narrow exception described below.
|
|
363
391
|
|
|
364
392
|
```bash
|
|
365
393
|
delegate codex call "Write a Python script that finds the 500th prime and run it."
|
|
366
394
|
delegate --json grok call --read-only --prompt-file rubric.md
|
|
367
395
|
delegate --json codex call --read-only --output-schema verdict.json --prompt-file rubric.md
|
|
396
|
+
delegate --json claude call --pure --timeout 60 --output-schema verdict.json < rubric.md
|
|
368
397
|
```
|
|
369
398
|
|
|
370
399
|
Call mode uses an empty temporary cwd instead of resolving the current repo, and
|
|
371
|
-
it deletes that cwd after the child exits. It does not
|
|
372
|
-
|
|
373
|
-
|
|
400
|
+
it deletes that cwd after the child exits. It does not create snapshots, inject
|
|
401
|
+
safe/work skill or completion-report framing, emit progress heartbeats, or honor
|
|
402
|
+
persistent worktree/commit policy options. JSON
|
|
374
403
|
output returns fields such as `ok`, `status`, `exitCode`, `engine`, `mode`,
|
|
375
|
-
`model`, `
|
|
376
|
-
|
|
404
|
+
`model`, `pure`, `structuredOutput`, `modelRequested`, `modelResolved`, `usage`,
|
|
405
|
+
`text`, `textChars`, `textTruncated`, `stdoutBytes`, `stderrBytes`, reasoning
|
|
406
|
+
metadata, and `warnings`. Failed calls include a redacted `stderrTail`.
|
|
377
407
|
`textTruncated` is `true` when the returned
|
|
378
408
|
`text` was bounded (large outputs keep the head and tail); `textChars` is the
|
|
379
409
|
full untruncated character count.
|
|
@@ -392,11 +422,38 @@ changed files…" on a repo-flavored prompt. Pair it with `--output-schema` (Cod
|
|
|
392
422
|
for structured verdicts. Use `--read-only` for any LLM-as-judge, grader, or
|
|
393
423
|
oracle use where the text is the product and the model must not act.
|
|
394
424
|
|
|
395
|
-
|
|
396
|
-
|
|
425
|
+
**`--pure` is the hostile-content completion boundary.** It is supported by
|
|
426
|
+
Claude only; other engines fail before launch with `unsupported_pure_call`. Pure
|
|
427
|
+
mode sends the prompt verbatim, drops ambient
|
|
428
|
+
environment variables outside the documented allowlist, and cannot be combined
|
|
429
|
+
with `--read-only`. Claude uses `--safe-mode`, disables every tool, ignores MCP
|
|
430
|
+
and ambient customization, disables session persistence, and receives the prompt
|
|
431
|
+
only on stdin. Use `--output-schema FILE` with Claude (schema contents inline)
|
|
432
|
+
or with ordinary Codex call mode (schema path).
|
|
433
|
+
|
|
434
|
+
`--timeout SECONDS` is a positive integer available on every call-mode engine.
|
|
435
|
+
On expiry Delegate terminates the whole child process group and returns
|
|
436
|
+
`call_timeout` with exit code 1.
|
|
437
|
+
|
|
438
|
+
`--read-only`, `--pure`, and `--timeout` apply only to `call`; passing them with
|
|
439
|
+
`safe`/`work` is rejected.
|
|
440
|
+
Because the child call is stateless, `--isolation`, `--pass-through`,
|
|
397
441
|
`--progress`, `--forbid-commit`, and markdown completion reports are rejected.
|
|
398
|
-
|
|
399
|
-
|
|
442
|
+
An ordinary call also rejects `--cwd`.
|
|
443
|
+
|
|
444
|
+
**Grouped calls preserve workflow tracking without exposing the workspace to the
|
|
445
|
+
child.** `--group NAME` registers the call in the invocation workspace so
|
|
446
|
+
workflow kill/adopt and group selectors can find it. In that one combination,
|
|
447
|
+
`--cwd PATH` may select the registry/config workspace:
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
delegate --cwd /path/to/project --group wf_0123abcdef45 codex call "Summarize this input."
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
The child still executes in an empty temporary cwd; `--cwd` does not give it the
|
|
454
|
+
project tree. Dry-run accepts the same combination for faithful planning but
|
|
455
|
+
creates no run entry. Use `safe` or `work` when the child should see the project
|
|
456
|
+
tree.
|
|
400
457
|
|
|
401
458
|
### Dry-run
|
|
402
459
|
|
|
@@ -536,7 +593,7 @@ Supported input keys:
|
|
|
536
593
|
- `progress`: optional boolean. `true` enables parent progress heartbeats on stderr; `false` disables them even when `progress.enabled` is true in config. When omitted, config `progress.enabled` applies (default `false`). `mode: "call"` rejects progress.
|
|
537
594
|
- `forbidCommit`: optional boolean. `true` requires `mode: "work"` with persistent worktree isolation and fails the run if the child creates commits. `mode: "call"` rejects commit policy.
|
|
538
595
|
- `includeDirty`: optional boolean. `true` requires `mode: "work"` with persistent worktree isolation and syncs tracked edits plus untracked non-ignored files into the new worktree before launch.
|
|
539
|
-
- `outputSchema`: optional path to a JSON Schema for
|
|
596
|
+
- `outputSchema`: optional path to a JSON Schema for the final message. Supported for Codex and Claude call mode (same semantics as `--output-schema`). Other engines fail with `unsupported_output_schema`.
|
|
540
597
|
- `prompt`: required task prompt.
|
|
541
598
|
|
|
542
599
|
`profile` is not accepted in run input JSON. Configure the Codex CLI config
|
|
@@ -734,7 +791,8 @@ signals the recorded process group with SIGTERM, waits a 5s grace period, then
|
|
|
734
791
|
uses SIGKILL if needed. It never signals pid/pgid `<= 1`. Legacy runs without a
|
|
735
792
|
recorded pgid fall back to the recorded pid with a warning. Cancel marks the run
|
|
736
793
|
`cancelled` with `failureReason: cancelled_by_user` and records current captured
|
|
737
|
-
stdout/stderr byte counts. `call` mode is untracked
|
|
794
|
+
stdout/stderr byte counts. Ungrouped `call` mode is untracked; grouped calls are
|
|
795
|
+
registered and can be selected for cancellation.
|
|
738
796
|
|
|
739
797
|
Before sending any signal, cancel stamps a `cancelRequested: true` marker (with
|
|
740
798
|
a `cancelRequestedAt` timestamp) on the run state under the registry lock, so
|
|
@@ -100,6 +100,35 @@ you need registry inspection.
|
|
|
100
100
|
OpenCode `call --read-only` uses the same protected environment settings and
|
|
101
101
|
`--pure` plugin restriction as OpenCode safe mode.
|
|
102
102
|
|
|
103
|
+
`call --pure` is a separate, stronger completion boundary. It is currently
|
|
104
|
+
supported on **Claude only**. Delegate sends the prompt verbatim on stdin, starts
|
|
105
|
+
the child in an empty temporary cwd, and builds the child environment from only
|
|
106
|
+
`PATH`, `HOME`, `USER`, `LOGNAME`, `SHELL`, `TMPDIR`, `LANG`, `LC_ALL`, `LC_CTYPE`,
|
|
107
|
+
and `TERM`, then applies trusted Delegate profile overrides. Claude additionally
|
|
108
|
+
uses `--safe-mode --tools "" --strict-mcp-config --no-session-persistence`, and the
|
|
109
|
+
result must carry an empty `permission_denials` list — a missing, null, or
|
|
110
|
+
non-empty value fails the call closed (`pure_boundary_unverified` /
|
|
111
|
+
`pure_boundary_violation`) rather than reporting success.
|
|
112
|
+
|
|
113
|
+
Codex and OpenCode are **not** pure-eligible; `<engine> call --pure` is rejected
|
|
114
|
+
before launch (`unsupported_pure_call`). They were disabled after review:
|
|
115
|
+
|
|
116
|
+
- **Codex** would need external OS confinement (a macOS Seatbelt profile) because
|
|
117
|
+
it stays a tool-using agent. The prototype handed the child an ephemeral
|
|
118
|
+
`CODEX_HOME` holding the resolved `auth.json`, but a single inherited Seatbelt
|
|
119
|
+
profile cannot distinguish a read by the Codex parent from a read by a
|
|
120
|
+
model-driven subprocess, so the credential was reachable inside the boundary it
|
|
121
|
+
was meant to protect. A credential transport the parent can use but model tools
|
|
122
|
+
cannot read is required before Codex pure is re-enabled. `sandbox-exec` is also
|
|
123
|
+
deprecated on macOS and would never cover other platforms.
|
|
124
|
+
- **OpenCode**'s native `--pure` only disables external plugins; it offers no
|
|
125
|
+
session non-persistence, no schema output, and no denial tripwire, so it does
|
|
126
|
+
not meet the hostile-input contract.
|
|
127
|
+
|
|
128
|
+
Fail-closed eligibility is intentional: an engine without a verified boundary
|
|
129
|
+
rejects `--pure` rather than presenting a weaker one under the same name. The
|
|
130
|
+
supported pure matrix may contain only Claude for some time.
|
|
131
|
+
|
|
103
132
|
## Reasoning-effort boundary
|
|
104
133
|
|
|
105
134
|
`--reasoning-effort LEVEL` and JSON `reasoningEffort` request model thinking depth only. They do not change:
|
|
@@ -12,6 +12,10 @@ Use persistent worktree isolation when:
|
|
|
12
12
|
|
|
13
13
|
Use the real workspace instead when the task depends on uncommitted local files that you do not want to commit or mirror into a worktree. If you do want a persistent worktree that starts from your current dirty checkout, use `--include-dirty`.
|
|
14
14
|
|
|
15
|
+
For grouped feature waves, commit between waves when they share the real
|
|
16
|
+
workspace. If each feature needs its own review or commit, use one persistent
|
|
17
|
+
worktree per feature and integrate those worktrees separately.
|
|
18
|
+
|
|
15
19
|
## Launch
|
|
16
20
|
|
|
17
21
|
```bash
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "delegate-agent-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.14.0"
|
|
8
8
|
description = "A tiny CLI for delegating bounded agent tasks to Cursor, Droid, OpenAI Codex, Claude Code, Grok Build, or Kimi Code runtimes."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -125,6 +125,13 @@ def _grok_harness_bypass_enabled(config: JsonObject, mode: str) -> bool:
|
|
|
125
125
|
return _harness_bypass_enabled(config, mode, "grok")
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
def _reject_pure(engine: str, mode: str, pure: bool, *, supported: bool = False) -> None:
|
|
129
|
+
if not pure:
|
|
130
|
+
return
|
|
131
|
+
if mode != MODE_CALL or not supported:
|
|
132
|
+
raise DelegateError("unsupported_pure_call", f"{engine} does not support pure call mode.")
|
|
133
|
+
|
|
134
|
+
|
|
128
135
|
def build_cursor_argv(
|
|
129
136
|
prefix: list[str],
|
|
130
137
|
mode: str,
|
|
@@ -134,7 +141,9 @@ def build_cursor_argv(
|
|
|
134
141
|
*,
|
|
135
142
|
stream_capture: bool = True,
|
|
136
143
|
call_read_only: bool = False,
|
|
144
|
+
pure: bool = False,
|
|
137
145
|
) -> list[str]:
|
|
146
|
+
_reject_pure("cursor", mode, pure)
|
|
138
147
|
argv = [*prefix, "--workspace", workspace, "-p", "--trust"]
|
|
139
148
|
if mode == MODE_WORK:
|
|
140
149
|
argv.extend(["--approve-mcps", "--force"])
|
|
@@ -165,7 +174,9 @@ def build_droid_argv(
|
|
|
165
174
|
reasoning_capability: reasoning.ReasoningCapability | None = None,
|
|
166
175
|
prompt_transport: str = PROMPT_TRANSPORT_ARGV,
|
|
167
176
|
call_read_only: bool = False,
|
|
177
|
+
pure: bool = False,
|
|
168
178
|
) -> list[str]:
|
|
179
|
+
_reject_pure("droid", mode, pure)
|
|
169
180
|
argv = [binary, "exec", "--cwd", workspace]
|
|
170
181
|
if mode == MODE_WORK:
|
|
171
182
|
argv.append("--skip-permissions-unsafe")
|
|
@@ -202,7 +213,9 @@ def build_kimi_argv(
|
|
|
202
213
|
prompt: str,
|
|
203
214
|
*,
|
|
204
215
|
stream_capture: bool = True,
|
|
216
|
+
pure: bool = False,
|
|
205
217
|
) -> list[str]:
|
|
218
|
+
_reject_pure("kimi", mode, pure)
|
|
206
219
|
argv = [str(kimi["binary"])]
|
|
207
220
|
if mode == MODE_SAFE:
|
|
208
221
|
prompt = prefix_kimi_safe_prompt(prompt)
|
|
@@ -226,16 +239,35 @@ def build_claude_argv(
|
|
|
226
239
|
reasoning_effort: str | None = None,
|
|
227
240
|
allow_bypass_permissions: bool = False,
|
|
228
241
|
call_read_only: bool = False,
|
|
242
|
+
pure: bool = False,
|
|
243
|
+
output_schema: str | None = None,
|
|
229
244
|
) -> list[str]:
|
|
245
|
+
_reject_pure("claude", mode, pure, supported=True)
|
|
246
|
+
if pure or output_schema is not None:
|
|
247
|
+
output_format = "json"
|
|
248
|
+
elif stream_capture:
|
|
249
|
+
output_format = "stream-json"
|
|
250
|
+
else:
|
|
251
|
+
output_format = "text"
|
|
230
252
|
argv = [
|
|
231
253
|
str(claude["binary"]),
|
|
232
254
|
"-p",
|
|
233
255
|
"--output-format",
|
|
234
|
-
|
|
256
|
+
output_format,
|
|
235
257
|
"--input-format",
|
|
236
258
|
"text",
|
|
237
259
|
]
|
|
238
|
-
if
|
|
260
|
+
if pure:
|
|
261
|
+
argv.extend(
|
|
262
|
+
[
|
|
263
|
+
"--safe-mode",
|
|
264
|
+
"--tools",
|
|
265
|
+
"",
|
|
266
|
+
"--strict-mcp-config",
|
|
267
|
+
"--no-session-persistence",
|
|
268
|
+
]
|
|
269
|
+
)
|
|
270
|
+
elif mode == MODE_SAFE:
|
|
239
271
|
argv.extend(
|
|
240
272
|
[
|
|
241
273
|
"--permission-mode",
|
|
@@ -271,10 +303,12 @@ def build_claude_argv(
|
|
|
271
303
|
argv.extend(["--permission-mode", str(claude.get("workPermissionMode", "auto"))])
|
|
272
304
|
else:
|
|
273
305
|
validate_mode(mode)
|
|
274
|
-
if claude.get("noSessionPersistence", True) is True:
|
|
306
|
+
if not pure and claude.get("noSessionPersistence", True) is True:
|
|
275
307
|
argv.append("--no-session-persistence")
|
|
276
|
-
if claude.get("bare", False) is True:
|
|
308
|
+
if not pure and claude.get("bare", False) is True:
|
|
277
309
|
argv.append("--bare")
|
|
310
|
+
if output_schema is not None:
|
|
311
|
+
argv.extend(["--json-schema", output_schema])
|
|
278
312
|
if model:
|
|
279
313
|
argv.extend(["--model", model])
|
|
280
314
|
if reasoning_effort is not None:
|
|
@@ -294,7 +328,9 @@ def build_grok_argv(
|
|
|
294
328
|
allow_bypass_permissions: bool = False,
|
|
295
329
|
prompt_transport: str = PROMPT_TRANSPORT_FILE,
|
|
296
330
|
call_read_only: bool = False,
|
|
331
|
+
pure: bool = False,
|
|
297
332
|
) -> list[str]:
|
|
333
|
+
_reject_pure("grok", mode, pure)
|
|
298
334
|
argv = [str(grok["binary"]), "--cwd", workspace]
|
|
299
335
|
if stream_capture:
|
|
300
336
|
argv.extend(["--output-format", "streaming-json"])
|
|
@@ -358,7 +394,9 @@ def build_devin_argv(
|
|
|
358
394
|
*,
|
|
359
395
|
prompt_transport: str = PROMPT_TRANSPORT_FILE,
|
|
360
396
|
call_read_only: bool = False,
|
|
397
|
+
pure: bool = False,
|
|
361
398
|
) -> list[str]:
|
|
399
|
+
_reject_pure("devin", mode, pure)
|
|
362
400
|
argv = [str(devin["binary"])]
|
|
363
401
|
if model:
|
|
364
402
|
argv.extend(["--model", model])
|
|
@@ -394,8 +432,10 @@ def build_opencode_argv(
|
|
|
394
432
|
variant: str | None,
|
|
395
433
|
*,
|
|
396
434
|
call_read_only: bool = False,
|
|
435
|
+
pure: bool = False,
|
|
397
436
|
) -> list[str]:
|
|
398
|
-
|
|
437
|
+
_reject_pure("opencode", mode, pure)
|
|
438
|
+
read_only = mode == MODE_SAFE or (mode == MODE_CALL and (call_read_only or pure))
|
|
399
439
|
argv = [str(opencode["binary"])]
|
|
400
440
|
if read_only:
|
|
401
441
|
argv.append("--pure")
|
|
@@ -428,8 +468,39 @@ def build_codex_argv(
|
|
|
428
468
|
prompt_transport: str = PROMPT_TRANSPORT_ARGV,
|
|
429
469
|
output_schema: str | None = None,
|
|
430
470
|
call_read_only: bool = False,
|
|
471
|
+
pure: bool = False,
|
|
431
472
|
) -> list[str]:
|
|
473
|
+
_reject_pure("codex", mode, pure)
|
|
432
474
|
binary = str(codex["binary"])
|
|
475
|
+
if pure:
|
|
476
|
+
argv = [binary]
|
|
477
|
+
if model:
|
|
478
|
+
argv.extend(["--model", model])
|
|
479
|
+
if reasoning_capability is not None:
|
|
480
|
+
argv.extend(["-c", f'model_reasoning_effort="{reasoning_capability.effort}"'])
|
|
481
|
+
if fast is not None:
|
|
482
|
+
service_tier = "fast" if fast else "default"
|
|
483
|
+
argv.extend(["-c", f'service_tier="{service_tier}"'])
|
|
484
|
+
if fast:
|
|
485
|
+
argv.extend(["-c", "features.fast_mode=true"])
|
|
486
|
+
argv.extend(
|
|
487
|
+
[
|
|
488
|
+
"exec",
|
|
489
|
+
"--ignore-user-config",
|
|
490
|
+
"--ignore-rules",
|
|
491
|
+
"--skip-git-repo-check",
|
|
492
|
+
"--sandbox",
|
|
493
|
+
"read-only",
|
|
494
|
+
]
|
|
495
|
+
)
|
|
496
|
+
if output_schema is not None:
|
|
497
|
+
argv.extend(["--output-schema", output_schema])
|
|
498
|
+
if stream_capture:
|
|
499
|
+
argv.extend(["--color", "never", "--json"])
|
|
500
|
+
if codex.get("ephemeral", True) is True:
|
|
501
|
+
argv.append("--ephemeral")
|
|
502
|
+
argv.append("-")
|
|
503
|
+
return argv
|
|
433
504
|
argv = [binary]
|
|
434
505
|
# Safe mode is read-only by contract: never emit the dangerous bypass flags,
|
|
435
506
|
# even if a policy block somehow carries them. Config validation rejects such
|
|
@@ -35,4 +35,12 @@ def replace_workspace_arg_in_argv(engine: str, argv: list[str], value: str) -> l
|
|
|
35
35
|
|
|
36
36
|
def public_argv(request: Request) -> list[str]:
|
|
37
37
|
"""Return the display-safe argv for a request (redacted form when present)."""
|
|
38
|
-
|
|
38
|
+
argv = list(request.display_argv if request.display_argv is not None else request.argv)
|
|
39
|
+
output_schema = getattr(request, "output_schema", None)
|
|
40
|
+
if output_schema and request.engine == "claude" and "--json-schema" in argv:
|
|
41
|
+
redacted = list(argv)
|
|
42
|
+
idx = redacted.index("--json-schema")
|
|
43
|
+
if idx + 1 < len(redacted):
|
|
44
|
+
redacted[idx + 1] = f"<json-schema:{len(redacted[idx + 1])} bytes>"
|
|
45
|
+
return redacted
|
|
46
|
+
return argv
|