delegate-agent-cli 0.24.0__tar.gz → 0.25.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/CHANGELOG.md +50 -0
  2. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/PKG-INFO +1 -1
  3. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/bin/delegate-profile-shim +1 -1
  4. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/config.example.json +3 -0
  5. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/cli-reference.md +41 -1
  6. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/configuration.md +24 -0
  7. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/delegate-workflows.md +16 -4
  8. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/security-model.md +25 -0
  9. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/pyproject.toml +1 -1
  10. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/__init__.py +1 -1
  11. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/argv_builders.py +5 -7
  12. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/cli.py +56 -1
  13. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/cli_parser.py +103 -1
  14. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/command_help.py +63 -1
  15. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/config.py +17 -0
  16. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/constants.py +13 -1
  17. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/describe_payload.py +27 -2
  18. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/harness_discovery.py +60 -1
  19. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/isolation.py +6 -0
  20. delegate_agent_cli-0.25.0/src/delegate_agent/personas.py +199 -0
  21. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/profile_guard.py +1 -0
  22. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/prompt_instructions.py +7 -0
  23. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/prompt_transport.py +6 -0
  24. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/request_build.py +443 -63
  25. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/request_models.py +33 -0
  26. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/resume_command.py +61 -2
  27. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/run_metadata.py +8 -0
  28. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/run_registry.py +1 -0
  29. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/run_status.py +5 -0
  30. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/runner.py +47 -1
  31. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/snapshot_view.py +5 -0
  32. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/runtime.py +110 -11
  33. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_execution.py +64 -20
  34. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/PKG-INFO +1 -1
  35. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +12 -0
  36. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_command_help.py +1 -0
  37. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_engine_argv.py +18 -8
  38. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_execution_argv_and_prompt.py +11 -1
  39. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_harness_discovery.py +17 -0
  40. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_kimi_commands.py +5 -2
  41. delegate_agent_cli-0.25.0/tests/test_persona_capability.py +214 -0
  42. delegate_agent_cli-0.25.0/tests/test_persona_claude.py +87 -0
  43. delegate_agent_cli-0.25.0/tests/test_persona_contract.py +79 -0
  44. delegate_agent_cli-0.25.0/tests/test_persona_framer.py +454 -0
  45. delegate_agent_cli-0.25.0/tests/test_persona_opencode.py +146 -0
  46. delegate_agent_cli-0.25.0/tests/test_persona_parser.py +176 -0
  47. delegate_agent_cli-0.25.0/tests/test_persona_records.py +574 -0
  48. delegate_agent_cli-0.25.0/tests/test_persona_resolution.py +300 -0
  49. delegate_agent_cli-0.25.0/tests/test_persona_size_guard.py +185 -0
  50. delegate_agent_cli-0.25.0/tests/test_persona_validation.py +107 -0
  51. delegate_agent_cli-0.25.0/tests/test_persona_workflow.py +445 -0
  52. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_attachment.py +4 -0
  53. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_size_guard.py +24 -25
  54. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_workflow_commands.py +7 -3
  55. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/CONTRIBUTING.md +0 -0
  56. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/LICENSE +0 -0
  57. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/MANIFEST.in +0 -0
  58. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/README.md +0 -0
  59. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/SECURITY.md +0 -0
  60. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/bin/delegate.py +0 -0
  61. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/agent-setup.md +0 -0
  62. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/assets/delegate-agent-header.png +0 -0
  63. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/development.md +0 -0
  64. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/live-runtime.md +0 -0
  65. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/publishing-checklist.md +0 -0
  66. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/troubleshooting.md +0 -0
  67. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/docs/worktrees.md +0 -0
  68. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.claude.json +0 -0
  69. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.codex.json +0 -0
  70. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.cursor.json +0 -0
  71. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.droid.json +0 -0
  72. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.grok.json +0 -0
  73. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.judge.json +0 -0
  74. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/examples/task.kimi.json +0 -0
  75. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/setup.cfg +0 -0
  76. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/archived_logs.py +0 -0
  77. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/argv_utils.py +0 -0
  78. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/bundled_models.py +0 -0
  79. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/capability_commands.py +0 -0
  80. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/child_failures.py +0 -0
  81. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/command_errors.py +0 -0
  82. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/config_commands.py +0 -0
  83. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/errors.py +0 -0
  84. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/git_utils.py +0 -0
  85. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/harness_events.py +0 -0
  86. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/inspection_commands.py +0 -0
  87. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/json_types.py +0 -0
  88. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/log_output.py +0 -0
  89. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/model_discovery.py +0 -0
  90. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/private_io.py +0 -0
  91. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/profile_commands.py +0 -0
  92. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/profiles.py +0 -0
  93. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/reasoning.py +0 -0
  94. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/redaction.py +0 -0
  95. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/rendering.py +0 -0
  96. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/retention.py +0 -0
  97. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/run_output_commands.py +0 -0
  98. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/safe_workspace.py +0 -0
  99. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/seatbelt.py +0 -0
  100. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/setup_commands.py +0 -0
  101. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/structured_output.py +0 -0
  102. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/wait_cancel_commands.py +0 -0
  103. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/__init__.py +0 -0
  104. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/commands.py +0 -0
  105. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/registry.py +0 -0
  106. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/schema.py +0 -0
  107. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/workflows/script.py +0 -0
  108. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_commands.py +0 -0
  109. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_gc.py +0 -0
  110. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_mgmt.py +0 -0
  111. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_records.py +0 -0
  112. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_remove.py +0 -0
  113. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/worktree_summary.py +0 -0
  114. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent/wsl.py +0 -0
  115. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
  116. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
  117. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/requires.txt +0 -0
  118. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
  119. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_capability_commands.py +0 -0
  120. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_child_failures.py +0 -0
  121. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_codex_pure_sandbox.py +0 -0
  122. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_codex_thread_resilience.py +0 -0
  123. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_config_commands.py +0 -0
  124. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_delegate_help_cli.py +0 -0
  125. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_delegate_isolation.py +0 -0
  126. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_delegate_parser.py +0 -0
  127. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_delegate_validation.py +0 -0
  128. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_end_to_end_tracking.py +0 -0
  129. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_execution_dry_run.py +0 -0
  130. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_execution_worktree_failure_cleanup.py +0 -0
  131. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_execution_worktree_preflight.py +0 -0
  132. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_execution_worktree_run.py +0 -0
  133. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_harness_events.py +0 -0
  134. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_inspection_commands.py +0 -0
  135. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_model_discovery.py +0 -0
  136. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_model_selection_wave1a.py +0 -0
  137. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_model_selection_wave1b.py +0 -0
  138. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_omp_read_only_behavior.py +0 -0
  139. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_packaging.py +0 -0
  140. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_profiles.py +0 -0
  141. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_pure_call.py +0 -0
  142. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_reasoning_capabilities.py +0 -0
  143. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_capture.py +0 -0
  144. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_inheritance.py +0 -0
  145. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_parser.py +0 -0
  146. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_projections.py +0 -0
  147. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_refusals.py +0 -0
  148. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_stale.py +0 -0
  149. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_resume_trust.py +0 -0
  150. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_retention.py +0 -0
  151. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_run_registry.py +0 -0
  152. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_runner_capture.py +0 -0
  153. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_safe_workspace_isolation.py +0 -0
  154. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_setup_commands.py +0 -0
  155. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_slash_passthrough.py +0 -0
  156. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_snapshot_redaction.py +0 -0
  157. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_snapshot_rendering.py +0 -0
  158. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_snapshot_run_output.py +0 -0
  159. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_snapshot_view.py +0 -0
  160. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_structured_output.py +0 -0
  161. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_tracked_timeout.py +0 -0
  162. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_utility_modules.py +0 -0
  163. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_wait_cancel_commands.py +0 -0
  164. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_wave4_launch_features.py +0 -0
  165. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_worktree_list_show.py +0 -0
  166. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_worktree_prune_gc.py +0 -0
  167. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_worktree_remove.py +0 -0
  168. {delegate_agent_cli-0.24.0 → delegate_agent_cli-0.25.0}/tests/test_wsl_guardrails.py +0 -0
