delegate-agent-cli 0.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. delegate_agent/__init__.py +5 -0
  2. delegate_agent/archived_logs.py +44 -0
  3. delegate_agent/argv_builders.py +423 -0
  4. delegate_agent/argv_utils.py +36 -0
  5. delegate_agent/capability_commands.py +99 -0
  6. delegate_agent/cli.py +987 -0
  7. delegate_agent/cli_parser.py +1627 -0
  8. delegate_agent/command_errors.py +29 -0
  9. delegate_agent/command_help.py +1264 -0
  10. delegate_agent/config.py +1117 -0
  11. delegate_agent/config_commands.py +143 -0
  12. delegate_agent/constants.py +50 -0
  13. delegate_agent/describe_payload.py +1018 -0
  14. delegate_agent/errors.py +32 -0
  15. delegate_agent/git_utils.py +180 -0
  16. delegate_agent/harness_events.py +719 -0
  17. delegate_agent/inspection_commands.py +104 -0
  18. delegate_agent/isolation.py +316 -0
  19. delegate_agent/json_types.py +18 -0
  20. delegate_agent/log_output.py +78 -0
  21. delegate_agent/private_io.py +109 -0
  22. delegate_agent/profile_commands.py +42 -0
  23. delegate_agent/profile_guard.py +116 -0
  24. delegate_agent/profiles.py +389 -0
  25. delegate_agent/prompt_instructions.py +39 -0
  26. delegate_agent/prompt_transport.py +12 -0
  27. delegate_agent/reasoning.py +916 -0
  28. delegate_agent/redaction.py +193 -0
  29. delegate_agent/rendering.py +573 -0
  30. delegate_agent/request_build.py +1681 -0
  31. delegate_agent/request_models.py +191 -0
  32. delegate_agent/retention.py +321 -0
  33. delegate_agent/run_metadata.py +78 -0
  34. delegate_agent/run_output_commands.py +645 -0
  35. delegate_agent/run_registry.py +747 -0
  36. delegate_agent/run_status.py +300 -0
  37. delegate_agent/runner.py +1830 -0
  38. delegate_agent/safe_workspace.py +821 -0
  39. delegate_agent/snapshot_view.py +229 -0
  40. delegate_agent/wait_cancel_commands.py +559 -0
  41. delegate_agent/worktree_commands.py +218 -0
  42. delegate_agent/worktree_execution.py +654 -0
  43. delegate_agent/worktree_gc.py +529 -0
  44. delegate_agent/worktree_mgmt.py +782 -0
  45. delegate_agent/worktree_records.py +232 -0
  46. delegate_agent/worktree_remove.py +547 -0
  47. delegate_agent/worktree_summary.py +242 -0
  48. delegate_agent/wsl.py +65 -0
  49. delegate_agent_cli-0.11.0.dist-info/METADATA +325 -0
  50. delegate_agent_cli-0.11.0.dist-info/RECORD +54 -0
  51. delegate_agent_cli-0.11.0.dist-info/WHEEL +5 -0
  52. delegate_agent_cli-0.11.0.dist-info/entry_points.txt +2 -0
  53. delegate_agent_cli-0.11.0.dist-info/licenses/LICENSE +21 -0
  54. delegate_agent_cli-0.11.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1264 @@
