cinna-cli 0.4.2__tar.gz → 0.4.3__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 (112) hide show
  1. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/PKG-INFO +22 -1
  2. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/README.md +21 -0
  3. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/README.md +1 -0
  4. cinna_cli-0.4.3/docs/features/delegation/delegation.md +160 -0
  5. cinna_cli-0.4.3/docs/features/delegation/delegation_acceptance.md +250 -0
  6. cinna_cli-0.4.3/docs/features/delegation/delegation_tech.md +149 -0
  7. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/pyproject.toml +1 -1
  8. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/client.py +44 -0
  9. cinna_cli-0.4.3/src/cinna/delegation.py +380 -0
  10. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/main.py +10 -0
  11. cinna_cli-0.4.3/tests/test_delegation.py +362 -0
  12. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/uv.lock +1 -1
  13. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/.claude/commands/cinna-cli.feature.doc.md +0 -0
  14. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/.github/workflows/publish.yml +0 -0
  15. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/.gitignore +0 -0
  16. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/LICENSE.md +0 -0
  17. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace.md +0 -0
  18. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace_acceptance.md +0 -0
  19. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace_tech.md +0 -0
  20. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons.md +0 -0
  21. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons_acceptance.md +0 -0
  22. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons_tech.md +0 -0
  23. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api.md +0 -0
  24. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api_acceptance.md +0 -0
  25. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api_tech.md +0 -0
  26. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management.md +0 -0
  27. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management_acceptance.md +0 -0
  28. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management_tech.md +0 -0
  29. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules.md +0 -0
  30. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules_acceptance.md +0 -0
  31. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules_tech.md +0 -0
  32. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +0 -0
  33. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +0 -0
  34. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +0 -0
  35. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/doctor/doctor.md +0 -0
  36. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/doctor/doctor_acceptance.md +0 -0
  37. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/doctor/doctor_tech.md +0 -0
  38. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning.md +0 -0
  39. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning_acceptance.md +0 -0
  40. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning_tech.md +0 -0
  41. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests.md +0 -0
  42. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests_acceptance.md +0 -0
  43. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests_tech.md +0 -0
  44. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync.md +0 -0
  45. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync_acceptance.md +0 -0
  46. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync_tech.md +0 -0
  47. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import.md +0 -0
  48. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import_acceptance.md +0 -0
  49. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import_tech.md +0 -0
  50. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration.md +0 -0
  51. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration_acceptance.md +0 -0
  52. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration_tech.md +0 -0
  53. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_chat/remote_chat.md +0 -0
  54. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_chat/remote_chat_acceptance.md +0 -0
  55. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_chat/remote_chat_tech.md +0 -0
  56. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec.md +0 -0
  57. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec_acceptance.md +0 -0
  58. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec_tech.md +0 -0
  59. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/interface.md +0 -0
  60. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/docs/mutagen_capabilities.md +0 -0
  61. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/scripts/check_docs_references.py +0 -0
  62. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/__init__.py +0 -0
  63. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/account.py +0 -0
  64. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/auth.py +0 -0
  65. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/bootstrap.py +0 -0
  66. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/chat.py +0 -0
  67. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/cli_version.py +0 -0
  68. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/config.py +0 -0
  69. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/console.py +0 -0
  70. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/context.py +0 -0
  71. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/doctor.py +0 -0
  72. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/errors.py +0 -0
  73. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/git_versioning.py +0 -0
  74. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/improve.py +0 -0
  75. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/kit_contract.py +0 -0
  76. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/local_import.py +0 -0
  77. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/logging.py +0 -0
  78. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/mcp_proxy.py +0 -0
  79. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/mutagen_runtime.py +0 -0
  80. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/scenarios.py +0 -0
  81. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/sync.py +0 -0
  82. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/sync_session.py +0 -0
  83. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/sync_ssh_shim.py +0 -0
  84. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/sync_tui.py +0 -0
  85. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +0 -0
  86. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/templates/CHAT_TESTING.md +0 -0
  87. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/templates/CLAUDE.md.template +0 -0
  88. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/templates/GIT_VERSIONING.md +0 -0
  89. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/src/cinna/templates/__init__.py +0 -0
  90. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/__init__.py +0 -0
  91. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/conftest.py +0 -0
  92. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_account.py +0 -0
  93. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_auth.py +0 -0
  94. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_bootstrap.py +0 -0
  95. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_chat.py +0 -0
  96. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_cli_version.py +0 -0
  97. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_client.py +0 -0
  98. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_config.py +0 -0
  99. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_console.py +0 -0
  100. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_context.py +0 -0
  101. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_doctor.py +0 -0
  102. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_git_versioning.py +0 -0
  103. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_improve.py +0 -0
  104. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_kit_contract.py +0 -0
  105. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_local_import.py +0 -0
  106. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_main.py +0 -0
  107. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_mutagen_runtime.py +0 -0
  108. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_onboarding.py +0 -0
  109. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_scenarios.py +0 -0
  110. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_sync.py +0 -0
  111. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_sync_session.py +0 -0
  112. {cinna_cli-0.4.2 → cinna_cli-0.4.3}/tests/test_sync_ssh_shim.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cinna-cli
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Local development CLI for Cinna Core agents
5
5
  Project-URL: Homepage, https://github.com/opencinna/cinna-cli
6
6
  Project-URL: Repository, https://github.com/opencinna/cinna-cli
@@ -549,6 +549,27 @@ cinna chat --show 3fa85f64-5717-4562-b3fc-2c963f66afa6 # read a transcript
549
549
 