@@ -5,6 +5,55 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.25.0] - 2026-08-01
11
+
12
+ ### Added
13
+
14
+ - Named personas: `--persona` / `--no-persona` / `--allow-repo-persona` on
15
+ every engine's safe/work launch (and dry-run), input-json `persona` /
16
+ `allowRepoPersona` keys, and workflow `agent(persona=...)` with the resolved
17
+ persona digest pinned into the structural cache key so an edited persona is
18
+ a cache miss by design.
19
+ - `delegate personas [--json]` listing (schema `delegate.personas.v1`) with
20
+ workspace-shadowing metadata and per-file invalid rows; read-only allowlisted
21
+ in both the profile guard and the shell shim.
22
+ - Persona transports: claude work uses `--append-system-prompt-file` with a
23
+ private 0600 file when discovery positively proves current support (probe
24
+ recognizes both the long and the collapsed `--append-system-prompt[-file]`
25
+ help spellings); opencode merges a synthetic `delegate-persona` agent into
26
+ the effective config without clobbering profile keys; every other engine
27
+ prepends. Safe mode always prepends, with the persona placed before the
28
+ safe policy so the safety text keeps recency.
29
+ - `persona.txt` as a private durable run artifact with manifest, snapshot,
30
+ and runs-summary projection; resume replays recorded persona bytes through
31
+ the target engine's transport, `--persona` re-resolves, `--no-persona`
32
+ drops.
33
+
34
+ ### Changed
35
+
36
+ - The central framer is now the sole prompt composer: cursor/droid/kimi argv
37
+ builders no longer self-prefix safe policy text, user and persona bytes are
38
+ joined verbatim, and persistent/attached worktree notes are tracked
39
+ structurally on the request rather than inferred from prompt content.
40
+ - Slash-passthrough prompts on persistent or attached worktree runs carry the
41
+ Delegate-owned worktree and forbid-commit notes ahead of the slash command,
42
+ matching v0.24.0 behavior; all other slash payloads remain byte-verbatim.
43
+
44
+ ### Security
45
+
46
+ - Persona resolution walks `.delegate/personas` component-by-component over
47
+ `O_NOFOLLOW` descriptors anchored at the source workspace or home, refusing
48
+ symlinked parents and leaves; strict UTF-8, C0 refusal, and a 64 KiB cap.
49
+ - Resume persona replay reads only the fixed `persona.txt` artifact with a
50
+ required, verified sha256 digest; manifest data cannot redirect the read.
51
+ - The claude native persona gate fails closed: probe errors, timeouts, and
52
+ unrecognized banners fall back to prepend so an older binary never receives
53
+ an unknown flag. Dry-run never probes.
54
+ - Workflow persona digests travel across the child seam and both sides fail
55
+ closed on mismatch without caching.
56
+
8
57
  ## [0.24.0] - 2026-07-31