1
+ """Registry-backed single source of truth for delegate CLI help.
2
+
3
+ This module is import-pure: it performs zero I/O, loads no configuration, and
4
+ touches no filesystem. Every piece of help -- per-command text, the agent-facing
5
+ JSON contract, and the global overview block -- derives from the declarative
6
+ ``COMMAND_SPECS`` registry and ``GLOBAL_OPTIONS`` so the three views cannot drift.
7
+
8
+ Worktree maintenance deliberately uses remove/prune/gc; the word "delete" never
9
+ appears in any spec or rendered output.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass, field
15
+
16
+ from delegate_agent import VERSION
17
+ from delegate_agent.constants import ENGINES_PROSE
18
+ from delegate_agent.json_types import JsonObject
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class OptionSpec:
23
+ """A single ``--flag`` (optionally taking an argument)."""
24
+
25
+ flag: str
26
+ arg: str | None
27
+ description: str
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class ArgSpec:
32
+ """A positional argument."""
33
+
34
+ name: str
35
+ required: bool
36
+ description: str
37
+
38
+
39
+ @dataclass(frozen=True)
40
+ class CommandSpec:
41
+ """Declarative metadata for one command path (e.g. ``"worktree remove"``)."""
42
+
43
+ name: str
44
+ summary: str
45
+ usage: tuple[str, ...]
46
+ arguments: tuple[ArgSpec, ...] = field(default_factory=tuple)
47
+ options: tuple[OptionSpec, ...] = field(default_factory=tuple)
48
+ examples: tuple[str, ...] = field(default_factory=tuple)
49
+ notes: tuple[str, ...] = field(default_factory=tuple)
50
+ see_also: tuple[str, ...] = field(default_factory=tuple)
51
+ unsupported_global_options: tuple[str, ...] = field(default_factory=tuple)
52
+
53
+
54
+ SAFE_WORKSPACE_SYNC_NOTE = (
55
+ "Safe mode reviews your **current working tree** — uncommitted tracked edits "
56
+ "and untracked, non-ignored files are mirrored into an isolated throwaway copy "
57
+ "(only gitignored paths are excluded), so you can review local changes without "
58
+ "committing first or pasting a diff."
59
+ )
60
+ CALL_MODE_NOTE = (
61
+ "call mode is a stateless model call with no repo: no workspace cwd, isolation, "
62
+ "progress heartbeat, commit policy, run registry, snapshot, or completion report. "
63
+ "It defaults to work-level capability (the child may write/run in a throwaway temp "
64
+ "cwd, so treat it like work and only pass trusted prompts); pass --read-only for the "
65
+ "stateless judge/completion contract (read-only capability plus an evaluator preamble "
66
+ "so non-Codex engines don't derail on repo-flavored prompts)."
67
+ )
68
+
69
+
70
+ # --------------------------------------------------------------------------- #
71
+ # Global options (must appear before the subcommand).
72
+ # --------------------------------------------------------------------------- #
73
+
74
+ GLOBAL_OPTIONS: tuple[OptionSpec, ...] = (
75
+ OptionSpec("--cwd", "PATH", "Resolve the workspace from PATH (repo root inside Git)."),
76
+ OptionSpec("--json", None, "Emit machine-readable JSON instead of human text."),
77
+ OptionSpec(
78
+ "--isolation",
79
+ "auto|none|worktree",
80
+ "Override isolation strategy for this run (auto, none, or worktree).",
81
+ ),
82
+ OptionSpec(
83
+ "--auth-profile",
84
+ "NAME",
85
+ "Select a configured profiles.definitions entry for this launch.",
86
+ ),
87
+ OptionSpec(
88
+ "--group",
89
+ "NAME",
90
+ "Tag a launched run for later runs/wait/worktree selectors ([A-Za-z0-9._-]{1,64}).",
91
+ ),
92
+ OptionSpec(
93
+ "--pass-through",
94
+ None,
95
+ "Stream raw child stdout/stderr (incompatible with --json).",
96
+ ),
97
+ OptionSpec(
98
+ "--completion-report",
99
+ "MODE",
100
+ "Completion-report mode: markdown (default) or none.",
101
+ ),
102
+ OptionSpec(
103
+ "--no-completion-report",
104
+ None,
105
+ "Disable completion-report prompt injection.",
106
+ ),
107
+ )
108
+
109
+
110
+ # Shared option/argument fragments reused across the engine-style commands.
111
+ _PROMPT_FILE_OPTION = OptionSpec(
112
+ "--prompt-file",
113
+ "PATH",
114
+ "Read the prompt from PATH instead of trailing prompt text.",
115
+ )
116
+ _REASONING_EFFORT_OPTION = OptionSpec(
117
+ "--reasoning-effort",
118
+ "LEVEL",
119
+ "Request model-specific reasoning depth; unsupported model/level pairs fail closed.",
120
+ )
121
+ _OUTPUT_SCHEMA_OPTION = OptionSpec(
122
+ "--output-schema",
123
+ "FILE",
124
+ "Codex-only JSON Schema for the final message; also suppresses the completion-report instruction.",
125
+ )
126
+ _PROGRESS_OPTION = OptionSpec(
127
+ "--progress",
128
+ None,
129
+ "Emit bounded, credential-scrubbed parent progress heartbeats to stderr while preserving final stdout.",
130
+ )
131
+ _NO_PROGRESS_OPTION = OptionSpec(
132
+ "--no-progress",
133
+ None,
134
+ "Disable progress heartbeats for this launch even when progress.enabled is true in config.",
135
+ )
136
+ _FORBID_COMMIT_OPTION = OptionSpec(
137
+ "--forbid-commit",
138
+ None,
139
+ "Only valid for persistent worktree work runs (--isolation worktree); "
140
+ "fail if commits remain ahead of the creation base when the child exits.",
141
+ )
142
+ _INCLUDE_DIRTY_OPTION = OptionSpec(
143
+ "--include-dirty",
144
+ None,
145
+ "work + persistent worktree only: sync tracked edits and untracked non-ignored files into the new worktree.",
146
+ )
147
+ _READ_ONLY_OPTION = OptionSpec(
148
+ "--read-only",
149
+ None,
150
+ "call mode only: drop to read-only capability and add an evaluator preamble "
151
+ "(the stateless judge/completion contract). Rejected for safe/work.",
152
+ )
153
+ _PROMPT_ARG = ArgSpec(
154
+ "prompt",
155
+ False,
156
+ "Trailing prompt text. Use --prompt-file or stdin for long or flag-like prompts.",
157
+ )
158
+ _MODE_ARG = ArgSpec(
159
+ "mode",
160
+ True,
161
+ "Execution mode: safe (read-only review), work (may edit the workspace), or call (stateless one-shot model call).",
162
+ )
163
+
164
+
165
+ # --------------------------------------------------------------------------- #
166
+ # Command registry.
167
+ # --------------------------------------------------------------------------- #
168
+
169
+ COMMAND_SPECS: dict[str, CommandSpec] = {
170
+ "cursor": CommandSpec(
171
+ name="cursor",
172
+ summary="Run Cursor Composer in safe, work, or stateless call mode.",
173
+ usage=(
174
+ "delegate [--json] [--isolation auto|none|worktree] "
175
+ "cursor {safe,work} [--reasoning-effort LEVEL] [--progress] "
176
+ "[--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
177
+ "delegate [--json] cursor call [--read-only] [--reasoning-effort LEVEL] "
178
+ "[--prompt-file PATH] [prompt...]",
179
+ ),
180
+ arguments=(_MODE_ARG, _PROMPT_ARG),
181
+ options=(
182
+ _REASONING_EFFORT_OPTION,
183
+ _PROGRESS_OPTION,
184
+ _NO_PROGRESS_OPTION,
185
+ _FORBID_COMMIT_OPTION,
186
+ _INCLUDE_DIRTY_OPTION,
187
+ _READ_ONLY_OPTION,
188
+ _PROMPT_FILE_OPTION,
189
+ ),
190
+ examples=(
191
+ 'delegate cursor work "Implement the scoped task; report changed files and tests."',
192
+ 'delegate cursor safe "Review this diff for regressions; report file/line/severity."',
193
+ "delegate cursor work --prompt-file task.md",
194
+ ),
195
+ notes=(
196
+ SAFE_WORKSPACE_SYNC_NOTE,
197
+ CALL_MODE_NOTE,
198
+ "Reasoning effort uses cursor.reasoningEffortModels; no standalone Cursor effort flag is emitted.",
199
+ "Trailing prompt text begins after the mode; a later --help is prompt text, "
200
+ "not a help request.",
201
+ ),
202
+ see_also=("codex", "droid", "kimi", "dry-run", "agent-help"),
203
+ ),
204
+ "kimi": CommandSpec(
205
+ name="kimi",
206
+ summary="Run Kimi Code CLI in safe, work, or stateless call mode.",
207
+ usage=(
208
+ "delegate [--json] [--isolation auto|none|worktree] "
209
+ "kimi {safe,work} [--reasoning-effort LEVEL] [--progress] "
210
+ "[--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
211
+ "delegate [--json] kimi call [--read-only] [--reasoning-effort LEVEL] "
212
+ "[--prompt-file PATH] [prompt...]",
213
+ ),
214
+ arguments=(_MODE_ARG, _PROMPT_ARG),
215
+ options=(
216
+ _REASONING_EFFORT_OPTION,
217
+ _PROGRESS_OPTION,
218
+ _NO_PROGRESS_OPTION,
219
+ _FORBID_COMMIT_OPTION,
220
+ _INCLUDE_DIRTY_OPTION,
221
+ _READ_ONLY_OPTION,
222
+ _PROMPT_FILE_OPTION,
223
+ ),
224
+ examples=(
225
+ 'delegate kimi work "Implement the scoped task; report changed files and tests."',
226
+ 'delegate kimi safe "Review this repo for regressions; report file/line/severity."',
227
+ "delegate kimi work --prompt-file task.md",
228
+ ),
229
+ notes=(
230
+ SAFE_WORKSPACE_SYNC_NOTE,
231
+ CALL_MODE_NOTE,
232
+ "Kimi safe mode also uses a read-only safety prompt.",
233
+ "work mode uses Kimi prompt mode; Delegate does not emit --yolo because "
234
+ "Kimi rejects combining --yolo with --prompt.",
235
+ "Model selection uses kimi.defaultModel in config or the run-input JSON model; "
236
+ "there is no CLI model alias.",
237
+ "Reasoning effort is unsupported for Kimi in v1.",
238
+ "Trailing prompt text begins after the mode; a later --help is prompt text, "
239
+ "not a help request.",
240
+ ),
241
+ see_also=("cursor", "codex", "droid", "dry-run", "agent-help"),
242
+ ),
243
+ "codex": CommandSpec(
244
+ name="codex",
245
+ summary="Run OpenAI Codex CLI in safe, work, or stateless call mode.",
246
+ usage=(
247
+ "delegate [--json] [--isolation auto|none|worktree] "
248
+ "codex {safe,work} [--reasoning-effort LEVEL] [--progress] "
249
+ "[--output-schema FILE] [--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
250
+ "delegate [--json] codex call [--read-only] [--reasoning-effort LEVEL] "
251
+ "[--output-schema FILE] [--prompt-file PATH] [prompt...]",
252
+ ),
253
+ arguments=(_MODE_ARG, _PROMPT_ARG),
254
+ options=(
255
+ _REASONING_EFFORT_OPTION,
256
+ _OUTPUT_SCHEMA_OPTION,
257
+ _PROGRESS_OPTION,
258
+ _NO_PROGRESS_OPTION,
259
+ _FORBID_COMMIT_OPTION,
260
+ _INCLUDE_DIRTY_OPTION,
261
+ _READ_ONLY_OPTION,
262
+ _PROMPT_FILE_OPTION,
263
+ ),
264
+ examples=(
265
+ 'delegate codex safe "Review this workspace. Do not edit files."',
266
+ 'delegate codex call --reasoning-effort high "Summarize this context."',
267
+ 'delegate codex work "Implement the scoped fix, run the named check, report changes."',
268
+ ),
269
+ notes=(
270
+ SAFE_WORKSPACE_SYNC_NOTE,
271
+ CALL_MODE_NOTE,
272
+ "Model selection uses codex.defaultModel in config or the run-input JSON model; "
273
+ "there is no CLI model alias.",
274
+ "Reasoning effort is validated against the resolved model and emitted as a Codex "
275
+ "config override; with no codex.defaultModel, explicit --reasoning-effort applies "
276
+ "to the Codex harness default model.",
277
+ "--output-schema resolves relative paths from the launch cwd and is native Codex "
278
+ "schema enforcement for the final message.",
279
+ "codex.profile is a Codex CLI config overlay; top-level profiles selects "
280
+ "Delegate-injected auth/env.",
281
+ ),
282
+ see_also=("cursor", "droid", "profiles", "models", "agent-help"),
283
+ ),
284
+ "claude": CommandSpec(
285
+ name="claude",
286
+ summary="Run Claude Code headless in safe, work, or stateless call mode.",
287
+ usage=(
288
+ "delegate [--json] [--isolation auto|none|worktree] "
289
+ "claude {safe,work} [--reasoning-effort LEVEL] [--progress] "
290
+ "[--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
291
+ "delegate [--json] claude call [--read-only] [--reasoning-effort LEVEL] "
292
+ "[--prompt-file PATH] [prompt...]",
293
+ ),
294
+ arguments=(_MODE_ARG, _PROMPT_ARG),
295
+ options=(
296
+ _REASONING_EFFORT_OPTION,
297
+ _PROGRESS_OPTION,
298
+ _NO_PROGRESS_OPTION,
299
+ _FORBID_COMMIT_OPTION,
300
+ _INCLUDE_DIRTY_OPTION,
301
+ _READ_ONLY_OPTION,
302
+ _PROMPT_FILE_OPTION,
303
+ ),
304
+ examples=(
305
+ 'delegate claude safe "Review this workspace. Do not edit files."',
306
+ 'delegate claude safe --reasoning-effort high "Review this workspace."',
307
+ 'delegate claude work "Implement the scoped fix, run the named check, report changes."',
308
+ ),
309
+ notes=(
310
+ "Uses Claude Code -p with prompt delivery on stdin; dry-run argv and run manifests "
311
+ "do not contain the prompt.",
312
+ SAFE_WORKSPACE_SYNC_NOTE,
313
+ CALL_MODE_NOTE,
314
+ "Claude safe mode runs with --permission-mode plan, "
315
+ "--strict-mcp-config, Read/Grep/Glob, and selected read-only Bash tools.",
316
+ "Claude safe mode is not hermetic: Delegate does not prove hooks, plugins, "
317
+ "user settings, output styles, or other non-MCP customization surfaces are disabled.",
318
+ "Work mode uses claude.workPermissionMode, unless Delegate policy explicitly "
319
+ "enables harness-scoped bypassApprovalsAndSandbox.",
320
+ "Reasoning effort maps to Claude Code --effort.",
321
+ ),
322
+ see_also=("cursor", "codex", "droid", "models", "agent-help"),
323
+ ),
324
+ "grok": CommandSpec(
325
+ name="grok",
326
+ summary="Run xAI Grok Build CLI in safe, work, or stateless call mode.",
327
+ usage=(
328
+ "delegate [--json] [--isolation auto|none|worktree] "
329
+ "grok {safe,work} [--reasoning-effort LEVEL] [--progress] "
330
+ "[--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
331
+ "delegate [--json] grok call [--read-only] [--reasoning-effort LEVEL] "
332
+ "[--prompt-file PATH] [prompt...]",
333
+ ),
334
+ arguments=(_MODE_ARG, _PROMPT_ARG),
335
+ options=(
336
+ _REASONING_EFFORT_OPTION,
337
+ _PROGRESS_OPTION,
338
+ _NO_PROGRESS_OPTION,
339
+ _FORBID_COMMIT_OPTION,
340
+ _INCLUDE_DIRTY_OPTION,
341
+ _READ_ONLY_OPTION,
342
+ _PROMPT_FILE_OPTION,
343
+ ),
344
+ examples=(
345
+ 'delegate grok safe "Review this workspace. Do not edit files."',
346
+ 'delegate grok safe --reasoning-effort high "Review this workspace."',
347
+ 'delegate grok work "Implement the scoped fix, run the named check, report changes."',
348
+ "delegate --isolation worktree grok work --forbid-commit "
349
+ '"Make the change without committing."',
350
+ ),
351
+ notes=(
352
+ "Prompt uses Delegate temp file via Grok --prompt-file; dry-run argv shows <prompt file>.",
353
+ SAFE_WORKSPACE_SYNC_NOTE,
354
+ CALL_MODE_NOTE,
355
+ "Tracked runs use --output-format streaming-json for snapshots/run-output; "
356
+ "pass-through uses plain.",
357
+ "Safe mode uses Delegate isolated copy plus Grok read-only sandbox/permission controls; "
358
+ "it does not use Grok plan mode.",
359
+ "Grok safe mode disables web search by default; explicit "
360
+ "policy.harness.grok.safe.webSearch=true re-enables network egress, and Delegate "
361
+ "safe-mode isolation is filesystem-only.",
362
+ "Work mode uses grok.workPermissionMode, unless Delegate policy explicitly "
363
+ "enables policy.harness.grok.work.bypassApprovalsAndSandbox.",
364
+ "Reasoning effort maps to Grok --effort (low, medium, high, xhigh, max).",
365
+ "--output-schema is unsupported in v1 because Grok --json-schema forces final json output.",
366
+ "The top-level grok engine is distinct from any Droid-served Grok model alias.",
367
+ ),
368
+ see_also=("cursor", "codex", "droid", "claude", "models", "agent-help"),
369
+ ),
370
+ "droid": CommandSpec(
371
+ name="droid",
372
+ summary="Run a Factory Droid BYOK model alias in safe, work, or stateless call mode.",
373
+ usage=(
374
+ "delegate [--json] [--isolation auto|none|worktree] "
375
+ "droid MODEL_ALIAS {safe,work} [--reasoning-effort LEVEL] [--progress] "
376
+ "[--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
377
+ "delegate [--json] droid MODEL_ALIAS call [--read-only] [--reasoning-effort LEVEL] "
378
+ "[--prompt-file PATH] [prompt...]",
379
+ ),
380
+ arguments=(
381
+ ArgSpec(
382
+ "MODEL_ALIAS",
383
+ True,
384
+ "A droid model alias from config (see delegate models).",
385
+ ),
386
+ _MODE_ARG,
387
+ _PROMPT_ARG,
388
+ ),
389
+ options=(
390
+ _REASONING_EFFORT_OPTION,
391
+ _PROGRESS_OPTION,
392
+ _NO_PROGRESS_OPTION,
393
+ _FORBID_COMMIT_OPTION,
394
+ _INCLUDE_DIRTY_OPTION,
395
+ _READ_ONLY_OPTION,
396
+ _PROMPT_FILE_OPTION,
397
+ ),
398
+ examples=(
399
+ 'delegate droid reviewer safe "Investigate this issue; do not edit."',
400
+ 'delegate droid reviewer work --reasoning-effort xhigh "Implement and verify."',
401
+ 'delegate droid reviewer work "Implement this bounded change; run the named check."',
402
+ ),
403
+ notes=(
404
+ SAFE_WORKSPACE_SYNC_NOTE,
405
+ CALL_MODE_NOTE,
406
+ "Droid safe mode stays read-only; work mode uses --skip-permissions-unsafe "
407
+ "and is intentionally no-prompt -- use only in workspaces you trust.",
408
+ "Reasoning effort is model-specific and never changes safe/work/call permissions.",
409
+ "--reasoning-effort requires a resolved Droid model alias from droid.models.",
410
+ "Run delegate models to list available aliases.",
411
+ ),
412
+ see_also=("models", "cursor", "codex", "agent-help"),
413
+ ),
414
+ "dry-run": CommandSpec(
415
+ name="dry-run",
416
+ summary="Resolve a cursor/codex/droid/kimi/claude/grok invocation and print the planned argv without running it.",
417
+ usage=(
418
+ "delegate [--json] [--isolation auto|none|worktree] "
419
+ "dry-run {cursor,kimi,claude,grok} {safe,work} [--reasoning-effort LEVEL] "
420
+ "[--progress] [--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
421
+ "delegate [--json] [--isolation auto|none|worktree] "
422
+ "dry-run {cursor,kimi,claude,grok} call [--read-only] [--reasoning-effort LEVEL] "
423
+ "[--prompt-file PATH] [prompt...]",
424
+ "delegate [--json] [--isolation auto|none|worktree] "
425
+ "dry-run codex {safe,work} [--reasoning-effort LEVEL] [--output-schema FILE] "
426
+ "[--progress] [--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
427
+ "delegate [--json] [--isolation auto|none|worktree] "
428
+ "dry-run codex call [--read-only] [--reasoning-effort LEVEL] [--output-schema FILE] "
429
+ "[--prompt-file PATH] [prompt...]",
430
+ "delegate [--json] [--isolation auto|none|worktree] "
431
+ "dry-run droid MODEL_ALIAS {safe,work} [--reasoning-effort LEVEL] "
432
+ "[--progress] [--forbid-commit] [--include-dirty] [--prompt-file PATH] [prompt...]",
433
+ "delegate [--json] [--isolation auto|none|worktree] "
434
+ "dry-run droid MODEL_ALIAS call [--read-only] [--reasoning-effort LEVEL] "
435
+ "[--prompt-file PATH] [prompt...]",
436
+ ),
437
+ arguments=(
438
+ ArgSpec("engine", True, "Engine to plan: cursor, codex, kimi, claude, grok, or droid."),
439
+ _PROMPT_ARG,
440
+ ),
441
+ options=(
442
+ _REASONING_EFFORT_OPTION,
443
+ _OUTPUT_SCHEMA_OPTION,
444
+ _PROGRESS_OPTION,
445
+ _NO_PROGRESS_OPTION,
446
+ _FORBID_COMMIT_OPTION,
447
+ _INCLUDE_DIRTY_OPTION,
448
+ _READ_ONLY_OPTION,
449
+ _PROMPT_FILE_OPTION,
450
+ ),
451
+ examples=(
452
+ 'delegate dry-run cursor work "Refactor the parser"',
453
+ "delegate --json dry-run droid reviewer safe --prompt-file task.md",
454
+ 'delegate dry-run grok safe "Review this repo."',
455
+ 'delegate dry-run claude safe "Review this repo."',
456
+ 'delegate dry-run kimi safe "Review this repo."',
457
+ ),
458
+ notes=(
459
+ "dry-run shares the full engine grammar but launches no child process.",
460
+ "--output-schema is accepted only for codex dry-runs.",
461
+ "Reasoning effort is resolved from config/cache/bundled capabilities without invoking child binaries.",
462
+ ),
463
+ see_also=("cursor", "codex", "droid", "kimi", "claude", "grok", "describe"),
464
+ ),
465
+ "run": CommandSpec(
466
+ name="run",
467
+ summary=(
468
+ "Launch a run from a JSON input file (engine, mode, model, cwd, prompt, isolation)."
469
+ ),
470
+ usage=("delegate [--json] [--isolation auto|none|worktree] run --input-json FILE",),
471
+ options=(
472
+ OptionSpec(
473
+ "--input-json",
474
+ "FILE",
475
+ "Path to a JSON file describing the run (required).",
476
+ ),
477
+ ),
478
+ examples=("delegate run --input-json task.json",),
479
+ notes=(
480
+ "Accepted JSON keys: engine, mode, model, cwd, prompt, isolation, "
481
+ "reasoningEffort, outputSchema, progress, forbidCommit.",
482
+ "Use this for long prompts or programmatic invocation.",
483
+ ),
484
+ see_also=("cursor", "codex", "droid", "claude", "grok", "agent-help"),
485
+ ),
486
+ "snapshot": CommandSpec(
487
+ name="snapshot",
488
+ summary="Print a bounded snapshot of a tracked run.",
489
+ usage=("delegate [--json] snapshot [--latest HARNESS] [--no-redact] <handle>",),
490
+ arguments=(
491
+ ArgSpec(
492
+ "<handle>",
493
+ False,
494
+ "Run ID, numbered alias, bare harness latest selector, or harness:modelAlias.",
495
+ ),
496
+ ),
497
+ options=(
498
+ OptionSpec(
499
+ "--latest",
500
+ "HARNESS",
501
+ f"Snapshot the most recent run for HARNESS ({ENGINES_PROSE}).",
502
+ ),
503
+ OptionSpec("--no-redact", None, "Do not redact secrets in the output."),
504
+ ),
505
+ examples=(
506
+ "delegate snapshot cursor-1",
507
+ "delegate snapshot cursor",
508
+ "delegate snapshot --latest codex",
509
+ ),
510
+ notes=(
511
+ "Provide either a handle or --latest HARNESS, not both.",
512
+ "Bare harness handles resolve to the latest run; generated commands use numbered aliases.",
513
+ ),
514
+ see_also=("runs", "run-output"),
515
+ unsupported_global_options=("--auth-profile",),
516
+ ),
517
+ "runs": CommandSpec(
518
+ name="runs",
519
+ summary="List tracked runs, optionally filtered by activity, recency, or harness.",
520
+ usage=(
521
+ "delegate [--json] runs [--active|--running|--stale|--recent] "
522
+ "[--harness HARNESS] [--group NAME] [--limit N]",
523
+ ),
524
+ options=(
525
+ OptionSpec(
526
+ "--active",
527
+ None,
528
+ "Show effective running and stale runs (back-compatible active view).",
529
+ ),
530
+ OptionSpec("--running", None, "Show only runs whose tracked process is still alive."),
531
+ OptionSpec("--stale", None, "Show only runs recorded as running but no longer live."),
532
+ OptionSpec("--recent", None, "Show only recent runs."),
533
+ OptionSpec(
534
+ "--harness",
535
+ "HARNESS",
536
+ f"Filter by harness: {ENGINES_PROSE}.",
537
+ ),
538
+ OptionSpec("--limit", "N", "Cap the number of runs listed (positive integer)."),
539
+ OptionSpec("--group", "NAME", "Filter by launch group."),
540
+ ),
541
+ examples=(
542
+ "delegate runs --active",
543
+ "delegate runs --running",
544
+ "delegate runs --stale",
545
+ "delegate runs --harness cursor --limit 5",
546
+ "delegate runs --group wave4",
547
+ ),
548
+ notes=("--active, --running, --stale, and --recent are mutually exclusive.",),
549
+ see_also=("snapshot", "run-output"),
550
+ unsupported_global_options=("--auth-profile",),
551
+ ),
552
+ "run-output": CommandSpec(
553
+ name="run-output",
554
+ summary="Inspect a tracked run's completion report or captured stdout/stderr.",
555
+ usage=(
556
+ "delegate [--json] run-output [--latest HARNESS] <handle> "
557
+ "[--completion-report] [--stdout] [--stderr] [--tail N] [--max-chars N] "
558
+ "[--raw] [--no-redact]",
559
+ ),
560
+ arguments=(
561
+ ArgSpec(
562
+ "<handle>",
563
+ True,
564
+ "Run ID, numbered alias, bare harness latest selector, or harness:modelAlias.",
565
+ ),
566
+ ),
567
+ options=(
568
+ OptionSpec(
569
+ "--latest",
570
+ "HARNESS",
571
+ f"Inspect the most recent run for HARNESS ({ENGINES_PROSE}); accepts harness:modelAlias.",
572
+ ),
573
+ OptionSpec("--completion-report", None, "Print the run's completion report."),
574
+ OptionSpec("--stdout", None, "Print captured stdout (defaults to --tail 80)."),
575
+ OptionSpec("--stderr", None, "Print captured stderr (defaults to --tail 80)."),
576
+ OptionSpec("--tail", "N", "Print only the last N lines of the selected stream."),
577
+ OptionSpec(
578
+ "--max-chars",
579
+ "N",
580
+ "Cap non-raw stdout/stderr output to the last N characters after tailing "
581
+ "(default 60000; incompatible with --raw).",
582
+ ),
583
+ OptionSpec(
584
+ "--raw",
585
+ None,
586
+ "Print the full stream unbounded (incompatible with --tail and --max-chars; "
587
+ "may be very large; JSON includes rawOutputBytes).",
588
+ ),
589
+ OptionSpec("--no-redact", None, "Do not redact secrets in the output."),
590
+ ),
591
+ examples=(
592
+ "delegate run-output cursor-1",
593
+ "delegate run-output --latest codex --completion-report",
594
+ "delegate run-output cursor --completion-report",
595
+ "delegate run-output cursor-1 --stderr --tail 100",
596
+ "delegate run-output cursor-1 --stdout --max-chars 20000",
597
+ ),
598
+ notes=(
599
+ "With no selector, prints the best available parent-facing output.",
600
+ "Bare harness handles resolve to the latest run; generated commands use numbered aliases.",
601
+ "Prefer this over piping launch output through tail.",
602
+ "Non-raw stdout/stderr are bounded by line tail and character cap; use --raw only "
603
+ "when you intentionally need the full stream.",
604
+ "--tail and --max-chars require --stdout or --stderr; completion reports reject them.",
605
+ ),
606
+ see_also=("snapshot", "runs"),
607
+ unsupported_global_options=("--auth-profile",),
608
+ ),
609
+ "wait": CommandSpec(
610
+ name="wait",
611
+ summary="Wait for tracked runs to finish and report terminal states.",
612
+ usage=(
613
+ "delegate [--json] wait <handle>... [--latest HARNESS] [--group NAME] "
614
+ "[--timeout SEC] [--interval SEC] [--completion-report]",
615
+ ),
616
+ arguments=(
617
+ ArgSpec(
618
+ "<handle>",
619
+ False,
620
+ "Run ID, numbered alias, bare harness latest selector, or harness:modelAlias.",
621
+ ),
622
+ ),
623
+ options=(
624
+ OptionSpec(
625
+ "--latest",
626
+ "HARNESS",
627
+ f"Also wait for the most recent run for HARNESS ({ENGINES_PROSE}); accepts harness:modelAlias.",
628
+ ),
629
+ OptionSpec("--timeout", "SEC", "Maximum wait in seconds (default 3600)."),
630
+ OptionSpec("--group", "NAME", "Wait for all runs tagged with this group."),
631
+ OptionSpec("--interval", "SEC", "Polling interval in seconds (default 3; min 1)."),
632
+ OptionSpec("--completion-report", None, "Append each run's completion report."),
633
+ ),
634
+ examples=(
635
+ "delegate wait codex-1 cursor-2",
636
+ "delegate wait --latest droid:glm --timeout 600 --interval 1",
637
+ "delegate wait --group wave4",
638
+ "delegate --json wait cursor --completion-report",
639
+ ),
640
+ notes=(
641
+ "Exit codes: 0 all succeeded; 1 any failed/cancelled; 124 timeout.",
642
+ "Dead recorded child pids are treated as terminal failures, not as hangs.",
643
+ ),
644
+ see_also=("runs", "snapshot", "run-output", "cancel"),
645
+ unsupported_global_options=("--auth-profile", "--isolation"),
646
+ ),
647
+ "cancel": CommandSpec(
648
+ name="cancel",
649
+ summary="Cancel tracked runs by signaling the recorded child process group.",
650
+ usage=("delegate [--json] cancel <handle>...",),
651
+ arguments=(
652
+ ArgSpec(
653
+ "<handle>",
654
+ True,
655
+ "Run ID, numbered alias, bare harness latest selector, or harness:modelAlias.",
656
+ ),
657
+ ),
658
+ examples=(
659
+ "delegate cancel cursor-1",
660
+ "delegate cancel droid:glm",
661
+ "delegate --json cancel codex-2",
662
+ ),
663
+ notes=(
664
+ "Refuses already-terminal runs.",
665
+ "Tracked launches record a process group; legacy runs without pgid fall back to pid with a warning.",
666
+ "call mode is untracked and therefore not cancellable.",
667
+ ),
668
+ see_also=("wait", "runs", "snapshot", "run-output"),
669
+ unsupported_global_options=("--auth-profile", "--isolation"),
670
+ ),
671
+ "profiles": CommandSpec(
672
+ name="profiles",
673
+ summary="Show the detected active auth/env profile and injected env keys.",
674
+ usage=("delegate [--cwd PATH] [--json] [--auth-profile NAME] profiles",),
675
+ examples=(
676
+ "delegate profiles",
677
+ "delegate --json --auth-profile work profiles",
678
+ ),
679
+ notes=(
680
+ "Selection is read-only: flag > profiles.detectFrom environment order > profiles.default.",
681
+ "Env values are key-aware redacted; inline profile env must not contain secrets.",
682
+ ),
683
+ see_also=("describe", "codex", "models"),
684
+ unsupported_global_options=(
685
+ "--isolation",
686
+ "--pass-through",
687
+ "--completion-report",
688
+ "--no-completion-report",
689
+ ),
690
+ ),
691
+ "config": CommandSpec(
692
+ name="config",
693
+ summary="Manage the user Delegate config file.",
694
+ usage=("delegate [--json] config <action>",),
695
+ arguments=(ArgSpec("action", True, "Currently: init, sync-profiles."),),
696
+ notes=(
697
+ "config init writes an editable starter config to ~/.delegate/config.json, "
698
+ "or to DELEGATE_CONFIG when that environment variable is set.",
699
+ "config sync-profiles writes missing config.work.json/config.personal.json overlays.",
700
+ "Run delegate config init --force to overwrite an existing base config.",
701
+ ),
702
+ see_also=("config init", "config sync-profiles", "profiles", "models", "describe"),
703
+ unsupported_global_options=(
704
+ "--cwd",
705
+ "--isolation",
706
+ "--auth-profile",
707
+ "--pass-through",
708
+ "--completion-report",
709
+ "--no-completion-report",
710
+ ),
711
+ ),
712
+ "config init": CommandSpec(
713
+ name="config init",
714
+ summary="Write an editable starter config file.",
715
+ usage=("delegate [--json] config init [--force]",),
716
+ options=(OptionSpec("--force", None, "Overwrite an existing config file."),),
717
+ examples=(
718
+ "delegate config init",
719
+ "delegate --json config init --force",
720
+ ),
721
+ notes=(
722
+ "The starter config includes placeholder Droid aliases and placeholder CODEX_HOME profile pointers.",
723
+ "It also writes missing config.work.json/config.personal.json profile overlays next to the base config.",
724
+ "Use POSIX paths inside WSL; convert Windows paths with wslpath before putting them in config.",
725
+ ),
726
+ see_also=("config", "config sync-profiles", "profiles", "models"),
727
+ unsupported_global_options=(
728
+ "--cwd",
729
+ "--isolation",
730
+ "--auth-profile",
731
+ "--pass-through",
732
+ "--completion-report",
733
+ "--no-completion-report",
734
+ ),
735
+ ),
736
+ "config sync-profiles": CommandSpec(
737
+ name="config sync-profiles",
738
+ summary="Write missing profile overlay config files.",
739
+ usage=("delegate [--json] config sync-profiles",),
740
+ examples=(
741
+ "delegate config sync-profiles",
742
+ "env -u AI_PROFILE delegate --json config sync-profiles",
743
+ ),
744
+ notes=(
745
+ "Creates missing config.work.json and config.personal.json next to the base config.",
746
+ "Existing profile overlay files are left untouched.",
747
+ "Each overlay pins profiles.default and carries that profile's CODEX_HOME pointer; secrets stay out of repo/config examples.",
748
+ ),
749
+ see_also=("config", "config init", "profiles"),
750
+ unsupported_global_options=(
751
+ "--cwd",
752
+ "--isolation",
753
+ "--auth-profile",
754
+ "--pass-through",
755
+ "--completion-report",
756
+ "--no-completion-report",
757
+ ),
758
+ ),
759
+ "worktree": CommandSpec(
760
+ name="worktree",
761
+ summary="Manage persistent isolation worktrees (list, show, remove, prune, gc).",
762
+ usage=(
763
+ "delegate [--cwd PATH] [--json] worktree list ...",
764
+ "delegate [--cwd PATH] [--json] worktree show ...",
765
+ "delegate [--cwd PATH] [--json] worktree remove ...",
766
+ "delegate [--cwd PATH] [--json] worktree prune ...",
767
+ "delegate [--cwd PATH] [--json] worktree gc ...",
768
+ ),
769
+ arguments=(
770
+ ArgSpec(
771
+ "action",
772
+ True,
773
+ "One of: list, show, remove, prune, gc.",
774
+ ),
775
+ ),
776
+ notes=(
777
+ "--isolation is not supported with worktree commands.",
778
+ "Run delegate worktree <action> --help for action-specific options.",
779
+ ),
780
+ see_also=(
781
+ "worktree list",
782
+ "worktree show",
783
+ "worktree remove",
784
+ "worktree prune",
785
+ "worktree gc",
786
+ ),
787
+ unsupported_global_options=("--isolation", "--auth-profile"),
788
+ ),
789
+ "worktree list": CommandSpec(
790
+ name="worktree list",
791
+ summary="List persistent worktrees, optionally filtered by harness or status.",
792
+ usage=(
793
+ "delegate [--cwd PATH] [--json] worktree list "
794
+ "[--harness HARNESS] [--group NAME] [--status STATUS] [--limit N] [--no-auto-prune]",
795
+ ),
796
+ options=(
797
+ OptionSpec("--harness", "HARNESS", f"Filter by harness ({ENGINES_PROSE})."),
798
+ OptionSpec("--group", "NAME", "Filter by launch group."),
799
+ OptionSpec(
800
+ "--status",
801
+ "STATUS",
802
+ "Filter by status: present, removed, missing, or unknown.",
803
+ ),
804
+ OptionSpec("--limit", "N", "Cap the number of worktrees listed (positive integer)."),
805
+ OptionSpec(
806
+ "--no-auto-prune",
807
+ None,
808
+ "Skip the implicit auto-prune pass before listing.",
809
+ ),
810
+ ),
811
+ examples=(
812
+ "delegate worktree list",
813
+ "delegate worktree list --harness cursor --status present",
814
+ ),
815
+ see_also=("worktree show", "worktree prune", "worktree gc"),
816
+ unsupported_global_options=("--isolation", "--auth-profile"),
817
+ ),
818
+ "worktree show": CommandSpec(
819
+ name="worktree show",
820
+ summary="Show details for one persistent worktree.",
821
+ usage=(
822
+ "delegate [--cwd PATH] [--json] worktree show <handle>",
823
+ "delegate [--cwd PATH] [--json] worktree show --latest HARNESS",
824
+ ),
825
+ arguments=(
826
+ ArgSpec(
827
+ "<handle>",
828
+ False,
829
+ "Worktree run ID, numbered alias, or bare harness latest-worktree selector.",
830
+ ),
831
+ ),
832
+ options=(
833
+ OptionSpec(
834
+ "--latest",
835
+ "HARNESS",
836
+ f"Show the most recent worktree for HARNESS ({ENGINES_PROSE}).",
837
+ ),
838
+ ),
839
+ examples=(
840
+ "delegate worktree show cursor-1",
841
+ "delegate worktree show cursor",
842
+ "delegate worktree show --latest droid",
843
+ ),
844
+ notes=(
845
+ "Provide either a handle or --latest HARNESS, not both.",
846
+ "Bare harness handles resolve to the latest persistent worktree, never a non-worktree run.",
847
+ ),
848
+ see_also=("worktree list", "worktree remove"),
849
+ unsupported_global_options=("--isolation", "--auth-profile"),
850
+ ),
851
+ "worktree remove": CommandSpec(
852
+ name="worktree remove",
853
+ summary="Remove one persistent worktree and, by default, its branch.",
854
+ usage=(
855
+ "delegate [--cwd PATH] [--json] worktree remove <handle|--group NAME> "
856
+ "[--discard-uncommitted] [--force-branch] [--force] [--keep-branch]",
857
+ ),
858
+ arguments=(
859
+ ArgSpec(
860
+ "<handle>",
861
+ True,
862
+ "Worktree run ID, numbered alias, or bare harness latest-worktree selector.",
863
+ ),
864
+ ),
865
+ options=(
866
+ OptionSpec(
867
+ "--group", "NAME", "Remove all persistent worktrees tagged with this group."
868
+ ),
869
+ OptionSpec(
870
+ "--discard-uncommitted",
871
+ None,
872
+ "Remove even if the worktree has uncommitted changes.",
873
+ ),
874
+ OptionSpec(
875
+ "--force-branch",
876
+ None,
877
+ "Remove the branch even if it is not fully merged.",
878
+ ),
879
+ OptionSpec("--force", None, "Force removal of the worktree and its branch."),
880
+ OptionSpec("--keep-branch", None, "Remove the worktree but keep its branch."),
881
+ ),
882
+ examples=(
883
+ "delegate worktree remove cursor-1",
884
+ "delegate worktree remove --group wave4 --discard-uncommitted",
885
+ "delegate worktree remove cursor-1 --keep-branch",
886
+ ),
887
+ notes=(
888
+ "--keep-branch is mutually exclusive with --force-branch and --force.",
889
+ "A --help token anywhere in the args prints help and removes nothing.",
890
+ ),
891
+ see_also=("worktree list", "worktree prune", "worktree gc"),
892
+ unsupported_global_options=("--isolation", "--auth-profile"),
893
+ ),
894
+ "worktree prune": CommandSpec(
895
+ name="worktree prune",
896
+ summary="Prune persistent worktrees matching age, merge, or harness criteria.",
897
+ usage=(
898
+ "delegate [--cwd PATH] [--json] worktree prune "
899
+ "[--merged] [--older-than DAYS] [--harness HARNESS] [--group NAME] [--include-detached] "
900
+ "[--dry-run] [--discard-uncommitted] [--force-branch] [--force]",
901
+ ),
902
+ options=(
903
+ OptionSpec("--merged", None, "Prune only worktrees whose branch is merged."),
904
+ OptionSpec(
905
+ "--older-than",
906
+ "DAYS",
907
+ "Prune only worktrees older than DAYS (non-negative integer).",
908
+ ),
909
+ OptionSpec(
910
+ "--harness",
911
+ "HARNESS",
912
+ f"Prune only the given harness ({ENGINES_PROSE}).",
913
+ ),
914
+ OptionSpec("--group", "NAME", "Prune only worktrees tagged with this group."),
915
+ OptionSpec(
916
+ "--include-detached",
917
+ None,
918
+ "Also prune detached worktrees (no tracking branch).",
919
+ ),
920
+ OptionSpec("--dry-run", None, "Report what would be pruned without removing anything."),
921
+ OptionSpec(
922
+ "--discard-uncommitted",
923
+ None,
924
+ "Prune even worktrees with uncommitted changes.",
925
+ ),
926
+ OptionSpec(
927
+ "--force-branch",
928
+ None,
929
+ "Remove branches even if not fully merged.",
930
+ ),
931
+ OptionSpec("--force", None, "Force removal of matched worktrees and their branches."),
932
+ ),
933
+ examples=(
934
+ "delegate worktree prune --merged",
935
+ "delegate worktree prune --older-than 7 --dry-run",
936
+ ),
937
+ notes=("Run with --dry-run first to preview the affected worktrees.",),
938
+ see_also=("worktree list", "worktree remove", "worktree gc"),
939
+ unsupported_global_options=("--isolation", "--auth-profile"),
940
+ ),
941
+ "worktree gc": CommandSpec(
942
+ name="worktree gc",
943
+ summary="Garbage-collect orphaned worktree metadata and stale registry entries.",
944
+ usage=("delegate [--cwd PATH] [--json] worktree gc [--dry-run]",),
945
+ options=(
946
+ OptionSpec(
947
+ "--dry-run", None, "Report what would be collected without changing anything."
948
+ ),
949
+ ),
950
+ examples=(
951
+ "delegate worktree gc",
952
+ "delegate worktree gc --dry-run",
953
+ ),
954
+ see_also=("worktree list", "worktree prune", "worktree remove"),
955
+ unsupported_global_options=("--isolation", "--auth-profile"),
956
+ ),
957
+ "models": CommandSpec(
958
+ name="models",
959
+ summary="List configured engines and model settings.",
960
+ usage=("delegate [--json] models [--summary]",),
961
+ options=(OptionSpec("--summary", None, "Emit a compact alias-centered inventory."),),
962
+ examples=(
963
+ "delegate models",
964
+ "delegate --json models",
965
+ "delegate --json models --summary",
966
+ ),
967
+ notes=(
968
+ "Discovery output applies best-effort credential scrubbing; model IDs and paths are shown verbatim.",
969
+ "Agent discovery should prefer --summary, then use raw output only when needed.",
970
+ ),
971
+ see_also=("describe", "cursor", "codex", "droid", "kimi", "claude"),
972
+ unsupported_global_options=("--auth-profile",),
973
+ ),
974
+ "capabilities": CommandSpec(
975
+ name="capabilities",
976
+ summary="Report reasoning-effort capabilities from config, workspace cache, and bundled fallback.",
977
+ usage=(
978
+ "delegate [--json] [--auth-profile NAME] capabilities",
979
+ "delegate [--json] [--auth-profile NAME] capabilities refresh",
980
+ ),
981
+ examples=(
982
+ "delegate --json capabilities",
983
+ "delegate capabilities refresh",
984
+ ),
985
+ notes=(
986
+ "Reporting does not invoke child binaries.",
987
+ "refresh may invoke child CLIs and writes .delegate/capabilities/reasoning.json in the workspace.",
988
+ ),
989
+ see_also=("models", "describe", "codex", "droid", "cursor"),
990
+ ),
991
+ "describe": CommandSpec(
992
+ name="describe",
993
+ summary="Print a machine-readable inventory of engines, modes, argv shapes, and policy.",
994
+ usage=("delegate [--json] describe [--summary]",),
995
+ options=(OptionSpec("--summary", None, "Emit a compact command/config surface summary."),),
996
+ examples=(
997
+ "delegate describe",
998
+ "delegate --json describe",
999
+ "delegate --json describe --summary",
1000
+ ),
1001
+ notes=(
1002
+ "--json describe is the full detailed surface.",
1003
+ "Discovery output applies best-effort credential scrubbing.",
1004
+ "Agent discovery should start with --summary, then use raw describe only when needed.",
1005
+ ),
1006
+ see_also=("models", "agent-help", "help"),
1007
+ unsupported_global_options=("--auth-profile",),
1008
+ ),
1009
+ "agent-help": CommandSpec(
1010
+ name="agent-help",
1011
+ summary="Print best-practices guidance for agents driving delegate.",
1012
+ usage=("delegate agent-help",),
1013
+ examples=("delegate agent-help",),
1014
+ see_also=("describe", "help"),
1015
+ unsupported_global_options=("--auth-profile",),
1016
+ ),
1017
+ "help": CommandSpec(
1018
+ name="help",
1019
+ summary="Show the overview, or focused help for a command path.",
1020
+ usage=(
1021
+ "delegate help",
1022
+ "delegate help <command> [<subcommand>]",
1023
+ "delegate --json help [<command> [<subcommand>]]",
1024
+ ),
1025
+ arguments=(
1026
+ ArgSpec(
1027
+ "command",
1028
+ False,
1029
+ "Command path to describe (e.g. cursor, worktree remove). Omit for the overview.",
1030
+ ),
1031
+ ),
1032
+ examples=(
1033
+ "delegate help",
1034
+ "delegate help worktree prune",
1035
+ "delegate --json help cursor",
1036
+ ),
1037
+ notes=(
1038
+ "<command> --help and -h are equivalent to delegate help <command>.",
1039
+ "A --json token anywhere in the help arguments selects JSON output.",
1040
+ ),
1041
+ see_also=("describe", "agent-help"),
1042
+ unsupported_global_options=("--auth-profile",),
1043
+ ),
1044
+ }
1045
+
1046
+
1047
+ # --------------------------------------------------------------------------- #
1048
+ # Help-token detection.
1049
+ # --------------------------------------------------------------------------- #
1050
+
1051
+
1052
+ def is_help_token(tok: str) -> bool:
1053
+ """True only for the literal help tokens ``--help`` and ``-h``."""
1054
+
1055
+ return tok in ("--help", "-h")
1056
+
1057
+
1058
+ # --------------------------------------------------------------------------- #
1059
+ # Text renderers.
1060
+ # --------------------------------------------------------------------------- #
1061
+
1062
+
1063
+ def _format_option(opt: OptionSpec) -> str:
1064
+ return f"{opt.flag} {opt.arg}" if opt.arg else opt.flag
1065
+
1066
+
1067
+ def render_command_help_text(spec: CommandSpec, *, prog: str = "delegate") -> str:
1068
+ """Render focused, human-readable help for one command spec."""
1069
+
1070
+ lines: list[str] = [f"{prog} {spec.name} -- {spec.summary}", ""]
1071
+
1072
+ lines.append("Usage:")
1073
+ for usage in spec.usage:
1074
+ lines.append(f" {usage}")
1075
+
1076
+ if spec.arguments:
1077
+ lines.append("")
1078
+ lines.append("Arguments:")
1079
+ width = max(len(arg.name) for arg in spec.arguments)
1080
+ for arg in spec.arguments:
1081
+ tag = "required" if arg.required else "optional"
1082
+ lines.append(f" {arg.name.ljust(width)} {arg.description} ({tag})")
1083
+
1084
+ if spec.options:
1085
+ lines.append("")
1086
+ lines.append("Options:")
1087
+ rendered = [(_format_option(opt), opt.description) for opt in spec.options]
1088
+ width = max(len(label) for label, _ in rendered)
1089
+ for label, description in rendered:
1090
+ lines.append(f" {label.ljust(width)} {description}")
1091
+
1092
+ lines.append("")
1093
+ lines.append("Global options (before the subcommand):")
1094
+ unsupported_globals = set(spec.unsupported_global_options)
1095
+ rendered_globals = [
1096
+ (_format_option(opt), opt.description)
1097
+ for opt in GLOBAL_OPTIONS
1098
+ if opt.flag not in unsupported_globals
1099
+ ]
1100
+ width = max(len(label) for label, _ in rendered_globals)
1101
+ for label, description in rendered_globals:
1102
+ lines.append(f" {label.ljust(width)} {description}")
1103
+
1104
+ if spec.examples:
1105
+ lines.append("")
1106
+ lines.append("Examples:")
1107
+ for example in spec.examples:
1108
+ lines.append(f" {example}")
1109
+
1110
+ if spec.notes:
1111
+ lines.append("")
1112
+ lines.append("Notes:")
1113
+ for note in spec.notes:
1114
+ lines.append(f" - {note}")
1115
+
1116
+ if spec.see_also:
1117
+ lines.append("")
1118
+ lines.append(f"See also: {', '.join(spec.see_also)}")
1119
+
1120
+ return "\n".join(lines) + "\n"
1121
+
1122
+
1123
+ def render_overview_text() -> str:
1124
+ """Render the global usage/help body that replaces the hand-written ``HELP``.
1125
+
1126
+ Worktree actions are enumerated on their own lines (``worktree prune ...``)
1127
+ so the overview contains the literal substring ``worktree prune``.
1128
+ """
1129
+
1130
+ iso = "[--isolation auto|none|worktree]"
1131
+ lines: list[str] = [f"delegate {VERSION}", "", "Usage:"]
1132
+
1133
+ usage_lines = [
1134
+ f"delegate [--cwd PATH] [--json] {iso} cursor {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1135
+ f"delegate [--cwd PATH] [--json] {iso} cursor call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1136
+ f"delegate [--cwd PATH] [--json] {iso} droid MODEL_ALIAS {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1137
+ f"delegate [--cwd PATH] [--json] {iso} droid MODEL_ALIAS call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1138
+ f"delegate [--cwd PATH] [--json] {iso} codex {{safe,work}} [--reasoning-effort LEVEL] [--output-schema FILE] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1139
+ f"delegate [--cwd PATH] [--json] {iso} codex call [--read-only] [--reasoning-effort LEVEL] [--output-schema FILE] [--prompt-file PATH] [prompt...]",
1140
+ f"delegate [--cwd PATH] [--json] {iso} claude {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1141
+ f"delegate [--cwd PATH] [--json] {iso} claude call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1142
+ f"delegate [--cwd PATH] [--json] {iso} grok {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1143
+ f"delegate [--cwd PATH] [--json] {iso} grok call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1144
+ f"delegate [--cwd PATH] [--json] {iso} kimi {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1145
+ f"delegate [--cwd PATH] [--json] {iso} kimi call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1146
+ f"delegate [--cwd PATH] [--json] {iso} dry-run cursor {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1147
+ f"delegate [--cwd PATH] [--json] {iso} dry-run cursor call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1148
+ f"delegate [--cwd PATH] [--json] {iso} dry-run droid MODEL_ALIAS {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1149
+ f"delegate [--cwd PATH] [--json] {iso} dry-run droid MODEL_ALIAS call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1150
+ f"delegate [--cwd PATH] [--json] {iso} dry-run codex {{safe,work}} [--reasoning-effort LEVEL] [--output-schema FILE] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1151
+ f"delegate [--cwd PATH] [--json] {iso} dry-run codex call [--read-only] [--reasoning-effort LEVEL] [--output-schema FILE] [--prompt-file PATH] [prompt...]",
1152
+ f"delegate [--cwd PATH] [--json] {iso} dry-run claude {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1153
+ f"delegate [--cwd PATH] [--json] {iso} dry-run claude call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1154
+ f"delegate [--cwd PATH] [--json] {iso} dry-run grok {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1155
+ f"delegate [--cwd PATH] [--json] {iso} dry-run grok call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1156
+ f"delegate [--cwd PATH] [--json] {iso} dry-run kimi {{safe,work}} [--reasoning-effort LEVEL] [--progress] [--forbid-commit] [--prompt-file PATH] [prompt...]",
1157
+ f"delegate [--cwd PATH] [--json] {iso} dry-run kimi call [--read-only] [--reasoning-effort LEVEL] [--prompt-file PATH] [prompt...]",
1158
+ f"delegate [--cwd PATH] [--json] {iso} run --input-json FILE",
1159
+ "delegate [--cwd PATH] [--json] snapshot [--latest HARNESS] [--no-redact] <handle>",
1160
+ "delegate [--cwd PATH] [--json] runs "
1161
+ "[--active|--running|--stale|--recent] [--harness HARNESS] [--limit N]",
1162
+ "delegate [--cwd PATH] [--json] run-output <handle> "
1163
+ "[--completion-report] [--stdout] [--stderr] [--tail N] [--max-chars N] "
1164
+ "[--raw] [--no-redact]",
1165
+ "delegate [--cwd PATH] [--json] wait <handle>... [--latest HARNESS] "
1166
+ "[--timeout SEC] [--interval SEC] [--completion-report]",
1167
+ "delegate [--cwd PATH] [--json] cancel <handle>...",
1168
+ "delegate [--cwd PATH] [--json] worktree list "
1169
+ "[--harness HARNESS] [--status STATUS] [--limit N] [--no-auto-prune]",
1170
+ "delegate [--cwd PATH] [--json] worktree show <handle>",
1171
+ "delegate [--cwd PATH] [--json] worktree show --latest HARNESS",
1172
+ "delegate [--cwd PATH] [--json] worktree remove <handle> "
1173
+ "[--discard-uncommitted] [--force-branch] [--force] [--keep-branch]",
1174
+ "delegate [--cwd PATH] [--json] worktree prune "
1175
+ "[--merged] [--older-than DAYS] [--harness HARNESS] [--include-detached] [--dry-run] "
1176
+ "[--discard-uncommitted] [--force-branch] [--force]",
1177
+ "delegate [--cwd PATH] [--json] worktree gc [--dry-run]",
1178
+ "delegate [--cwd PATH] [--json] [--auth-profile NAME] profiles",
1179
+ "delegate [--json] models [--summary]",
1180
+ "delegate [--json] capabilities [refresh]",
1181
+ "delegate [--json] describe [--summary]",
1182
+ "delegate agent-help",
1183
+ "delegate help [<command> [<subcommand>]]",
1184
+ ]
1185
+ for usage in usage_lines:
1186
+ lines.append(f" {usage}")
1187
+
1188
+ lines.append("")
1189
+ lines.append("Global options must appear before the subcommand.")
1190
+
1191
+ lines.append("")
1192
+ lines.append("Run output options (before subcommand):")
1193
+ detail_globals = (
1194
+ "--pass-through",
1195
+ "--completion-report",
1196
+ "--no-completion-report",
1197
+ )
1198
+ for opt in GLOBAL_OPTIONS:
1199
+ if opt.flag not in detail_globals:
1200
+ continue
1201
+ label = _format_option(opt)
1202
+ lines.append(f" {label.ljust(26)} {opt.description}")
1203
+
1204
+ lines.append("")
1205
+ lines.append("Discovery:")
1206
+ lines.append(" delegate help <command> Focused help for any command path.")
1207
+ lines.append(" delegate --json <command> --help Machine-readable spec for an agent.")
1208
+ lines.append(" delegate --json describe --summary Compact command/config surface inventory.")
1209
+ lines.append(" delegate --json models --summary Compact model inventory.")
1210
+ lines.append(" delegate agent-help Full agent guidance.")
1211
+
1212
+ lines.append("")
1213
+ lines.append(
1214
+ "Tracked runs return bounded summaries by default. Avoid piping launches through tail;"
1215
+ )
1216
+ lines.append("inspect runs with delegate snapshot, delegate runs, and delegate run-output.")
1217
+
1218
+ return "\n".join(lines) + "\n"
1219
+
1220
+
1221
+ # --------------------------------------------------------------------------- #
1222
+ # JSON payloads.
1223
+ # --------------------------------------------------------------------------- #
1224
+
1225
+
1226
+ def _option_payload(opt: OptionSpec) -> JsonObject:
1227
+ return {"flag": opt.flag, "argument": opt.arg, "description": opt.description}
1228
+
1229
+
1230
+ def _argument_payload(arg: ArgSpec) -> JsonObject:
1231
+ return {"name": arg.name, "required": arg.required, "description": arg.description}
1232
+
1233
+
1234
+ def command_help_payload(spec: CommandSpec) -> JsonObject:
1235
+ """Return the stable, agent-facing JSON help contract for one command (D4)."""
1236
+
1237
+ unsupported = set(spec.unsupported_global_options)
1238
+ return {
1239
+ "ok": True,
1240
+ "command": spec.name,
1241
+ "summary": spec.summary,
1242
+ "usage": list(spec.usage),
1243
+ "arguments": [_argument_payload(arg) for arg in spec.arguments],
1244
+ "options": [_option_payload(opt) for opt in spec.options],
1245
+ "globalOptions": [
1246
+ _option_payload(opt) for opt in GLOBAL_OPTIONS if opt.flag not in unsupported
1247
+ ],
1248
+ "unsupportedGlobalOptions": list(spec.unsupported_global_options),
1249
+ "examples": list(spec.examples),
1250
+ "notes": list(spec.notes),
1251
+ "seeAlso": list(spec.see_also),
1252
+ }
1253
+
1254
+
1255
+ def help_index_payload() -> JsonObject:
1256
+ """Return the overview JSON: command catalog plus global options."""
1257
+
1258
+ return {
1259
+ "ok": True,
1260
+ "commands": [
1261
+ {"command": spec.name, "summary": spec.summary} for spec in COMMAND_SPECS.values()
1262
+ ],
1263
+ "globalOptions": [_option_payload(opt) for opt in GLOBAL_OPTIONS],
1264
+ }