550
550
  The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`, or to re-attach with `--attach`.
551
551
 
552
+ ### `cinna delegation create | status | report | reply`
553
+
554
+ Hand work to a remote agent as a **durable delegation** — a platform task with a stable identity that survives retries and carries structured results. Run from the account workspace. Every command first checks the server's delegation capability and refuses with "This server does not support durable delegations." when it is missing or not version 1.
555
+
556
+ - `create --id KEY --target AGENT_UUID --title T --brief B [--execute]` — the identity is `--target` + `--id`: a retry with the same pair returns the original task (changed title/brief are ignored) and never launches execution twice (the backend deduplicates). Prints the backend **task id** the other commands take, and whether it executes. `--depth 2 --root ROOT` makes a sub-delegation (`--root` is required at depth 2, not allowed at depth 1); `--group` tags related work.
557
+ - `status TASK_ID` — one read: state, latest result, and any open question with its result id. A requester agent should end its turn and let Cinna Desktop deliver the result rather than poll.
558
+ - `report [TASK_ID] --status in_progress|blocked|done|failed --summary S` — `blocked` needs `--question`; `--audience user` when a human must decide (default `requester`). `--artifact` (repeatable) is a JSON object with non-empty `kind` (backend accepts `file` or `link`), `name` and an `http(s)` `ref` — upload local files separately. `--body` adds detail.
559
+ - **Inside a cloud task**, omit `TASK_ID`: the report goes to the current task using `AGENT_AUTH_TOKEN`, `BACKEND_URL`, `ENV_ID` and the session in `CINNA_SESSION_CONTEXT_PATH` (default `./session_context.json`); the backend checks the session belongs to this environment's agent and owner.
560
+ - `reply TASK_ID --result-id ID --message M` — answer a blocked question.
561
+ - `--json` (after the subcommand) prints `{"result": "ok", "delegation": {…}}`.
562
+
563
+ ```bash
564
+ cinna delegation create --id research-1 --target AGENT_UUID --title Research --brief 'Find the facts' --execute
565
+ cinna delegation status TASK_ID
566
+ cinna delegation report TASK_ID --status blocked --summary 'Choose a source' --question 'Which source?' --audience user
567
+ cinna delegation reply TASK_ID --result-id RESULT_ID --message 'Use the primary source'
568
+ cinna delegation report --status done --summary 'Finished' # inside the cloud task
569
+ ```
570
+
571
+ Inside cloud tasks, cinna-core's MCP task server also offers a `handover_report` tool for the same report.
572
+
552
573
  ### `cinna dev`
553
574
 
554
575
  Start a foreground dev session — creates / resumes the Mutagen sync session for this workspace and attaches the terminal to a two-tab TUI (status + raw Mutagen details). Ctrl-C terminates the session; sync does not outlive the TUI. To observe sync from another terminal without affecting it, use `cinna sync status`.
@@ -512,6 +512,27 @@ cinna chat --show 3fa85f64-5717-4562-b3fc-2c963f66afa6 # read a transcript
512
512
 
513
513
  The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`, or to re-attach with `--attach`.
514
514
 
515
+ ### `cinna delegation create | status | report | reply`
516
+
517
+ Hand work to a remote agent as a **durable delegation** — a platform task with a stable identity that survives retries and carries structured results. Run from the account workspace. Every command first checks the server's delegation capability and refuses with "This server does not support durable delegations." when it is missing or not version 1.
518
+
519
+ - `create --id KEY --target AGENT_UUID --title T --brief B [--execute]` — the identity is `--target` + `--id`: a retry with the same pair returns the original task (changed title/brief are ignored) and never launches execution twice (the backend deduplicates). Prints the backend **task id** the other commands take, and whether it executes. `--depth 2 --root ROOT` makes a sub-delegation (`--root` is required at depth 2, not allowed at depth 1); `--group` tags related work.
520
+ - `status TASK_ID` — one read: state, latest result, and any open question with its result id. A requester agent should end its turn and let Cinna Desktop deliver the result rather than poll.
521
+ - `report [TASK_ID] --status in_progress|blocked|done|failed --summary S` — `blocked` needs `--question`; `--audience user` when a human must decide (default `requester`). `--artifact` (repeatable) is a JSON object with non-empty `kind` (backend accepts `file` or `link`), `name` and an `http(s)` `ref` — upload local files separately. `--body` adds detail.
522
+ - **Inside a cloud task**, omit `TASK_ID`: the report goes to the current task using `AGENT_AUTH_TOKEN`, `BACKEND_URL`, `ENV_ID` and the session in `CINNA_SESSION_CONTEXT_PATH` (default `./session_context.json`); the backend checks the session belongs to this environment's agent and owner.
523
+ - `reply TASK_ID --result-id ID --message M` — answer a blocked question.
524
+ - `--json` (after the subcommand) prints `{"result": "ok", "delegation": {…}}`.
525
+
526
+ ```bash
527
+ cinna delegation create --id research-1 --target AGENT_UUID --title Research --brief 'Find the facts' --execute
528
+ cinna delegation status TASK_ID
529
+ cinna delegation report TASK_ID --status blocked --summary 'Choose a source' --question 'Which source?' --audience user
530
+ cinna delegation reply TASK_ID --result-id RESULT_ID --message 'Use the primary source'
531
+ cinna delegation report --status done --summary 'Finished' # inside the cloud task
532
+ ```
533
+
534
+ Inside cloud tasks, cinna-core's MCP task server also offers a `handover_report` tool for the same report.
535
+
515
536
  ### `cinna dev`
516
537
 
517
538
  Start a foreground dev session — creates / resumes the Mutagen sync session for this workspace and attaches the terminal to a two-tab TUI (status + raw Mutagen details). Ctrl-C terminates the session; sync does not outlive the TUI. To observe sync from another terminal without affecting it, use `cinna sync status`.