9
58
 
10
59
  ### Added
@@ -783,6 +832,7 @@ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week o
783
832
 
784
833
  - Releases before 0.1.3 predate this changelog.
785
834
 
835
+ [0.25.0]: https://github.com/treygoff24/delegate-agent/compare/v0.24.0...v0.25.0
786
836
  [0.24.0]: https://github.com/treygoff24/delegate-agent/compare/v0.23.0...v0.24.0
787
837
  [0.23.0]: https://github.com/treygoff24/delegate-agent/compare/v0.22.0...v0.23.0
788
838
  [0.22.0]: https://github.com/treygoff24/delegate-agent/compare/v0.21.0...v0.22.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: delegate-agent-cli
3
- Version: 0.24.0
3
+ Version: 0.25.0
4
4
  Summary: A tiny CLI for delegating bounded agent tasks across coding-agent runtimes.
5
5
  Author: Trey Goff
6
6
  License-Expression: MIT
@@ -134,7 +134,7 @@ _delegate_is_readonly_request() {
134
134
  esac
135
135
  done
136
136
  case "$_cmd" in
137
- profiles|runs|ps|run-output|describe|snapshot|agent-help|help|--help|-h|--version)
137
+ profiles|runs|ps|run-output|describe|snapshot|agent-help|personas|help|--help|-h|--version)
138
138
  return 0
139
139
  ;;
140
140
  models)
@@ -8,6 +8,9 @@
8
8
  "rawLogDays": 7
9
9
  }
10
10
  },
11
+ "personas": {
12
+ "forceTransport": null
13
+ },
11
14
  "cursor": {
12
15
  "argvPrefix": [
13
16
  "agent"
@@ -15,6 +15,46 @@ Use `delegate --help` for the exact command list from the installed version. Glo
15
15
  --group NAME Tag a launch/run-input request with a lightweight group ([A-Za-z0-9._-]{1,64}).
16
16
  ```
17
17
 
18
+ ## Personas
19
+
20
+ Named personas are UTF-8 Markdown files resolved from the source workspace:
21
+ `.delegate/personas/<name>.md` shadows `~/.delegate/personas/<name>.md`. Names
22
+ must match `[A-Za-z0-9][A-Za-z0-9._-]{0,63}`; files are regular, non-symlink
23
+ files no larger than 64 KiB and are rejected on invalid UTF-8 or disallowed C0
24
+ controls. The workspace-local directory is not VCS-shared by default; teams
25
+ that intentionally version a persona must force-add that individual file.
26
+
27
+ ```bash
28
+ delegate personas
29
+ delegate --json personas
30
+ delegate claude work --persona editor "Review chapter 3"
31
+ delegate codex safe --persona editor --allow-repo-persona "Review the diff"
32
+ delegate resume --persona editor <handle> "Continue with the requested fixes"
33
+ delegate resume --no-persona <handle> "Continue without the recorded persona"
34
+ ```
35
+
36
+ `--persona NAME`, `--no-persona`, and `--allow-repo-persona` are shared launch
37
+ options. A workspace-local persona is refused in safe mode unless explicitly
38
+ allowed. Resolution logs `persona: NAME (workspace|global)` to stderr. Personas
39
+ are not accepted for call, read-only call, `--pass-through`, or slash-passthrough
40
+ prompts. Input JSON uses `persona` (string or null) and `allowRepoPersona`
41
+ (boolean).
42
+
43
+ `delegate --json personas` returns schema `delegate.personas.v1` with sorted rows
44
+ containing `name`, `source`, `sizeBytes`, and an escaped bounded `preview`.
45
+ Invalid files remain visible with an `invalid` reason; a workspace row that
46
+ shadows a global row also includes `shadowsGlobal: true`.
47
+
48
+ Work-mode transport is prepend for most engines, Claude native-file only when
49
+ the discovery cache proves `--append-system-prompt-file` (otherwise prepend
50
+ with a warning), and OpenCode agent-config merge. OpenCode preserves existing
51
+ root keys, agent keys, and prompts, appending the persona after an existing
52
+ agent prompt. Safe mode always prepends. Claude native-file keeps the persona
53
+ body out of argv, dry-run JSON, and the manifest; prepend engines using argv
54
+ transport (Cursor, Kimi, and Oh My Pi) expose it in the live process argv.
55
+ Tracked runs retain it only in the private
56
+ `persona.txt` artifact.
57
+
18
58
  ## Commands
19
59
 
20
60
  ### Direct runtime commands
@@ -420,7 +460,7 @@ delegate [--json] workflow save <script.py> --name NAME
420
460
  - `run` launches a detached supervisor; `--dry-run` renders planned stubs
421
461
  without launching child agents or consuming real budget. Each entry in
422
462
  `runTree.calls` includes the resolved `model`, `effort`, `fast`, `isolation`,
423
- and UTF-8 `promptBytes`; Cursor/Kimi prompts over 102400 bytes add a warning
463
+ and UTF-8 `promptBytes`; Cursor/Kimi/OMP prompts over 102400 bytes add a warning
424
464
  before their argv transport limit can fail a real run.
425
465
  - `--resume` replays the journal, adopts matching child runs by workflow agent
426
466
  key, and continues from missing work.
@@ -201,6 +201,30 @@ reasoning defaults.
201
201
 
202
202
  ## Sections
203
203
 
204
+ ### `personas`
205
+
206
+ Persona files are workspace-local by design, not VCS-shared configuration:
207
+ `.delegate/personas/*.md` shadows the same name under
208
+ `~/.delegate/personas/`. The `delegate personas` command lists both scopes
209
+ without exposing persona bodies in JSON previews. Because `.delegate` is
210
+ normally excluded, teams that intentionally version a persona must force-add
211
+ the individual file; the resolution scope remains workspace-local.
212
+
213
+ ```json
214
+ {
215
+ "personas": {
216
+ "forceTransport": null
217
+ }
218
+ }
219
+ ```
220
+
221
+ `forceTransport` is optional and accepts `null`, `prepend`, `native-file`, or
222
+ `agent-config`. It is an explicit transport pin, not a capability probe;
223
+ `native-file` is appropriate only when the configured Claude binary supports
224
+ `--append-system-prompt-file`, and `agent-config` is meaningful for OpenCode.
225
+ Safe mode never uses native persona channels. A workspace-local persona is
226
+ refused in safe mode unless the launch includes `--allow-repo-persona`.
227
+
204
228
  ### `tracking`
205
229
 
206
230
  Controls local run recording.
@@ -64,7 +64,7 @@ workflow result in `result.json`. Injected globals are `agent`, `pipeline`,
64
64
 
65
65
  ## Core DSL
66
66
 
67
- - `agent(prompt, engine=None, mode=None, model=None, effort=None, schema=None, label=None, phase=None, isolation=None, passthrough=False, timeout=None, retries=None, fast=None)` launches a real Delegate child run and returns parent-facing output, a validated schema object, or `None`. `fast=True` requests Codex Fast, `fast=False` requests Standard, and `None` inherits; non-Codex fallback candidates ignore this Codex-only preference. `fast` is appended to preserve positional compatibility with existing workflow scripts.
67
+ - `agent(prompt, engine=None, mode=None, model=None, effort=None, schema=None, label=None, phase=None, isolation=None, passthrough=False, timeout=None, retries=None, fast=None, persona=None, allow_repo_persona=False)` launches a real Delegate child run and returns parent-facing output, a validated schema object, or `None`. `fast=True` requests Codex Fast, `fast=False` requests Standard, and `None` inherits; non-Codex fallback candidates ignore this Codex-only preference. `persona` resolves one named persona from the source workspace; `allow_repo_persona=True` opts into workspace-local personas in safe mode.
68
68
  - `pipeline(items, stage1, ...)` runs per-item stage chains with no inter-stage barrier. A throwing stage drops that item to `None` and skips later stages for that item.
69
69
  - `parallel([lambda: ...])` is a barrier and preserves order. Ordinary item failures become `None` slots; gate checkpoints propagate to the supervisor.
70
70
  - `phase(title)` emits a progress event.
@@ -76,6 +76,17 @@ Workflow `engine` values and `workflows.engineCaps` keys accept `cursor`,
76
76
  `droid`, `codex`, `claude`, `grok`, `devin`, `opencode`, `pi`, `omp`, and
77
77
  `kimi`.
78
78
 
79
+ ### Persona digest pinning
80
+
81
+ When `agent(persona="editor")` first resolves `editor.md`, the workflow
82
+ structural key and `agent_started` journal event include the resolved bytes'
83
+ SHA-256 digest. Replay therefore returns the result only for the same persona
84
+ version: editing the file creates a cache miss instead of mixing two versions
85
+ under the same name. Dry-runs expose persona name/source/digest/byte count but
86
+ never write the persona body. Child input JSON carries `persona` and
87
+ `allowRepoPersona`; the normal run manifest and inspection projections expose
88
+ non-sensitive persona metadata only.
89
+
79
90
  ## Gates and resume
80
91
 
81
92
  A workflow gate checkpoints the whole workflow tree, not just the nested child
@@ -200,9 +211,10 @@ python3 bin/delegate.py --json workflow run review.py \
200
211
  ```
201
212
 
202
213
  The preview's `runTree.calls` records each call's resolved `model`, `effort`,
203
- `fast`, `isolation`, and UTF-8 `promptBytes`. Cursor and Kimi calls whose prompts
204
- exceed 102400 bytes also carry a warning because those harnesses transport the
205
- prompt in argv.
214
+ `fast`, `isolation`, and UTF-8 `promptBytes` (the raw user prompt plus resolved
215
+ persona text). Cursor, Kimi, and OMP calls whose user-plus-resolved-persona input
216
+ exceeds 102400 bytes carry a warning; the final materialized prompt is checked
217
+ again before exec.
206
218
 
207
219
  ## CLI
208
220
 
@@ -13,6 +13,31 @@ Delegate controls:
13
13
  - Prompt framing that tells sub-agents to review available skills and, in safe mode, avoid edits.
14
14
  - Local run metadata under `.delegate/` for tracked runs.
15
15
 
16
+ ### Persona boundary
17
+
18
+ Personas are untrusted prompt text, not policy. Delegate validates the name,
19
+ path containment, file type, UTF-8, byte limit, and C0 controls, but does not
20
+ trust persona instructions. Safe-mode framing deliberately places the safe
21
+ advisory after the persona (`skill -> persona -> safe`) so a persona cannot
22
+ replace the safety text by recency. Native persona channels are work-only;
23
+ safe mode always prepends.
24
+
25
+ Workspace-local personas live under `.delegate/personas/`, which is local state
26
+ and is not VCS-shared. Safe mode refuses them by default; use
27
+ `--allow-repo-persona` only when the source workspace is trusted. Global
28
+ personas are resolved from `~/.delegate/personas/` when no workspace file
29
+ shadows the name. Call, read-only call, pass-through, and slash-passthrough
30
+ surfaces refuse personas rather than silently changing their prompt contract.
31
+
32
+ Claude native-file transport is discovery-gated and writes a private 0600 file;
33
+ an absent, stale, or unproven capability falls back to prepend. OpenCode merges
34
+ into the effective config without destroying existing root keys, agent fields,
35
+ or prompt text; malformed config falls back to prepend with a warning. Claude
36
+ native-file keeps persona bodies out of argv, dry-run output, and manifests;
37
+ prepend engines using argv transport expose them in the live process argv.
38
+ Tracked runs retain
39
+ the resolved bytes only in private `persona.txt`, which is removed with the run.
40
+
16
41
  Delegate does not control:
17
42
 
18
43
  - The child runtime's implementation.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "delegate-agent-cli"
7
- version = "0.24.0"
7
+ version = "0.25.0"
8
8
  description = "A tiny CLI for delegating bounded agent tasks across coding-agent runtimes."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,5 +1,5 @@
1
1
  """Delegate Agent CLI package."""
2
2
 
3
- VERSION = "0.24.0"
3
+ VERSION = "0.25.0"
4
4
 
5
5
  __all__ = ["VERSION"]
@@ -20,6 +20,7 @@ from delegate_agent.prompt_transport import (
20
20
  CURSOR_PROMPT_REDACTION,
21
21
  DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
22
22
  DROID_PROMPT_FILE_ARG_PLACEHOLDER,
23
+ PERSONA_FILE_ARG_PLACEHOLDER,
23
24
  PROMPT_FILE_ARG_PLACEHOLDER,
24
25
  PROMPT_TRANSPORT_ARGV,
25
26
  PROMPT_TRANSPORT_FILE,
@@ -176,8 +177,6 @@ def build_cursor_argv(
176
177
  argv = [*prefix, "--workspace", workspace, "-p", "--trust"]
177
178
  if mode == MODE_WORK:
178
179
  argv.extend(["--approve-mcps", "--force"])
179
- elif mode == MODE_SAFE:
180
- prompt = prefix_cursor_safe_prompt(prompt)
181
180
  elif mode == MODE_CALL:
182
181
  # Call defaults to work-level capability ("work minus a repo"); --read-only
183
182
  # drops the write flags for the stateless judge/completion contract.
@@ -209,8 +208,6 @@ def build_droid_argv(
209
208
  argv = [binary, "exec", "--cwd", workspace]
210
209
  if mode == MODE_WORK:
211
210
  argv.append("--skip-permissions-unsafe")
212
- elif mode == MODE_SAFE:
213
- prompt = prefix_droid_safe_prompt(prompt)
214
211
  elif mode == MODE_CALL:
215
212
  if not call_read_only:
216
213
  argv.append("--skip-permissions-unsafe")
@@ -246,9 +243,7 @@ def build_kimi_argv(
246
243
  ) -> list[str]:
247
244
  _reject_pure("kimi", mode, pure)
248
245
  argv = [str(kimi["binary"])]
249
- if mode == MODE_SAFE:
250
- prompt = prefix_kimi_safe_prompt(prompt)
251
- elif mode not in (MODE_WORK, MODE_CALL):
246
+ if mode not in (MODE_SAFE, MODE_WORK, MODE_CALL):
252
247
  validate_mode(mode)
253
248
  if model:
254
249
  argv.extend(["--model", model])
@@ -270,6 +265,7 @@ def build_claude_argv(
270
265
  call_read_only: bool = False,
271
266
  pure: bool = False,
272
267
  output_schema: str | None = None,
268
+ persona_file: bool = False,
273
269
  ) -> list[str]:
274
270
  _reject_pure("claude", mode, pure, supported=True)
275
271
  if pure or output_schema is not None:
@@ -342,6 +338,8 @@ def build_claude_argv(
342
338
  argv.extend(["--model", model])
343
339
  if reasoning_effort is not None:
344
340
  argv.extend(["--effort", reasoning_effort])
341
+ if persona_file:
342
+ argv.extend(["--append-system-prompt-file", PERSONA_FILE_ARG_PLACEHOLDER])
345
343
  return argv
346
344
 
347
345
 
@@ -18,6 +18,7 @@ from delegate_agent import (
18
18
  config_commands,
19
19
  harness_discovery,
20
20
  inspection_commands,
21
+ personas,
21
22
  profile_commands,
22
23
  profile_guard,
23
24
  profiles,
@@ -93,6 +94,7 @@ from delegate_agent.prompt_transport import ( # noqa: F401 # CURSOR_PROMPT_RED
93
94
  DEVIN_AGENT_CONFIG_DISPLAY,
94
95
  DROID_PROMPT_FILE_ARG_PLACEHOLDER,
95
96
  DROID_PROMPT_FILE_DISPLAY,
97
+ PERSONA_FILE_ARG_PLACEHOLDER,
96
98
  PROMPT_FILE_ARG_PLACEHOLDER,
97
99
  PROMPT_FILE_DISPLAY,
98
100
  PROMPT_TRANSPORT_ARGV,
@@ -291,6 +293,25 @@ def emit_config_command(parsed: ParsedCommand, stdout: TextIO) -> int:
291
293
  return config_commands.emit(command, stdout)
292
294
 
293
295
 
296
+ def emit_personas(workspace: ResolvedWorkspace, *, json_mode: bool, stdout: TextIO) -> int:
297
+ rows = personas.list_personas(workspace.path)
298
+ if json_mode:
299
+ delegate_rendering.print_json({"schema": "delegate.personas.v1", "personas": rows}, stdout)
300
+ return EXIT_OK
301
+ if not rows:
302
+ print("No personas found.", file=stdout)
303
+ return EXIT_OK
304
+ for row in rows:
305
+ name = row.get("name", "")
306
+ source = row.get("source", "")
307
+ if "invalid" in row:
308
+ print(f"{name} ({source}): invalid: {row['invalid']}", file=stdout)
309
+ continue
310
+ shadow = " [shadows global]" if row.get("shadowsGlobal") else ""
311
+ print(f"{name} ({source}, {row.get('sizeBytes', 0)} bytes){shadow}", file=stdout)
312
+ return EXIT_OK
313
+
314
+
294
315
  def dry_run_payload(request: Request) -> JsonObject:
295
316
  payload: JsonObject = {
296
317
  "ok": True,
@@ -328,6 +349,12 @@ def dry_run_payload(request: Request) -> JsonObject:
328
349
  payload["group"] = request.group
329
350
  if request.agent is not None:
330
351
  payload["agent"] = request.agent
352
+ if request.persona_name is not None:
353
+ payload["personaName"] = request.persona_name
354
+ payload["personaSource"] = request.persona_source
355
+ payload["personaTransport"] = request.persona_transport
356
+ payload["personaDigest"] = request.persona_digest
357
+ payload["personaFile"] = request.persona_file
331
358
  if request.resumed_from is not None:
332
359
  payload["resumedFrom"] = request.resumed_from
333
360
  if request.auth_profile is not None:
@@ -602,6 +629,12 @@ def make_run_context(
602
629
  output_schema_text=request.output_schema_record_text,
603
630
  agent=request.agent,
604
631
  resumed_from=request.resumed_from,
632
+ persona_name=request.persona_name,
633
+ persona_source=request.persona_source,
634
+ persona_transport=request.persona_transport,
635
+ persona_digest=request.persona_digest,
636
+ persona_file=request.persona_file,
637
+ persona_text=request.persona_text,
605
638
  )
606
639
 
607
640
 
@@ -760,6 +793,10 @@ def _execute_attached_worktree(
760
793
  run_registry.write_private_text(
761
794
  run_path / run_registry.PROMPT_TXT_FILE, ctx_runner.source_prompt
762
795
  )
796
+ if ctx_runner.persona_text is not None:
797
+ run_registry.write_private_text(
798
+ run_path / run_registry.PERSONA_TXT_FILE, ctx_runner.persona_text
799
+ )
763
800
  delegate_runner.write_manifest(
764
801
  run_path,
765
802
  delegate_runner.build_manifest(ctx_runner, execution_request.display_argv),
@@ -808,6 +845,8 @@ def _execute_attached_worktree(
808
845
  prompt_file_placeholder=PROMPT_FILE_ARG_PLACEHOLDER,
809
846
  agent_config_text=execution_request.agent_config_text,
810
847
  agent_config_placeholder=DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
848
+ persona_file_text=execution_request.persona_file_text,
849
+ persona_file_placeholder=PERSONA_FILE_ARG_PLACEHOLDER,
811
850
  output_schema_text=request.output_schema_text,
812
851
  output_schema_path=request.output_schema,
813
852
  manifest_argv=execution_request.display_argv,
@@ -894,6 +933,12 @@ def execute_request(
894
933
  prompt_file_placeholder=PROMPT_FILE_ARG_PLACEHOLDER,
895
934
  agent_config_text=request.agent_config_text,
896
935
  agent_config_placeholder=DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
936
+ persona_file_text=(
937
+ request.persona_text
938
+ if request.persona_transport == "native-file"
939
+ else None
940
+ ),
941
+ persona_file_placeholder=PERSONA_FILE_ARG_PLACEHOLDER,
897
942
  output_schema_text=request.output_schema_text,
898
943
  output_schema_path=request.output_schema,
899
944
  manifest_argv=public_argv(request),
@@ -1157,6 +1202,12 @@ def execute_request(
1157
1202
  prompt_file_placeholder=PROMPT_FILE_ARG_PLACEHOLDER,
1158
1203
  agent_config_text=isolated_request.agent_config_text,
1159
1204
  agent_config_placeholder=DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
1205
+ persona_file_text=(
1206
+ isolated_request.persona_text
1207
+ if isolated_request.persona_transport == "native-file"
1208
+ else None
1209
+ ),
1210
+ persona_file_placeholder=PERSONA_FILE_ARG_PLACEHOLDER,
1160
1211
  output_schema_text=isolated_request.output_schema_text,
1161
1212
  output_schema_path=isolated_request.output_schema,
1162
1213
  manifest_argv=public_argv(isolated_request),
@@ -1320,6 +1371,10 @@ def main(
1320
1371
  config, source = load_config(workspace=config_workspace)
1321
1372
  validate_config(config)
1322
1373
 
1374
+ if parsed.subcommand == "personas":
1375
+ workspace = resolve_workspace(global_options.cwd)
1376
+ return emit_personas(workspace, json_mode=global_options.json_mode, stdout=stdout)
1377
+
1323
1378
  discovery_profile: profiles.ProfileResolution | None = None
1324
1379
  discovery_snapshot: JsonObject | None = None
1325
1380
  if parsed.subcommand in {"models", "capabilities"}:
@@ -1425,7 +1480,7 @@ def main(
1425
1480
  # through the normal request build and execution path.
1426
1481
  parsed = resume_plan.parsed
1427
1482
  global_options = parsed.global_options
1428
- request = request_from_parsed(parsed, config, stdin)
1483
+ request = request_from_parsed(parsed, config, stdin, stderr)
1429
1484
  if resume_plan is not None:
1430
1485
  request = resume_command.apply_resume_to_request(request, resume_plan)
1431
1486
  if request.dry_run:
@@ -160,7 +160,7 @@ def parse_help_subcommand(rest: list[str], json_mode: bool) -> ParsedCommand:
160
160
  return help_command(json_mode, topic)
161
161
 
162
162
 
163
- SIMPLE_INSPECTION_SUBCOMMANDS = frozenset({"models", "describe", "agent-help"})
163
+ SIMPLE_INSPECTION_SUBCOMMANDS = frozenset({"models", "describe", "agent-help", "personas"})
164
164
  INSPECTION_OPTION_SUBCOMMANDS = frozenset({"models", "describe"})
165
165
 
166
166
 
@@ -791,6 +791,9 @@ def parse_modeless_engine(
791
791
  include_dirty,
792
792
  model,
793
793
  agent,
794
+ persona,
795
+ no_persona,
796
+ allow_repo_persona,
794
797
  ) = parse_prompt_tail(rest[1:], json_mode, isolation, command_prefix=[engine, mode])
795
798
  if agent is not None and engine != "opencode":
796
799
  raise DelegateError("unsupported_agent", "--agent is only supported by opencode.")
@@ -844,6 +847,9 @@ def parse_modeless_engine(
844
847
  dry_run=dry_run,
845
848
  model=model,
846
849
  agent=agent,
850
+ persona=persona,
851
+ no_persona=no_persona,
852
+ allow_repo_persona=allow_repo_persona,
847
853
  ),
848
854
  )
849
855
 
@@ -918,6 +924,9 @@ def parse_droid(
918
924
  include_dirty,
919
925
  model,
920
926
  agent,
927
+ persona,
928
+ no_persona,
929
+ allow_repo_persona,
921
930
  ) = parse_prompt_tail(tail, json_mode, isolation, command_prefix=command_prefix)
922
931
  if agent is not None:
923
932
  raise DelegateError("unsupported_agent", "--agent is only supported by opencode.")
@@ -973,6 +982,9 @@ def parse_droid(
973
982
  dry_run=dry_run,
974
983
  model=model,
975
984
  agent=agent,
985
+ persona=persona,
986
+ no_persona=no_persona,
987
+ allow_repo_persona=allow_repo_persona,
976
988
  ),
977
989
  )
978
990
 
@@ -1060,6 +1072,9 @@ def parse_resume(
1060
1072
  drop_output_schema = False
1061
1073
  include_dirty = False
1062
1074
  dry_run = False
1075
+ persona: str | None = None
1076
+ no_persona = False
1077
+ allow_repo_persona = False
1063
1078
  handle: str | None = None
1064
1079
  extra_parts: list[str] = []
1065
1080
  i = 0
@@ -1140,6 +1155,38 @@ def parse_resume(
1140
1155
  include_dirty = True
1141
1156
  i += 1
1142
1157
  continue
1158
+ if token == "--persona":
1159
+ if i + 1 >= len(rest):
1160
+ raise DelegateError("missing_persona", "--persona requires a non-empty name.")
1161
+ value = rest[i + 1]
1162
+ if not value.strip() or value.startswith("-") or command_help.is_help_token(value):
1163
+ raise DelegateError("missing_persona", "--persona requires a non-empty name.")
1164
+ if persona is not None or no_persona:
1165
+ raise DelegateError(
1166
+ "invalid_option_combination",
1167
+ "--persona and --no-persona cannot be combined.",
1168
+ )
1169
+ persona = value
1170
+ i += 2
1171
+ continue
1172
+ if token == "--no-persona":
1173
+ if persona is not None or no_persona:
1174
+ raise DelegateError(
1175
+ "invalid_option_combination",
1176
+ "--persona and --no-persona cannot be combined.",
1177
+ )
1178
+ no_persona = True
1179
+ i += 1
1180
+ continue
1181
+ if token == "--allow-repo-persona":
1182
+ if allow_repo_persona:
1183
+ raise DelegateError(
1184
+ "invalid_option_combination",
1185
+ "Only one --allow-repo-persona flag is allowed.",
1186
+ )
1187
+ allow_repo_persona = True
1188
+ i += 1
1189
+ continue
1143
1190
  if token == "--dry-run":
1144
1191
  dry_run = True
1145
1192
  i += 1
@@ -1183,6 +1230,9 @@ def parse_resume(
1183
1230
  drop_output_schema=drop_output_schema,
1184
1231
  include_dirty=include_dirty,
1185
1232
  dry_run=dry_run,
1233
+ persona=persona,
1234
+ no_persona=no_persona,
1235
+ allow_repo_persona=allow_repo_persona,
1186
1236
  ),
1187
1237
  )
1188
1238
 
@@ -1209,6 +1259,9 @@ def parse_prompt_tail(
1209
1259
  bool,
1210
1260
  str | None,
1211
1261
  str | None,
1262
+ str | None,
1263
+ bool,
1264
+ bool,
1212
1265
  ]:
1213
1266
  prompt_file: str | None = None
1214
1267
  output_schema: str | None = None
@@ -1222,6 +1275,9 @@ def parse_prompt_tail(
1222
1275
  timeout: int | None = None
1223
1276
  model: str | None = None
1224
1277
  agent: str | None = None
1278
+ persona: str | None = None
1279
+ no_persona = False
1280
+ allow_repo_persona = False
1225
1281
  prompt_parts: list[str] = []
1226
1282
  i = 0
1227
1283
  while i < len(rest):
@@ -1354,6 +1410,49 @@ def parse_prompt_tail(
1354
1410
  agent = value
1355
1411
  i += 2
1356
1412
  continue
1413
+ if token == "--persona":
1414
+ if prompt_parts:
1415
+ raise DelegateError(
1416
+ "ambiguous_persona_source", "--persona must appear before direct prompt text."
1417
+ )
1418
+ if i + 1 >= len(rest):
1419
+ raise DelegateError("missing_persona", "--persona requires a non-empty name.")
1420
+ value = rest[i + 1]
1421
+ if not value.strip() or value.startswith("-") or command_help.is_help_token(value):
1422
+ raise DelegateError("missing_persona", "--persona requires a non-empty name.")
1423
+ if persona is not None or no_persona:
1424
+ raise DelegateError(
1425
+ "invalid_option_combination", "--persona and --no-persona cannot be combined."
1426
+ )
1427
+ persona = value
1428
+ i += 2
1429
+ continue
1430
+ if token == "--no-persona":
1431
+ if prompt_parts:
1432
+ raise DelegateError(
1433
+ "ambiguous_persona_source",
1434
+ "--no-persona must appear before direct prompt text.",
1435
+ )
1436
+ if persona is not None or no_persona:
1437
+ raise DelegateError(
1438
+ "invalid_option_combination", "--persona and --no-persona cannot be combined."
1439
+ )
1440
+ no_persona = True
1441
+ i += 1
1442
+ continue
1443
+ if token == "--allow-repo-persona":
1444
+ if prompt_parts:
1445
+ raise DelegateError(
1446
+ "ambiguous_persona_source",
1447
+ "--allow-repo-persona must appear before direct prompt text.",
1448
+ )
1449
+ if allow_repo_persona:
1450
+ raise DelegateError(
1451
+ "invalid_option_combination", "Only one --allow-repo-persona flag is allowed."
1452
+ )
1453
+ allow_repo_persona = True
1454
+ i += 1
1455
+ continue
1357
1456
  if token == "--progress":
1358
1457
  if progress_intent == "on":
1359
1458
  raise DelegateError(
@@ -1476,6 +1575,9 @@ def parse_prompt_tail(
1476
1575
  include_dirty,
1477
1576
  model,
1478
1577
  agent,
1578
+ persona,
1579
+ no_persona,
1580
+ allow_repo_persona,
1479
1581
  )
1480
1582
 
1481
1583