@@ -296,6 +296,7 @@ authoring convention.
296
296
  | **Agent addons** | `cinna skills` (list — with each declared credential slot's readiness, publish, install, uninstall, update, toggle, refresh, catalog, show, revisions, files, grants, grant, revoke, visibility, delist, relist) — the whole skills lifecycle: what an agent carries, publishing one of its `skills/<name>/` folders to the catalog, installing a package on another agent and keeping it current, and sharing after the fact | [business](features/agent_addons/agent_addons.md) · [tech](features/agent_addons/agent_addons_tech.md) · [acceptance](features/agent_addons/agent_addons_acceptance.md) |
297
297
  | **MCP integration** | `cinna connect mcp` · `cinna mcp-proxy` (knowledge stdio server) | [business](features/mcp_integration/mcp_integration.md) · [tech](features/mcp_integration/mcp_integration_tech.md) · [acceptance](features/mcp_integration/mcp_integration_acceptance.md) |
298
298
  | **Git versioning** | `cinna git` (link, status, commit, push, pull, log, checkout, unlink) | [business](features/git_versioning/git_versioning.md) · [tech](features/git_versioning/git_versioning_tech.md) · [acceptance](features/git_versioning/git_versioning_acceptance.md) |
299
+ | **Durable delegation** | `cinna delegation` (create — idempotent per target + `--id`, status, report — owner side with a task id or from inside a cloud task, reply), gated on the backend capability version | [business](features/delegation/delegation.md) · [tech](features/delegation/delegation_tech.md) · [acceptance](features/delegation/delegation_acceptance.md) |
299
300
  | **Improvement requests** | `cinna improve` (list, show, download, status) | [business](features/improvement_requests/improvement_requests.md) · [tech](features/improvement_requests/improvement_requests_tech.md) · [acceptance](features/improvement_requests/improvement_requests_acceptance.md) |
300
301
  | **Local agent import** | `cinna agent import` (Local Agent Kit → cloud agent), incl. the versioned folder contract (`.cinna-kit/layout.json`), `publications.json` and `content_hash` | [business](features/local_agent_import/local_agent_import.md) · [tech](features/local_agent_import/local_agent_import_tech.md) · [acceptance](features/local_agent_import/local_agent_import_acceptance.md) |
301
302
 
@@ -0,0 +1,160 @@
1
+ # Durable Delegation (`cinna delegation`)
2
+
3
+ ## Purpose
4
+
5
+ Let a requester (a developer, a local coding agent, or a script) hand a piece of
6
+ work to a remote platform agent as a **durable delegation**: a platform task
7
+ with a stable identity that survives retries, reports structured results back,
8
+ and can ask the requester (or a human) a question and wait for the answer.
9
+ The same command group lets the cloud agent doing the work report its own
10
+ progress from inside its task session.
11
+
12
+ ## Mental model / core concepts
13
+
14
+ A delegation is **not** local state. It is a platform task (the same task
15
+ record the platform UI shows) carrying extra delegation metadata. The CLI is a
16
+ remote control over it; nothing is written to the workspace.
17
+
18
+ - **Requester key (`--id`)** — a name the requester picks for one piece of work
19
+ (`research-1`). Together with the target agent it forms the delegation's
20
+ identity. Reusing the same key against the same target means "the same work",
21
+ never "new work".
22
+ - **Target** — the UUID of the remote agent that will do the work.
23
+ - **Task id** — the backend id of the created task. `create` prints it; every
24
+ other command (`status`, `report`, `reply`) takes it.
25
+ - **Result** — a structured report on the task: a status (`in_progress`,
26
+ `blocked`, `done`, `failed`), a summary, an optional body, optional
27
+ artifacts, and — when blocked — a question with an audience.
28
+ - **Question / reply** — a `blocked` result carries a question. Its result id
29
+ is the handle the answer is sent against (`reply --result-id`).
30
+ - **Audience** — who must answer a question: `requester` (the agent/tool that
31
+ created the delegation) or `user` (a human decision).
32
+ - **Depth and root** — a delegation may itself delegate once more. Depth 1 is a
33
+ top-level delegation whose root is itself; depth 2 is a sub-delegation that
34
+ names its depth-1 root. Deeper chains are not allowed.
35
+ - **Owner side vs executor side** —
36
+ - *Owner side*: run from an **account workspace**, authenticated by the
37
+ account token, reaching the platform through the account API proxy
38
+ (`create`, `status`, `reply`, and `report` with a task id).
39
+ - *Executor side*: run **inside a cloud task session** in the agent's
40
+ environment, authenticated by the environment's own agent token
41
+ (`report` without a task id). It reports on "the task I am currently
42
+ running" — it never needs to know the task id.
43
+ - **Capability negotiation** — durable delegations are a versioned backend
44
+ extension. Every owner-side command first asks the server whether it supports
45
+ version 1; if not, the command refuses instead of calling routes that may not
46
+ exist.
47
+
48
+ ## User flows
49
+
50
+ ### Hand work to a remote agent
51
+ 1. From the account workspace run
52
+ `cinna delegation create --id research-1 --target <agent uuid> --title … --brief …`,
53
+ adding `--execute` to start the work immediately.
54
+ 2. The CLI prints the backend task id and whether the task will execute.
55
+ 3. On a network error or timeout, run the **same command again**: the platform
56
+ returns the original task. Any changed `--title` / `--brief` on the retry is
57
+ ignored, and execution is never launched a second time.
58
+
59
+ ### Follow up without polling
60
+ 4. `cinna delegation status <task id>` reads the task once: its state, the
61
+ latest result, and any open question together with that question's result id.
62
+ 5. A requester agent should **end its turn** after delegating and let Cinna
63
+ Desktop deliver the result, rather than polling `status` in a loop.
64
+
65
+ ### Report progress (owner side)
66
+ 6. `cinna delegation report <task id> --status in_progress --summary …` records a
67
+ result on the task through the account workspace.
68
+
69
+ ### Report progress (inside the cloud task)
70
+ 7. The agent executing the task runs
71
+ `cinna delegation report --status done --summary … [--artifact …]` with no task
72
+ id. The CLI uses the environment's agent credentials and the current session
73
+ context; the backend attaches the result to the task that session belongs to.
74
+
75
+ ### Ask and answer a question
76
+ 8. The executor reports `--status blocked --question "Which source?"`, with
77
+ `--audience user` when a human must decide.
78
+ 9. The requester reads the question and its result id with `status`, then
79
+ answers with `cinna delegation reply <task id> --result-id <id> --message …`.
80
+
81
+ ### Machine-readable use
82
+ 10. Every command accepts `--json` after the subcommand; the output is a single
83
+ `{"result": "ok", "delegation": …}` line carrying the backend's answer, or
84
+ the standard `{"result": "error", …}` line on failure.
85
+
86
+ ## Business rules
87
+
88
+ - **Account workspace required** for every owner-side command; outside one they
89
+ fail loud.
90
+ - **Capability gate** — if the server lacks the capability route, or reports a
91
+ version other than 1, the command stops with "This server does not support
92
+ durable delegations." and sends nothing else.
93
+ - **Retry identity** — the delegation identity is derived only from
94
+ target + requester key. The same pair always yields the same identity, so a
95
+ retry is idempotent. Idempotency **depends on the backend** deduplicating on
96
+ that identity; the CLI keeps no local record of what it created.
97
+ - **First write wins** — on a retry the original task is returned unchanged;
98
+ new title/brief text does not update it.
99
+ - **Execute at most once** — `--execute` only takes effect when the task is
100
+ newly created. A retry with `--execute` never launches a second run.
101
+ - **Depth and root** — depth is 1 or 2. At depth 1 `--root` is forbidden (the
102
+ delegation is its own root). At depth 2 `--root` is required.
103
+ - **Origin** — CLI-created delegations are marked as originating externally
104
+ (not from a platform agent, chat, or task).
105
+ - **Blocked needs a question** — `--status blocked` without `--question` is
106
+ refused before any request.
107
+ - **Audience** — defaults to `requester`; use `user` when a human must decide.
108
+ - **Artifacts are references, not uploads** — each `--artifact` is a JSON object
109
+ with a non-empty `kind`, a non-empty `name`, and an `http(s)` `ref`. The CLI
110
+ checks only that shape; the backend further restricts `kind` (currently
111
+ `file` or `link`). Local files must be uploaded separately first; the CLI
112
+ never uploads them.
113
+ - **Executor report is session-bound** — without a task id, `report` needs the
114
+ environment's agent token, backend URL and environment id, plus the current
115
+ session context. Missing any of them is a hard failure. The backend verifies
116
+ that the session belongs to this environment's agent and owner, so an agent
117
+ cannot report on someone else's task.
118
+ - **Status is a single read** — no watching, no waiting.
119
+ - **Fail loud** — any backend refusal surfaces as a platform error with the
120
+ backend's own detail; nothing is retried silently.
121
+
122
+ ## Architecture overview
123
+
124
+ ```
125
+ Owner side (account workspace)
126
+ cinna delegation create|status|reply|report TASK_ID
127
+ │
128
+ ▼
129
+ delegation.py ──► AccountClient ──► POST /api/v1/cli/account/api-proxy
130
+ │ 1. GET tasks/delegation-capabilities (version 1?)
131
+ │ 2. the delegation route
132
+ ▼
133
+ cinna-core tasks API (dedup, execution, results)
134
+
135
+ Executor side (inside a cloud task session)
136
+ cinna delegation report (no TASK_ID)
137
+ │ env: AGENT_AUTH_TOKEN, BACKEND_URL, ENV_ID + session_context.json
138
+ ▼
139
+ POST {BACKEND_URL}/api/v1/agent/tasks/current/delegation-result
140
+ │ backend checks session ↔ environment agent ↔ owner
141
+ ▼
142
+ result attached to the current task ──► delivered to the requester (Desktop)
143
+ ```
144
+
145
+ ## Integration points
146
+
147
+ - **Account workspace** — owner-side commands use the account token and the api
148
+ proxy. See [Account Workspace](../account_workspace/account_workspace.md).
149
+ - **Agent API / `cinna api`** — the same api-proxy escape hatch `cinna api`
150
+ exposes; delegation wraps the task routes with identity, validation and a
151
+ capability gate. See [Agent API](../agent_api/agent_api.md).
152
+ - **Remote chat** — a delegated task runs as a platform session like the ones
153
+ `cinna chat` drives. See [Remote Chat](../remote_chat/remote_chat.md).
154
+ - **cinna-core task MCP server (not in this repo)** — inside cloud tasks the
155
+ backend's MCP task server exposes a `handover_report` tool that records the
156
+ same kind of result. It is implemented and documented in cinna-core; this CLI
157
+ only offers the equivalent command-line path.
158
+
159
+ Implementation: see [delegation_tech.md](delegation_tech.md).
160
+ Real-usage e2e scenarios: see [delegation_acceptance.md](delegation_acceptance.md).
@@ -0,0 +1,250 @@
1
+ # Durable Delegation — Acceptance Scenarios (live e2e)
2
+
3
+ The catalog of **real-usage scenarios** for an agent integration-testing
4
+ `cinna delegation` against a **live** platform: a real cinna-core backend with
5
+ the durable-delegation extension, a real account workspace, and at least one
6
+ real target agent. These exercise backend dedup, task execution, the result /
7
+ question / reply cycle, and the executor-side report from inside a cloud task —
8
+ the parts unit tests only mock.
9
+
10
+ How to use: run the **Steps** from inside the account workspace (except where a
11
+ scenario says "inside the cloud task"), assert the **Expected**, and check the
12
+ **Watch for** items. Scenarios 2–3 (retry identity) and 9–11 (executor report)
13
+ are the highest-value ones for any change to `src/cinna/delegation.py`.
14
+
15
+ ## Preconditions
16
+
17
+ - A reachable cinna-core backend whose `tasks/delegation-capabilities` returns
18
+ `version: 1`; ideally also an older backend without it (scenario 13).
19
+ - An **account workspace** (`.cinna/account.json` reachable from the cwd;
20
+ `cinna login` if the token expired).
21
+ - **Editable install**: `which cinna` resolves, and
22
+ `python3 -c "import cinna,os;print(os.path.dirname(cinna.__file__))"` points at
23
+ this repo's `src/cinna`. `cinna delegation --help` lists create, status,
24
+ report, reply.
25
+ - At least one **target agent** UUID (`cinna account agents`), with a running
26
+ or startable environment.
27
+ - `jq` for asserting JSON output.
28
+ - Use a fresh key per run, e.g. `KEY=acc-$(date +%s)`, so earlier runs do not
29
+ dedup into this one.
30
+
31
+ ## Scenario catalog
32
+
33
+ ### 1. Create without executing
34
+
35
+ - **Goal:** register work without starting it.
36
+ - **Steps:**
37
+ ```
38
+ cinna delegation create --id "$KEY" --target "$AGENT" --title Research --brief 'Find the facts'
39
+ ```
40
+ - **Expected:** exit 0; output shows the backend task id and that it will
41
+ **not** execute. The task appears in the platform UI for the target agent,
42
+ not started. Record the id as `TASK`.
43
+ - **Watch for:** the delegation id / requester key printed instead of the
44
+ backend task id; the task auto-starting.
45
+
46
+ ### 2. Retry reuses the original task (idempotent create)
47
+
48
+ - **Goal:** a retry after a timeout never duplicates work.
49
+ - **Steps:**
50
+ ```
51
+ cinna delegation create --id "$KEY" --target "$AGENT" --title Research --brief 'Find the facts' --json | jq -r .delegation.id
52
+ cinna delegation create --id "$KEY" --target "$AGENT" --title 'Changed title' --brief 'Changed brief' --json | jq -r .delegation.id
53
+ ```
54
+ - **Expected:** both ids equal `TASK`. The platform shows one task, still titled
55
+ `Research` with the original brief.
56
+ - **Watch for:** a second task; the title/brief being overwritten; a non-`ok`
57
+ result on the retry.
58
+
59
+ ### 3. `--execute` runs at most once
60
+
61
+ - **Goal:** execution is never launched twice for the same key.
62
+ - **Steps:**
63
+ ```
64
+ KEY2=$KEY-exec
65
+ cinna delegation create --id "$KEY2" --target "$AGENT" --title Run --brief 'Say hello' --execute
66
+ cinna delegation create --id "$KEY2" --target "$AGENT" --title Run --brief 'Say hello' --execute
67
+ ```
68
+ - **Expected:** the first reports the task executes; the second returns the same
69
+ task id. The platform shows exactly one execution/session for that task.
70
+ - **Watch for:** two sessions on the target agent; the retry reporting a new
71
+ execution.
72
+
73
+ ### 4. Same key, different target is different work
74
+
75
+ - **Goal:** identity is target + key.
76
+ - **Steps:** repeat scenario 1's command with `--target "$AGENT_B"` (a second
77
+ agent) and the same `$KEY`.
78
+ - **Expected:** a new, different task id.
79
+ - **Watch for:** dedup across targets (identity must include the target).
80
+
81
+ ### 5. Depth and root rules
82
+
83
+ - **Goal:** sub-delegation shape is enforced client-side.
84
+ - **Steps:**
85
+ ```
86
+ cinna delegation create --id "$KEY-d2" --target "$AGENT" --title T --brief B --depth 2
87
+ cinna delegation create --id "$KEY-d1" --target "$AGENT" --title T --brief B --root "$ROOT_ID"
88
+ cinna delegation create --id "$KEY-d3" --target "$AGENT" --title T --brief B --depth 3
89
+ cinna delegation create --id "$KEY-d2" --target "$AGENT" --title T --brief B --depth 2 --root "$ROOT_ID" --json
90
+ ```
91
+ (`$ROOT_ID` is the `delegation_metadata.id` of the task from scenario 1.)
92
+ - **Expected:** the first three fail with a usage error (exit 2) and create
93
+ nothing; the last succeeds and its `delegation_metadata` has `depth: 2`,
94
+ `root: $ROOT_ID`. A depth-1 task's metadata has `root` equal to its own id.
95
+ - **Watch for:** a task created by an invalid invocation; `root` null at depth 1.
96
+
97
+ ### 6. Status is a single read
98
+
99
+ - **Goal:** read state, latest result and open question once.
100
+ - **Steps:**
101
+ ```
102
+ cinna delegation status "$TASK"
103
+ cinna delegation status "$TASK" --json | jq .result
104
+ ```
105
+ - **Expected:** human output shows state, latest result (or none), and any open
106
+ question with its result id; returns immediately. JSON prints `"ok"` with the
107
+ task detail under `.delegation`.
108
+ - **Watch for:** the command waiting or polling; missing result id next to an
109
+ open question.
110
+
111
+ ### 7. Owner-side report and blocked question
112
+
113
+ - **Goal:** record results and ask a question through the account workspace.
114
+ - **Steps:**
115
+ ```
116
+ cinna delegation report "$TASK" --status in_progress --summary 'Started'
117
+ cinna delegation report "$TASK" --status blocked --summary 'Need input'
118
+ cinna delegation report "$TASK" --status blocked --summary 'Need input' --question 'Which source?' --audience user
119
+ cinna delegation status "$TASK"
120
+ ```
121
+ - **Expected:** the first succeeds; the second fails client-side (blocked
122
+ without a question) and sends nothing; the third succeeds. `status` shows the
123
+ open question `Which source?`, audience `user`, and its result id (`RESULT`).
124
+ - **Watch for:** a blocked result accepted without a question; audience
125
+ defaulting wrongly (default is `requester`).
126
+
127
+ ### 8. Reply answers the question
128
+
129
+ - **Goal:** close the question loop.
130
+ - **Steps:**
131
+ ```
132
+ cinna delegation reply "$TASK" --result-id "$RESULT" --message 'Use the primary source'
133
+ cinna delegation status "$TASK"
134
+ ```
135
+ - **Expected:** exit 0; the question is no longer open and the reply is visible
136
+ on the task. A wrong `--result-id` yields a platform error with the backend
137
+ detail (exit 1).
138
+ - **Watch for:** reply accepted against a non-question result id.
139
+
140
+ ### 9. Artifacts are validated
141
+
142
+ - **Goal:** only well-formed, portable artifact references are sent.
143
+ - **Steps:**
144
+ ```
145
+ cinna delegation report "$TASK" --status done --summary Done --artifact '{"kind":"link","name":"r","ref":"https://example.com/r.pdf"}'
146
+ cinna delegation report "$TASK" --status done --summary Done --artifact 'not json'
147
+ cinna delegation report "$TASK" --status done --summary Done --artifact '{"kind":"link","name":"r","ref":"file:///tmp/r.pdf"}'
148
+ cinna delegation report "$TASK" --status done --summary Done --artifact '{"kind":"","name":"r","ref":"https://x"}'
149
+ cinna delegation report "$TASK" --status done --summary Done --artifact '["a"]'
150
+ ```
151
+ - **Expected:** only the first succeeds and the artifact appears on the latest
152
+ result. The others fail client-side (exit 2) with no request sent.
153
+ - **Watch for:** local paths or non-http refs accepted; empty `kind`/`name`
154
+ accepted; a JSON array accepted as an artifact.
155
+
156
+ ### 10. Executor report from inside the cloud task
157
+
158
+ - **Goal:** the working agent reports on its own current task without a task id.
159
+ - **Setup:** a task created with `--execute` (scenario 3), running in the target
160
+ environment where `AGENT_AUTH_TOKEN`, `BACKEND_URL`, `ENV_ID` are set and
161
+ `session_context.json` holds `backend_session_id`.
162
+ - **Steps (inside the cloud task, e.g. as an instruction in the brief):**
163
+ ```
164
+ cinna delegation report --status done --summary 'Finished' --json
165
+ ```
166
+ Then, from the account workspace: `cinna delegation status "$TASK3"`.
167
+ - **Expected:** `{"result": "ok", "delegation": {…}}`; `status` shows the `done`
168
+ result on that task. The request went to
169
+ `$BACKEND_URL/api/v1/agent/tasks/current/delegation-result` with the bearer
170
+ token and `X-Agent-Env-Id`.
171
+ - **Watch for:** the result landing on a different task; the command trying to
172
+ load an account workspace.
173
+
174
+ ### 11. Executor report fails loud without its context
175
+
176
+ - **Goal:** no silent fallback when not in a cloud task.
177
+ - **Steps (from a plain shell, then with a partial env):**
178
+ ```
179
+ env -u AGENT_AUTH_TOKEN -u BACKEND_URL -u ENV_ID cinna delegation report --status done --summary x
180
+ AGENT_AUTH_TOKEN=t BACKEND_URL=https://backend.example ENV_ID=e CINNA_SESSION_CONTEXT_PATH=/nonexistent.json cinna delegation report --status done --summary x
181
+ ```
182
+ - **Expected:** both fail before any network call with a clear message (missing
183
+ environment / no current session). Nothing is recorded on any task.
184
+ - **Watch for:** falling back to the account workspace; a request sent with an
185
+ empty `X-Agent-Env-Id` or no `source_session_id`.
186
+
187
+ ### 12. Executor report rejected by the backend
188
+
189
+ - **Goal:** backend verification and error surfacing.
190
+ - **Steps (inside a cloud environment):** point `CINNA_SESSION_CONTEXT_PATH` at
191
+ a file whose `backend_session_id` belongs to another agent's session, then run
192
+ `cinna delegation report --status done --summary x --json`.
193
+ - **Expected:** the backend refuses; the CLI prints
194
+ `{"result": "error", "code": "platform_error", "http_status": 4xx, …}` and
195
+ exits 1 (5xx → `platform_unavailable`, exit 12). A 3xx is not followed and is
196
+ also an error.
197
+ - **Watch for:** the report accepted for a foreign session; a redirect followed
198
+ with the bearer token.
199
+
200
+ ### 13. Unsupported server
201
+
202
+ - **Goal:** capability gate on every owner-side verb.
203
+ - **Steps (against a backend without the extension, or one reporting another
204
+ version):**
205
+ ```
206
+ cinna delegation create --id "$KEY" --target "$AGENT" --title T --brief B
207
+ cinna delegation status "$TASK"
208
+ cinna delegation report "$TASK" --status done --summary x
209
+ cinna delegation reply "$TASK" --result-id r --message m
210
+ ```
211
+ - **Expected:** each fails with "This server does not support durable
212
+ delegations." and no task is created or changed.
213
+ - **Watch for:** a create going through on an old backend (which would ignore
214
+ `external_ref` and break retry safety).
215
+
216
+ ### 14. `--json` is per-command
217
+
218
+ - **Goal:** machine output works after the subcommand.
219
+ - **Steps:**
220
+ ```
221
+ cinna delegation status "$TASK" --json
222
+ cinna delegation create --id "$KEY" --target "$AGENT" --title T --brief B --json
223
+ ```
224
+ - **Expected:** each prints exactly one JSON line with `result: "ok"` and the
225
+ backend body under `delegation`; no Rich output on stdout.
226
+ - **Watch for:** extra human lines mixed into stdout; the body at top level
227
+ instead of under `delegation`.
228
+
229
+ ### 15. Outside an account workspace
230
+
231
+ - **Steps:** `cd /tmp && cinna delegation status "$TASK"`
232
+ - **Expected:** fails loud pointing at the missing account workspace; no request.
233
+
234
+ ## Cross-cutting invariants
235
+
236
+ - One target + key ⇒ one task and at most one execution, across any number of
237
+ retries and any changed title/brief.
238
+ - Every owner-side verb calls the capability route first; an unsupported server
239
+ receives no task-route writes.
240
+ - Client-side validation failures (depth/root, blocked without question,
241
+ artifacts, missing executor env) send **no** request.
242
+ - The executor bearer token is only ever sent to `BACKEND_URL` (no redirects).
243
+ - Nothing is written to the workspace, `.cinna/`, or `~/.cinna/agents.json`. <!-- nocheck -->
244
+ - Every `--json` invocation ends with exactly one `{"result": …}` line.
245
+
246
+ ## Cleanup
247
+
248
+ - Delete or archive the test tasks (keys prefixed `acc-`) in the platform UI, or
249
+ via `cinna api DELETE tasks/<id>` where the backend allows it.
250
+ - Stop any sessions left running on the target agent by `--execute` scenarios.
@@ -0,0 +1,149 @@
1
+ # Durable Delegation — Technical Reference
2
+
3
+ Implementation of [delegation.md](delegation.md). cinna-cli is a Python CLI; all
4
+ logic lives in `src/cinna/`, tests in `tests/`. The `cinna delegation` group is a
5
+ thin validation + transport layer over cinna-core task routes. It keeps no local
6
+ state.
7
+
8
+ ## File locations
9
+
10
+ - `src/cinna/delegation.py` — the whole feature: the Click group, the four verb
11
+ commands, the owner-side request helper (capability gate + proxy call), the
12
+ executor-side report path, and output rendering.
13
+ - `src/cinna/main.py` — attaches `json_option()` to every delegation
14
+ subcommand and registers the group on the root CLI
15
+ (`cli.add_command(delegation)`).
16
+ - `src/cinna/account.py` — `find_account_root()` / `load_account_config()`:
17
+ locate the account workspace and its token.
18
+ - `src/cinna/client.py` — public wrappers `get_delegation_capabilities()`,
19
+ `create_delegated_task()`, `get_task_detail()`, `put_delegation_result()`,
20
+ `post_delegation_reply()` over `_proxy_json()` / `api_proxy()` (the api-proxy
21
+ transport and error mapping), plus `AccountClient.error_detail()` used by the
22
+ executor path.
23
+ - `src/cinna/console.py` — `emit_result()` (the `--json` success line) and
24
+ `json_mode`.
25
+ - `src/cinna/errors.py` — `PlatformError`, `CinnaExit` (exit codes and the
26
+ `--json` error line).
27
+ - Tests: `tests/test_delegation.py` — retry identity and payload, depth/root
28
+ rules, owner-side routes, capability gate, report validation (blocked
29
+ question, artifacts), executor report (env, session context, headers,
30
+ redirects, non-2xx), and the `--json` envelope.
31
+
32
+ ## Command surface
33
+
34
+ - `cinna delegation` → `src/cinna/delegation.py:delegation()` (Click group).
35
+ - `cinna delegation create` → `src/cinna/delegation.py:create()`.
36
+ - `cinna delegation status` → `src/cinna/delegation.py:status()`.
37
+ - `cinna delegation report` → `src/cinna/delegation.py:report()`.
38
+ - `cinna delegation reply` → `src/cinna/delegation.py:reply()`.
39
+
40
+ Each verb carries its own `--json` option (the shared per-command
41
+ `src/cinna/main.py:json_option()`, applied in `main.py` at registration because
42
+ `delegation.py` cannot import `main.py` without a cycle); `--json` is not taken
43
+ from the root group.
44
+
45
+ ## Key functions & flow
46
+
47
+ - **Owner-side request helper** (`src/cinna/delegation.py`) — every owner-side
48
+ call: `find_account_root()` + `load_account_config()`, open an
49
+ `AccountClient`, `get_delegation_capabilities()`. A 404/405 or a body that is
50
+ not a dict with `version` `1` raises "This server does not support durable
51
+ delegations."; other platform errors propagate. Only then is the actual route
52
+ called through the matching public client method.
53
+ - `src/cinna/delegation.py:create()` — builds the identity string as the JSON
54
+ array `[target, key]`; `external_ref` is its sha256 hex digest; the delegation
55
+ id is `uuid5(NAMESPACE_URL, identity)`. Validates depth/root before any call.
56
+ POSTs `tasks/` with `title`, `original_message` (= `--brief`),
57
+ `selected_agent_id` (= `--target`), `external_ref`, `delegation_metadata`, and
58
+ `auto_execute` (= `--execute`). Human output: the backend task id and whether
59
+ it executes.
60
+ - `src/cinna/delegation.py:status()` — one `GET tasks/{id}/detail`; human output
61
+ shows state, the latest result, and any open question with its result id.
62
+ - `src/cinna/delegation.py:report()` — validates (`blocked` ⇒ `--question`;
63
+ each `--artifact` parses to a JSON object with non-empty `kind`, `name` and an
64
+ `http`/`https` `ref`), builds the payload (`status`, `summary`, `question`,
65
+ `audience`, `artifacts`, `body`), then:
66
+ - with `TASK_ID`: owner-side `PUT tasks/{id}/delegation-result`;
67
+ - without: the executor path (below).
68
+ - **Executor path** (`report()` without `TASK_ID`) — reads `AGENT_AUTH_TOKEN`,
69
+ `BACKEND_URL`, `ENV_ID` (all required); reads `backend_session_id` from the
70
+ file at `CINNA_SESSION_CONTEXT_PATH` (default `session_context.json` in the
71
+ cwd) and adds it as `source_session_id`; POSTs directly (not via the account
72
+ proxy) with `Authorization: Bearer <token>` and `X-Agent-Env-Id: <ENV_ID>`,
73
+ redirects disabled, 30 s timeout. No capability gate on this path. Any 2xx is
74
+ accepted (an empty or non-JSON success body is treated as `{}` so callers do
75
+ not retry an accepted report); non-2xx raises `PlatformError` with the detail
76
+ from `AccountClient.error_detail()`.
77
+ - `src/cinna/delegation.py:reply()` — `POST tasks/{id}/delegation-reply` with
78
+ `result_id` and `message`. Exits 0 but warns when the backend answers
79
+ `delivered: false` (result is not an open question) or `uncertain` (check
80
+ `status` before resending).
81
+ - **Output** — in `--json` mode `console.emit_result(delegation=<backend body>)`,
82
+ i.e. one line `{"result": "ok", "delegation": {…}}`; otherwise a short
83
+ human summary.
84
+
85
+ ## Payload shape
86
+
87
+ `delegation_metadata` on create:
88
+
89
+ - `id` — `uuid5(NAMESPACE_URL, json [target, key])`, stable per target+key.
90
+ - `requester_key` — the `--id` value.
91
+ - `origin_kind` — always `external`; `origin_agent_id`, `origin_chat_id`,
92
+ `origin_task_id` — always null (a CLI requester is not a platform agent,
93
+ chat or task).
94
+ - `depth` — 1 or 2.
95
+ - `root` — own `id` at depth 1; the `--root` value at depth 2.
96
+ - `group` — `--group` or null.
97
+
98
+ There is no config or registry footprint: nothing is written to
99
+ `.cinna/account.json`, `.cinna/config.json` or `~/.cinna/agents.json`. <!-- nocheck -->
100
+
101
+ ## External contracts (cinna-core backend dependencies)
102
+
103
+ Owner side — all through `POST /api/v1/cli/account/api-proxy` with the account
104
+ CLI token (`token_type="cli-account"`); the proxy mirrors the inner status and
105
+ body:
106
+
107
+ - `GET tasks/delegation-capabilities` — returns `{version: 1, …}`; 404/405 means
108
+ unsupported.
109
+ - `POST tasks/` — creates the task. **Must deduplicate on `external_ref`**:
110
+ a second create with the same `external_ref` returns the existing task,
111
+ ignores new title/brief, and does not start execution again. The CLI's retry
112
+ safety relies entirely on this.
113
+ - `GET tasks/{id}/detail` — task state, results, open question + result id.
114
+ - `PUT tasks/{id}/delegation-result` — record a result on a task.
115
+ - `POST tasks/{id}/delegation-reply` — answer a question by `result_id`.
116
+
117
+ Executor side — direct call, agent-token auth:
118
+
119
+ - `POST /api/v1/agent/tasks/current/delegation-result` — headers
120
+ `Authorization: Bearer <AGENT_AUTH_TOKEN>`, `X-Agent-Env-Id: <ENV_ID>`; body is
121
+ the report payload plus `source_session_id`. The backend verifies the session
122
+ belongs to this environment's agent and owner, and resolves the task from the
123
+ session. Any 2xx is success.
124
+
125
+ Related, not in this repo: cinna-core's cloud MCP task server exposes a
126
+ `handover_report` tool for the same executor-side report.
127
+
128
+ ## Edge cases & guardrails (preserve these)
129
+
130
+ - **Identity is target+key only** — title, brief, group, depth and `--execute`
131
+ must not enter `external_ref` or the delegation id, or retries would create
132
+ duplicates (`src/cinna/delegation.py:create()`).
133
+ - **No local dedup** — do not add a local "already created" cache; the backend
134
+ dedup is the single source of truth.
135
+ - **Depth/root validated client-side** — depth outside 1–2, `--root` at depth
136
+ 1, or missing `--root` at depth 2 are usage errors before any request.
137
+ - **Capability gate first** — every owner-side verb gates before its real call;
138
+ an unsupported server gets no task-route traffic.
139
+ - **Blocked requires a question; artifacts validated** — rejected client-side
140
+ (`report()`), never sent half-valid to the backend.
141
+ - **Executor env is mandatory** — missing `AGENT_AUTH_TOKEN`, `BACKEND_URL` or
142
+ `ENV_ID`, or an unreadable context / missing `backend_session_id`, fails
143
+ before any network call.
144
+ - **No redirects on the executor POST** — a redirect would forward the bearer
145
+ token to another origin; `follow_redirects=False` keeps it on `BACKEND_URL`.
146
+ - **Any 2xx accepted** — non-2xx becomes a `PlatformError` (exit 1 for 4xx,
147
+ 12 for 5xx) carrying the backend detail.
148
+ - **`--json` envelope** — always `{"result": "ok", "delegation": …}` via
149
+ `console.emit_result()`; errors use the standard `CinnaExit` JSON line.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cinna-cli"
3
- version = "0.4.2"
3
+ version = "0.4.3"
4
4
  description = "Local development CLI for Cinna Core agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"