cinna-cli 0.4.1__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 (113) hide show
  1. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/PKG-INFO +80 -9
  2. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/README.md +79 -8
  3. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/README.md +7 -5
  4. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace.md +7 -2
  5. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace_acceptance.md +11 -0
  6. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/account_workspace/account_workspace_tech.md +10 -0
  7. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons.md +23 -0
  8. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons_acceptance.md +34 -0
  9. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_addons/agent_addons_tech.md +29 -2
  10. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management.md +107 -11
  11. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management_acceptance.md +107 -5
  12. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_management/agent_management_tech.md +142 -4
  13. cinna_cli-0.4.3/docs/features/delegation/delegation.md +160 -0
  14. cinna_cli-0.4.3/docs/features/delegation/delegation_acceptance.md +250 -0
  15. cinna_cli-0.4.3/docs/features/delegation/delegation_tech.md +149 -0
  16. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning_acceptance.md +3 -3
  17. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync.md +19 -0
  18. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync_acceptance.md +46 -3
  19. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/live_sync/live_sync_tech.md +26 -0
  20. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/remote_chat/remote_chat.md +62 -1
  21. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/remote_chat/remote_chat_acceptance.md +93 -0
  22. cinna_cli-0.4.3/docs/features/remote_chat/remote_chat_tech.md +274 -0
  23. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec.md +10 -4
  24. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec_acceptance.md +21 -4
  25. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/remote_exec/remote_exec_tech.md +5 -1
  26. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/pyproject.toml +1 -1
  27. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/account.py +1115 -59
  28. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/chat.py +308 -27
  29. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/client.py +110 -0
  30. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/console.py +27 -3
  31. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/context.py +2 -0
  32. cinna_cli-0.4.3/src/cinna/delegation.py +380 -0
  33. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/git_versioning.py +2 -0
  34. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/main.py +592 -21
  35. cinna_cli-0.4.3/src/cinna/scenarios.py +602 -0
  36. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +59 -16
  37. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/templates/CHAT_TESTING.md +15 -0
  38. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/templates/CLAUDE.md.template +92 -22
  39. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_account.py +1214 -1
  40. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_chat.py +187 -0
  41. cinna_cli-0.4.3/tests/test_console.py +22 -0
  42. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_context.py +5 -0
  43. cinna_cli-0.4.3/tests/test_delegation.py +362 -0
  44. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_main.py +124 -1
  45. cinna_cli-0.4.3/tests/test_scenarios.py +413 -0
  46. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/uv.lock +1 -1
  47. cinna_cli-0.4.1/docs/features/remote_chat/remote_chat_tech.md +0 -159
  48. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/.claude/commands/cinna-cli.feature.doc.md +0 -0
  49. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/.github/workflows/publish.yml +0 -0
  50. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/.gitignore +0 -0
  51. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/LICENSE.md +0 -0
  52. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api.md +0 -0
  53. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api_acceptance.md +0 -0
  54. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_api/agent_api_tech.md +0 -0
  55. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules.md +0 -0
  56. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules_acceptance.md +0 -0
  57. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/agent_schedules/agent_schedules_tech.md +0 -0
  58. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +0 -0
  59. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +0 -0
  60. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +0 -0
  61. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/doctor/doctor.md +0 -0
  62. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/doctor/doctor_acceptance.md +0 -0
  63. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/doctor/doctor_tech.md +0 -0
  64. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning.md +0 -0
  65. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/git_versioning/git_versioning_tech.md +0 -0
  66. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests.md +0 -0
  67. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests_acceptance.md +0 -0
  68. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/improvement_requests/improvement_requests_tech.md +0 -0
  69. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import.md +0 -0
  70. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import_acceptance.md +0 -0
  71. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/local_agent_import/local_agent_import_tech.md +0 -0
  72. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration.md +0 -0
  73. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration_acceptance.md +0 -0
  74. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/features/mcp_integration/mcp_integration_tech.md +0 -0
  75. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/interface.md +0 -0
  76. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/docs/mutagen_capabilities.md +0 -0
  77. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/scripts/check_docs_references.py +0 -0
  78. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/__init__.py +0 -0
  79. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/auth.py +0 -0
  80. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/bootstrap.py +0 -0
  81. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/cli_version.py +0 -0
  82. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/config.py +0 -0
  83. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/doctor.py +0 -0
  84. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/errors.py +0 -0
  85. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/improve.py +0 -0
  86. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/kit_contract.py +0 -0
  87. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/local_import.py +0 -0
  88. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/logging.py +0 -0
  89. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/mcp_proxy.py +0 -0
  90. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/mutagen_runtime.py +0 -0
  91. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/sync.py +0 -0
  92. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/sync_session.py +0 -0
  93. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/sync_ssh_shim.py +0 -0
  94. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/sync_tui.py +0 -0
  95. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/templates/GIT_VERSIONING.md +0 -0
  96. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/src/cinna/templates/__init__.py +0 -0
  97. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/__init__.py +0 -0
  98. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/conftest.py +0 -0
  99. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_auth.py +0 -0
  100. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_bootstrap.py +0 -0
  101. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_cli_version.py +0 -0
  102. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_client.py +0 -0
  103. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_config.py +0 -0
  104. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_doctor.py +0 -0
  105. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_git_versioning.py +0 -0
  106. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_improve.py +0 -0
  107. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_kit_contract.py +0 -0
  108. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_local_import.py +0 -0
  109. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_mutagen_runtime.py +0 -0
  110. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_onboarding.py +0 -0
  111. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_sync.py +0 -0
  112. {cinna_cli-0.4.1 → cinna_cli-0.4.3}/tests/test_sync_session.py +0 -0
  113. {cinna_cli-0.4.1 → 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.1
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
@@ -211,7 +211,9 @@ cinna account credentials types # types + the
211
211
  cinna account credentials create --name "Stripe Key" --type api_token \
212
212
  --agent billing-agent # create a draft and attach it in one step
213
213
  # → prints required fields (e.g. api_token) + a link to fill them in
214
- cinna account credentials list # name, type, status (complete / needs setup)
214
+ cinna account credentials list # name, type, slot, status (complete / needs setup), id
215
+ cinna account credentials list --json # the raw listing
216
+ cinna account credentials update <cred_id> --service-uri some-token.com # give it the slot a skill declares
215
217
  cinna account credentials share-with-agent <cred_id> --agent crm-agent
216
218
  cinna account credentials update <cred_id> --name "Stripe (live)"
217
219
  cinna account credentials delete <cred_id> --yes
@@ -263,19 +265,60 @@ cinna agent sync crm-agent
263
265
 
264
266
  ### `cinna agent sync <agent>`
265
267
 
266
- Mint a per-agent CLI token (no UI interaction) and materialize a standard workspace under `agents/<slug>/`. `<agent>` is the display name, slug, or agent ID from `cinna account agents`. The result is identical to what `cinna setup` produces — own `.cinna/config.json`, registry entry, generated `CLAUDE.md` / `BUILDING_AGENT.md` / MCP configs / `mutagen.yml`, and the initial workspace clone — so afterwards:
268
+ Mint a per-agent CLI token (no UI interaction) and materialize a standard workspace under `agents/<slug>/<subdir>/` (the Model-A nested layout — `<subdir>` is the slug unless the agent is git-versioned with another one; the command prints the exact path). `<agent>` is the display name, slug, or agent ID from `cinna account agents`. The result is identical to what `cinna setup` produces — own `.cinna/config.json`, registry entry, generated `CLAUDE.md` / `BUILDING_AGENT.md` / MCP configs / `mutagen.yml`, and the initial workspace clone — so afterwards:
267
269
 
268
270
  ```bash
269
- cd agents/hr-manager-agent/
271
+ cd agents/hr-manager-agent/hr-manager-agent/
270
272
  cinna dev
271
273
  ```
272
274
 
273
275
  works exactly as for a manually set-up agent. Synced agents also appear in `cinna list` and in the agent's Integrations-tab session list like any other CLI session. The backend gates minting on building rights: foreign bundle installs and view-only agents are rejected with the server's error message.
274
276
 
277
+ It also **starts the sync session and flushes it once**, while local and remote are still the same clone, so edits made afterwards sync as plain changes — a session first created by a later `cinna sync push` has no common starting point and reported the builder's own edits as conflicts. If the session cannot start (Mutagen missing, environment unreachable) the sync still succeeds with a warning to run `cinna sync push --agent <slug>` before editing.
278
+
275
279
  ### `cinna agent unsync <agent>`
276
280
 
277
281
  Detach a synced workspace: stop its sync session, revoke the minted CLI token server-side (via the account-scoped revoke endpoint, authenticated with the account token; idempotent), then perform the equivalent of `cinna disconnect`: remove `.cinna/`, generated files, and the registry entry. Workspace files under `agents/<slug>/workspace/` are preserved. The revoke degrades gracefully — if it fails (no connection, or a workspace synced before token-id tracking), a warning is printed and the local teardown still completes; the token then expires on its own or can be revoked from the agent's Integrations tab.
278
282
 
283
+ ### `cinna agent prompts pull | diff | push <agent> [--dir DIR]`
284
+
285
+ Edit an agent's prompts as files instead of raw `cinna api` calls (whose inline JSON let the shell command-substitute a prompt's Markdown backticks).
286
+
287
+ ```bash
288
+ cinna agent prompts pull crm-agent # → prompts/crm-agent/{workflow,entrypoint,refiner,router_trigger,description}.md + example_prompts.json
289
+ cinna agent prompts diff crm-agent # local edits vs the platform
290
+ cinna agent prompts push crm-agent --dry-run
291
+ cinna agent prompts push crm-agent # one bulk write, then the doc prompts into the running env
292
+ ```
293
+
294
+ `pull` records what it pulled in `.pulled.json` and refuses to overwrite unpushed edits, files it did not write, or another agent's prompts without `--force`. `push` sends **only the fields edited since the pull**: a field the platform changed meanwhile is left alone when you did not edit it, and refused when you did (`--force` keeps yours; `pull --force` takes the platform's). After the write it calls the env's prompt sync when a workflow/entrypoint/refiner field changed (`--no-sync-env` to skip; a stopped environment picks them up on its next start). Delete a file to leave its field untouched. The agent config is authoritative — hand-editing the synced `workspace/docs/*.md` as well is a last-writer-wins race.
295
+
296
+ `cinna agent show <agent>` prints each prompt under its `[entrypoint]` / `[workflow]` / `[refiner]` label and each connected credential with its type, slot, setup state and id. `cinna agent rebuild-env <agent>` waits after the rebuild until the environment answers its health check, and says "ready to chat" only then. `cinna agent restart-env` re-runs the same image and does not update the container's core or SDK helpers.
297
+
298
+ ### `cinna agent model show | set <agent>`
299
+
300
+ The model is a setting of the agent's environment, not of the agent. `show` prints each mode's SDK, model override, effective model and health; `set` changes only what you pass and rebuilds.
301
+
302
+ ```bash
303
+ cinna agent model show crm-agent
304
+ cinna agent model set crm-agent --conversation haiku # rebuilds, waits for the health check
305
+ cinna agent model set crm-agent --building default --no-rebuild # clear the override; apply on the next rebuild-env
306
+ ```
307
+
308
+ `default` clears an override, or with `--conversation-credential` / `--building-credential` unpins an AI credential. The other mode and the credential pins keep their values, a setting already in place is a no-op, and `unknown_model` right after a set is usually a typo in the model id. Refused on a foreign install.
309
+
310
+ ### `cinna agent scenarios list | run <agent>`
311
+
312
+ Re-run the agent's recorded `docs/test_scenarios/*.md` — each file's `## Say | Expect` table — without one `cinna chat` per row.
313
+
314
+ ```bash
315
+ cinna agent scenarios list crm-agent
316
+ cinna agent scenarios run crm-agent --out run.md
317
+ cinna agent scenarios run crm-agent scope_and_pushback --yes --json
318
+ ```
319
+
320
+ Every Say row goes to a fresh session, one after another. Each case reports the reply, the tool calls, the outcome and the session id, under a header naming the conversation model. The run does not judge: mark each row against its Expect. A case that does not complete prints its `cinna chat --attach` command, is not re-sent, and makes the command exit non-zero. The files are read from the synced workspace (`--path DIR` for any other folder) and never pushed.
321
+
279
322
  ### `cinna agent import <path> [--name TEXT] [--workspace REF] [--update] [--dry-run] [--no-push] [--yes]`
280
323
 
281
324
  Import an agent that was built **locally** with the [Local Agent Kit](docs/features/local_agent_import/local_agent_import.md) — a folder holding a `cinna-agent.json` manifest, typically `../Local/<slug>` next to this account workspace. Run it from the account workspace root (or any folder inside it).
@@ -328,6 +371,8 @@ before skills carried one, which fills in after the next refresh or publish.
328
371
 
329
372
  The **Version** column is what the agent carries (`installed_version`), and an installed addon whose catalog has moved since reads `1.0.0 → 1.1.0` with the update command named under the table — an agent sitting two revisions back must not look identical to a current one. `Name` is the engine-facing folder name — the string `cinna skills publish` takes back — with the display name beside it when they differ. `· published` marks a local skill that already has a catalog package, so a re-publish appends a revision instead of creating a second package. The status column carries the server's own code (`secrets`, `oversized`, `shadowed` for warnings; `missing_description`, `name_mismatch`, `source_unavailable`, `orphan` for errors), and the platform's own sentence for each flagged row — with the offending files for `secrets` — follows under the table. Reads the server's cache, so it never wakes a sleeping environment: when the skill half could not be read the plugin rows still list and the reason is printed (`env_not_running`, `adapter_error`, `parse_error`) instead of a short list looking complete. `--json` prints the raw payload (`addons`, `counts`, `skills_error`) for a script or a local coding agent.
330
373
 
374
+ When any skill declares credential slots (a `credentials:` block in its `SKILL.md`), a **Credentials** column lists each slot: `✓` filled, `! <reason>` not usable yet, `?` unchecked. Beneath the table each unusable slot gets its fix — e.g. naming the linked `api_token` credential that has no slot with `cinna account credentials update <id> --service-uri <slot>`, or a `credentials create … --service-uri <slot> --agent <agent>` draft when nothing could carry it. For a catalog install the reason is the platform's own (`not_linked`, `not_configured`, `access_revoked`); for a local or bundle skill an older platform computes nothing, so the CLI checks the agent's linked credentials itself (`not_linked`, `not_configured`, `type_mismatch`). A platform that does judge local skills has no `type_mismatch`, so a slot it calls `not_linked` while a linked credential of another type carries it is shown as `type_mismatch` — never as a draft for a second credential on that slot. A slot's value is read from the account credential listing, because the agent's own credential route reports none; a credential shared by someone else whose slot is not visible makes the slot `?`, never `not_linked`. The check is display-only: `--json` stays the raw payload.
375
+
331
376
  ### `cinna skills publish <agent> <name> [--visibility public|private|users] [--grant EMAIL ...] [--version V] [--notes TEXT] [--package-id ID] [--dry-run] [--yes] [--json]`
332
377
 
333
378
  Publish one of the agent's own skills to the instance skills catalog, where other agents can install it. `<name>` is the folder name from `cinna skills list`. Requires the `agent-developer` role on an agent that is not a foreign install; the skill must be clean (no parse error, no files that look like key material).
@@ -488,6 +533,9 @@ Run it from the account workspace (or any synced agent folder under it). The rep
488
533
  - Each `message` carries the agent's reasoning/tool trace under **`events`** — an ordered list of the `thinking` blocks, `tool` calls (with their full `tool_input` payload) and tool results behind the reply, so you see *what the agent did*, not just its final `content`. Pass `--no-events` to drop the trace and keep only the final text.
489
534
  - Files the agent attaches to its replies are downloaded under `./cinna-chat-files/<session_id>/` (override with `--download-dir`, or skip with `--no-download` to just report the file ids). Downloads are bounded by the api-proxy's 8 MiB response cap.
490
535
  - `--interval` / `--timeout` tune the poll cadence and the maximum wait for a turn. Ctrl-C interrupts the agent's turn and exits.
536
+ - A poll request that fails transiently (a proxy timeout, a 429, a 5xx) is **retried within `--timeout`**, each retry announced as a `warning` event — the turn runs on the platform regardless. If contact is lost for good the command exits `12` with an `error` event carrying `session_id` and `recover`.
537
+ - The closing `done` event always carries `outcome` — `completed`, `timeout` or `not_started` (`in_progress` / `idle` for `--show`) — plus `recover` when the turn may still be running.
538
+ - `--attach <session_id>` sends nothing: it waits for that session's current turn and prints it, the way back into a turn a dead command left running (Ctrl-C only stops watching). `--show <session_id>` prints a session's transcript once and waits for nothing.
491
539
 
492
540
  ```bash
493
541
  cinna chat --agent crm-agent "Summarize today's leads"
@@ -495,9 +543,32 @@ cinna chat --agent crm-agent --file report.csv "Validate this export"
495
543
  cinna chat --resume 3fa85f64-5717-4562-b3fc-2c963f66afa6 "Now break it down by region"
496
544
  echo "ping" | cinna chat --agent crm-agent # message from stdin
497
545
  cinna chat --agent crm-agent "hi" | jq -c 'select(.event=="message")'
546
+ cinna chat --attach 3fa85f64-5717-4562-b3fc-2c963f66afa6 # recover a turn after a timeout
547
+ cinna chat --show 3fa85f64-5717-4562-b3fc-2c963f66afa6 # read a transcript
548
+ ```
549
+
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
+
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
498
569
  ```
499
570
 
500
- The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`.
571
+ Inside cloud tasks, cinna-core's MCP task server also offers a `handover_report` tool for the same report.
501
572
 
502
573
  ### `cinna dev`
503
574
 
@@ -519,8 +590,8 @@ cinna redev # remote wins the initial conflicts, then a normal dev session
519
590
  Inspect and drive the sync session. `status` / `conflicts` are read-only views (safe alongside a live `cinna dev`); `push` / `pull` / `resolve` are for scripted (headless) builders who aren't running the TUI. All accept `--agent <ref>` to target a synced child workspace from the account root.
520
591
 
521
592
  - `status` — state, pending changes, conflict count. Warns loudly when conflicts mean your edits aren't fully live.
522
- - `conflicts` — list conflicted paths (sourced from the Mutagen daemon, so it agrees with `status`; two-way-safe writes no `.conflict.*` files on disk).
523
- - `push [--force]` — ensure a session, then flush and block until settled. `--force` resolves any parked conflicts in favor of **local** first ("my local is the truth"). The session persists in the daemon so later edits keep syncing.
593
+ - `conflicts [--diff]` — list conflicted paths (sourced from the Mutagen daemon, so it agrees with `status`; two-way-safe writes no `.conflict.*` files on disk). `--diff` compares both copies of each path — size, sha256, a unified diff (remote → local) for text, and "identical content" / "only one copy exists" when the facts say so — reading the remote side in one `cinna exec`, and still showing the local side if the environment cannot answer.
594
+ - `push [--force]` — ensure a session, then flush and block until settled. `--force` resolves any parked conflicts in favor of **local** first ("my local is the truth"). The session persists in the daemon so later edits keep syncing. A flush that ends with conflicts never prints "Sync settled": it warns with the count and points at `conflicts --diff`. (`cinna agent sync` already started the session on the fresh clone, so edits made after attaching don't come back as conflicts.)
524
595
  - `pull [--force]` — the mirror; `--force` resolves in favor of **remote** (e.g. after the backend regenerates managed files).
525
596
  - `resolve --prefer local|remote` — clear parked conflicts in one command. `local` deletes the remote losing copies (your version propagates out); `remote` backs up your local copies under `.cinna/sync/` and takes the container's version. Replaces the manual kill/delete/restart dance.
526
597
 
@@ -528,7 +599,7 @@ Inspect and drive the sync session. `status` / `conflicts` are read-only views (
528
599
 
529
600
  Stream a command through the platform to the remote agent environment. Output streams back live; Ctrl+C aborts. Exit code matches the remote process.
530
601
 
531
- The command runs with the **workspace root (`/app/workspace`) as its working directory**, so relative paths resolve against the synced workspace — e.g. `cinna exec python scripts/main.py` runs `/app/workspace/scripts/main.py` (the same cwd the scheduler uses). No need to prefix paths with `/app/workspace/`.
602
+ The command runs with the **workspace root (`/app/workspace`) as its working directory**, so relative paths resolve against the synced workspace — e.g. `cinna exec python scripts/main.py` runs `/app/workspace/scripts/main.py` (the same cwd the scheduler uses). No need to prefix paths with `/app/workspace/`. `--cwd /app` starts at the container's app root instead. The command must be a program, not a shell builtin — hand pipes, redirects and `&&` to a shell: `cinna exec sh -c 'a | b'`.
532
603
 
533
604
  Arguments pass through transparently — each token is re-quoted before being sent, so spaces and shell metacharacters inside an argument survive intact. Use ordinary single-level quoting, exactly as for a local command. To run a shell snippet (pipes, redirects, `&&`), pass it to a shell explicitly: `cinna exec bash -c '…'`.
534
605
 
@@ -652,7 +723,7 @@ claude # or: opencode
652
723
 
653
724
  ## Sync & Conflict Resolution
654
725
 
655
- `cinna sync` drives Mutagen in `two-way-safe` mode with VCS-aware ignores (including the backend-managed `credentials/` directory, so it never conflicts on files you're told not to edit). When the same file changes on both sides, Mutagen parks a conflict (it does **not** pick a winner, and does not write `.conflict.*` files in this mode) — list them with `cinna sync conflicts`, then clear them with `cinna sync resolve --prefer local` (your edits win) or `--prefer remote` (the container's version wins). For a non-interactive flush, `cinna sync push` / `cinna sync pull` settle the session and exit.
726
+ `cinna sync` drives Mutagen in `two-way-safe` mode with VCS-aware ignores (including the backend-managed `credentials/` directory, so it never conflicts on files you're told not to edit). When the same file changes on both sides, Mutagen parks a conflict (it does **not** pick a winner, and does not write `.conflict.*` files in this mode) — list them with `cinna sync conflicts` (add `--diff` to compare the two copies of each), then clear them with `cinna sync resolve --prefer local` (your edits win) or `--prefer remote` (the container's version wins). For a non-interactive flush, `cinna sync push` / `cinna sync pull` settle the session and exit.
656
727
 
657
728
  Large binary files and build artifacts are ignored by default (see `mutagen.yml`). Add your own ignores there if needed.
658
729
 
@@ -174,7 +174,9 @@ cinna account credentials types # types + the
174
174
  cinna account credentials create --name "Stripe Key" --type api_token \
175
175
  --agent billing-agent # create a draft and attach it in one step
176
176
  # → prints required fields (e.g. api_token) + a link to fill them in
177
- cinna account credentials list # name, type, status (complete / needs setup)
177
+ cinna account credentials list # name, type, slot, status (complete / needs setup), id
178
+ cinna account credentials list --json # the raw listing
179
+ cinna account credentials update <cred_id> --service-uri some-token.com # give it the slot a skill declares
178
180
  cinna account credentials share-with-agent <cred_id> --agent crm-agent
179
181
  cinna account credentials update <cred_id> --name "Stripe (live)"
180
182
  cinna account credentials delete <cred_id> --yes
@@ -226,19 +228,60 @@ cinna agent sync crm-agent
226
228
 
227
229
  ### `cinna agent sync <agent>`
228
230
 
229
- Mint a per-agent CLI token (no UI interaction) and materialize a standard workspace under `agents/<slug>/`. `<agent>` is the display name, slug, or agent ID from `cinna account agents`. The result is identical to what `cinna setup` produces — own `.cinna/config.json`, registry entry, generated `CLAUDE.md` / `BUILDING_AGENT.md` / MCP configs / `mutagen.yml`, and the initial workspace clone — so afterwards:
231
+ Mint a per-agent CLI token (no UI interaction) and materialize a standard workspace under `agents/<slug>/<subdir>/` (the Model-A nested layout — `<subdir>` is the slug unless the agent is git-versioned with another one; the command prints the exact path). `<agent>` is the display name, slug, or agent ID from `cinna account agents`. The result is identical to what `cinna setup` produces — own `.cinna/config.json`, registry entry, generated `CLAUDE.md` / `BUILDING_AGENT.md` / MCP configs / `mutagen.yml`, and the initial workspace clone — so afterwards:
230
232
 
231
233
  ```bash
232
- cd agents/hr-manager-agent/
234
+ cd agents/hr-manager-agent/hr-manager-agent/
233
235
  cinna dev
234
236
  ```
235
237
 
236
238
  works exactly as for a manually set-up agent. Synced agents also appear in `cinna list` and in the agent's Integrations-tab session list like any other CLI session. The backend gates minting on building rights: foreign bundle installs and view-only agents are rejected with the server's error message.
237
239
 
240
+ It also **starts the sync session and flushes it once**, while local and remote are still the same clone, so edits made afterwards sync as plain changes — a session first created by a later `cinna sync push` has no common starting point and reported the builder's own edits as conflicts. If the session cannot start (Mutagen missing, environment unreachable) the sync still succeeds with a warning to run `cinna sync push --agent <slug>` before editing.
241
+
238
242
  ### `cinna agent unsync <agent>`
239
243
 
240
244
  Detach a synced workspace: stop its sync session, revoke the minted CLI token server-side (via the account-scoped revoke endpoint, authenticated with the account token; idempotent), then perform the equivalent of `cinna disconnect`: remove `.cinna/`, generated files, and the registry entry. Workspace files under `agents/<slug>/workspace/` are preserved. The revoke degrades gracefully — if it fails (no connection, or a workspace synced before token-id tracking), a warning is printed and the local teardown still completes; the token then expires on its own or can be revoked from the agent's Integrations tab.
241
245
 
246
+ ### `cinna agent prompts pull | diff | push <agent> [--dir DIR]`
247
+
248
+ Edit an agent's prompts as files instead of raw `cinna api` calls (whose inline JSON let the shell command-substitute a prompt's Markdown backticks).
249
+
250
+ ```bash
251
+ cinna agent prompts pull crm-agent # → prompts/crm-agent/{workflow,entrypoint,refiner,router_trigger,description}.md + example_prompts.json
252
+ cinna agent prompts diff crm-agent # local edits vs the platform
253
+ cinna agent prompts push crm-agent --dry-run
254
+ cinna agent prompts push crm-agent # one bulk write, then the doc prompts into the running env
255
+ ```
256
+
257
+ `pull` records what it pulled in `.pulled.json` and refuses to overwrite unpushed edits, files it did not write, or another agent's prompts without `--force`. `push` sends **only the fields edited since the pull**: a field the platform changed meanwhile is left alone when you did not edit it, and refused when you did (`--force` keeps yours; `pull --force` takes the platform's). After the write it calls the env's prompt sync when a workflow/entrypoint/refiner field changed (`--no-sync-env` to skip; a stopped environment picks them up on its next start). Delete a file to leave its field untouched. The agent config is authoritative — hand-editing the synced `workspace/docs/*.md` as well is a last-writer-wins race.
258
+
259
+ `cinna agent show <agent>` prints each prompt under its `[entrypoint]` / `[workflow]` / `[refiner]` label and each connected credential with its type, slot, setup state and id. `cinna agent rebuild-env <agent>` waits after the rebuild until the environment answers its health check, and says "ready to chat" only then. `cinna agent restart-env` re-runs the same image and does not update the container's core or SDK helpers.
260
+
261
+ ### `cinna agent model show | set <agent>`
262
+
263
+ The model is a setting of the agent's environment, not of the agent. `show` prints each mode's SDK, model override, effective model and health; `set` changes only what you pass and rebuilds.
264
+
265
+ ```bash
266
+ cinna agent model show crm-agent
267
+ cinna agent model set crm-agent --conversation haiku # rebuilds, waits for the health check
268
+ cinna agent model set crm-agent --building default --no-rebuild # clear the override; apply on the next rebuild-env
269
+ ```
270
+
271
+ `default` clears an override, or with `--conversation-credential` / `--building-credential` unpins an AI credential. The other mode and the credential pins keep their values, a setting already in place is a no-op, and `unknown_model` right after a set is usually a typo in the model id. Refused on a foreign install.
272
+
273
+ ### `cinna agent scenarios list | run <agent>`
274
+
275
+ Re-run the agent's recorded `docs/test_scenarios/*.md` — each file's `## Say | Expect` table — without one `cinna chat` per row.
276
+
277
+ ```bash
278
+ cinna agent scenarios list crm-agent
279
+ cinna agent scenarios run crm-agent --out run.md
280
+ cinna agent scenarios run crm-agent scope_and_pushback --yes --json
281
+ ```
282
+
283
+ Every Say row goes to a fresh session, one after another. Each case reports the reply, the tool calls, the outcome and the session id, under a header naming the conversation model. The run does not judge: mark each row against its Expect. A case that does not complete prints its `cinna chat --attach` command, is not re-sent, and makes the command exit non-zero. The files are read from the synced workspace (`--path DIR` for any other folder) and never pushed.
284
+
242
285
  ### `cinna agent import <path> [--name TEXT] [--workspace REF] [--update] [--dry-run] [--no-push] [--yes]`
243
286
 
244
287
  Import an agent that was built **locally** with the [Local Agent Kit](docs/features/local_agent_import/local_agent_import.md) — a folder holding a `cinna-agent.json` manifest, typically `../Local/<slug>` next to this account workspace. Run it from the account workspace root (or any folder inside it).
@@ -291,6 +334,8 @@ before skills carried one, which fills in after the next refresh or publish.
291
334
 
292
335
  The **Version** column is what the agent carries (`installed_version`), and an installed addon whose catalog has moved since reads `1.0.0 → 1.1.0` with the update command named under the table — an agent sitting two revisions back must not look identical to a current one. `Name` is the engine-facing folder name — the string `cinna skills publish` takes back — with the display name beside it when they differ. `· published` marks a local skill that already has a catalog package, so a re-publish appends a revision instead of creating a second package. The status column carries the server's own code (`secrets`, `oversized`, `shadowed` for warnings; `missing_description`, `name_mismatch`, `source_unavailable`, `orphan` for errors), and the platform's own sentence for each flagged row — with the offending files for `secrets` — follows under the table. Reads the server's cache, so it never wakes a sleeping environment: when the skill half could not be read the plugin rows still list and the reason is printed (`env_not_running`, `adapter_error`, `parse_error`) instead of a short list looking complete. `--json` prints the raw payload (`addons`, `counts`, `skills_error`) for a script or a local coding agent.
293
336
 
337
+ When any skill declares credential slots (a `credentials:` block in its `SKILL.md`), a **Credentials** column lists each slot: `✓` filled, `! <reason>` not usable yet, `?` unchecked. Beneath the table each unusable slot gets its fix — e.g. naming the linked `api_token` credential that has no slot with `cinna account credentials update <id> --service-uri <slot>`, or a `credentials create … --service-uri <slot> --agent <agent>` draft when nothing could carry it. For a catalog install the reason is the platform's own (`not_linked`, `not_configured`, `access_revoked`); for a local or bundle skill an older platform computes nothing, so the CLI checks the agent's linked credentials itself (`not_linked`, `not_configured`, `type_mismatch`). A platform that does judge local skills has no `type_mismatch`, so a slot it calls `not_linked` while a linked credential of another type carries it is shown as `type_mismatch` — never as a draft for a second credential on that slot. A slot's value is read from the account credential listing, because the agent's own credential route reports none; a credential shared by someone else whose slot is not visible makes the slot `?`, never `not_linked`. The check is display-only: `--json` stays the raw payload.
338
+
294
339
  ### `cinna skills publish <agent> <name> [--visibility public|private|users] [--grant EMAIL ...] [--version V] [--notes TEXT] [--package-id ID] [--dry-run] [--yes] [--json]`
295
340
 
296
341
  Publish one of the agent's own skills to the instance skills catalog, where other agents can install it. `<name>` is the folder name from `cinna skills list`. Requires the `agent-developer` role on an agent that is not a foreign install; the skill must be clean (no parse error, no files that look like key material).
@@ -451,6 +496,9 @@ Run it from the account workspace (or any synced agent folder under it). The rep
451
496
  - Each `message` carries the agent's reasoning/tool trace under **`events`** — an ordered list of the `thinking` blocks, `tool` calls (with their full `tool_input` payload) and tool results behind the reply, so you see *what the agent did*, not just its final `content`. Pass `--no-events` to drop the trace and keep only the final text.
452
497
  - Files the agent attaches to its replies are downloaded under `./cinna-chat-files/<session_id>/` (override with `--download-dir`, or skip with `--no-download` to just report the file ids). Downloads are bounded by the api-proxy's 8 MiB response cap.
453
498
  - `--interval` / `--timeout` tune the poll cadence and the maximum wait for a turn. Ctrl-C interrupts the agent's turn and exits.
499
+ - A poll request that fails transiently (a proxy timeout, a 429, a 5xx) is **retried within `--timeout`**, each retry announced as a `warning` event — the turn runs on the platform regardless. If contact is lost for good the command exits `12` with an `error` event carrying `session_id` and `recover`.
500
+ - The closing `done` event always carries `outcome` — `completed`, `timeout` or `not_started` (`in_progress` / `idle` for `--show`) — plus `recover` when the turn may still be running.
501
+ - `--attach <session_id>` sends nothing: it waits for that session's current turn and prints it, the way back into a turn a dead command left running (Ctrl-C only stops watching). `--show <session_id>` prints a session's transcript once and waits for nothing.
454
502
 
455
503
  ```bash
456
504
  cinna chat --agent crm-agent "Summarize today's leads"
@@ -458,9 +506,32 @@ cinna chat --agent crm-agent --file report.csv "Validate this export"
458
506
  cinna chat --resume 3fa85f64-5717-4562-b3fc-2c963f66afa6 "Now break it down by region"
459
507
  echo "ping" | cinna chat --agent crm-agent # message from stdin
460
508
  cinna chat --agent crm-agent "hi" | jq -c 'select(.event=="message")'
509
+ cinna chat --attach 3fa85f64-5717-4562-b3fc-2c963f66afa6 # recover a turn after a timeout
510
+ cinna chat --show 3fa85f64-5717-4562-b3fc-2c963f66afa6 # read a transcript
511
+ ```
512
+
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
+
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
461
532
  ```
462
533
 
463
- The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`.
534
+ Inside cloud tasks, cinna-core's MCP task server also offers a `handover_report` tool for the same report.
464
535
 
465
536
  ### `cinna dev`
466
537
 
@@ -482,8 +553,8 @@ cinna redev # remote wins the initial conflicts, then a normal dev session
482
553
  Inspect and drive the sync session. `status` / `conflicts` are read-only views (safe alongside a live `cinna dev`); `push` / `pull` / `resolve` are for scripted (headless) builders who aren't running the TUI. All accept `--agent <ref>` to target a synced child workspace from the account root.
483
554
 
484
555
  - `status` — state, pending changes, conflict count. Warns loudly when conflicts mean your edits aren't fully live.
485
- - `conflicts` — list conflicted paths (sourced from the Mutagen daemon, so it agrees with `status`; two-way-safe writes no `.conflict.*` files on disk).
486
- - `push [--force]` — ensure a session, then flush and block until settled. `--force` resolves any parked conflicts in favor of **local** first ("my local is the truth"). The session persists in the daemon so later edits keep syncing.
556
+ - `conflicts [--diff]` — list conflicted paths (sourced from the Mutagen daemon, so it agrees with `status`; two-way-safe writes no `.conflict.*` files on disk). `--diff` compares both copies of each path — size, sha256, a unified diff (remote → local) for text, and "identical content" / "only one copy exists" when the facts say so — reading the remote side in one `cinna exec`, and still showing the local side if the environment cannot answer.
557
+ - `push [--force]` — ensure a session, then flush and block until settled. `--force` resolves any parked conflicts in favor of **local** first ("my local is the truth"). The session persists in the daemon so later edits keep syncing. A flush that ends with conflicts never prints "Sync settled": it warns with the count and points at `conflicts --diff`. (`cinna agent sync` already started the session on the fresh clone, so edits made after attaching don't come back as conflicts.)
487
558
  - `pull [--force]` — the mirror; `--force` resolves in favor of **remote** (e.g. after the backend regenerates managed files).
488
559
  - `resolve --prefer local|remote` — clear parked conflicts in one command. `local` deletes the remote losing copies (your version propagates out); `remote` backs up your local copies under `.cinna/sync/` and takes the container's version. Replaces the manual kill/delete/restart dance.
489
560
 
@@ -491,7 +562,7 @@ Inspect and drive the sync session. `status` / `conflicts` are read-only views (
491
562
 
492
563
  Stream a command through the platform to the remote agent environment. Output streams back live; Ctrl+C aborts. Exit code matches the remote process.
493
564
 
494
- The command runs with the **workspace root (`/app/workspace`) as its working directory**, so relative paths resolve against the synced workspace — e.g. `cinna exec python scripts/main.py` runs `/app/workspace/scripts/main.py` (the same cwd the scheduler uses). No need to prefix paths with `/app/workspace/`.
565
+ The command runs with the **workspace root (`/app/workspace`) as its working directory**, so relative paths resolve against the synced workspace — e.g. `cinna exec python scripts/main.py` runs `/app/workspace/scripts/main.py` (the same cwd the scheduler uses). No need to prefix paths with `/app/workspace/`. `--cwd /app` starts at the container's app root instead. The command must be a program, not a shell builtin — hand pipes, redirects and `&&` to a shell: `cinna exec sh -c 'a | b'`.
495
566
 
496
567
  Arguments pass through transparently — each token is re-quoted before being sent, so spaces and shell metacharacters inside an argument survive intact. Use ordinary single-level quoting, exactly as for a local command. To run a shell snippet (pipes, redirects, `&&`), pass it to a shell explicitly: `cinna exec bash -c '…'`.
497
568
 
@@ -615,7 +686,7 @@ claude # or: opencode
615
686
 
616
687
  ## Sync & Conflict Resolution
617
688
 
618
- `cinna sync` drives Mutagen in `two-way-safe` mode with VCS-aware ignores (including the backend-managed `credentials/` directory, so it never conflicts on files you're told not to edit). When the same file changes on both sides, Mutagen parks a conflict (it does **not** pick a winner, and does not write `.conflict.*` files in this mode) — list them with `cinna sync conflicts`, then clear them with `cinna sync resolve --prefer local` (your edits win) or `--prefer remote` (the container's version wins). For a non-interactive flush, `cinna sync push` / `cinna sync pull` settle the session and exit.
689
+ `cinna sync` drives Mutagen in `two-way-safe` mode with VCS-aware ignores (including the backend-managed `credentials/` directory, so it never conflicts on files you're told not to edit). When the same file changes on both sides, Mutagen parks a conflict (it does **not** pick a winner, and does not write `.conflict.*` files in this mode) — list them with `cinna sync conflicts` (add `--diff` to compare the two copies of each), then clear them with `cinna sync resolve --prefer local` (your edits win) or `--prefer remote` (the container's version wins). For a non-interactive flush, `cinna sync push` / `cinna sync pull` settle the session and exit.
619
690
 
620
691
  Large binary files and build artifacts are ignored by default (see `mutagen.yml`). Add your own ignores there if needed.
621
692
 
@@ -201,6 +201,7 @@ main.py (CLI commands — Click)
201
201
  ├── account.py — account workspace; `cinna login` (device auth), `cinna account`, `cinna agent`
202
202
  ├── doctor.py — `cinna doctor`: reconcile registry ↔ Mutagen, delete stalled / terminate active sessions, refresh tokens
203
203
  ├── chat.py — `cinna chat`: session-backed conversation testing (poll + NDJSON) over the api-proxy
204
+ ├── scenarios.py — `cinna agent scenarios`: parse docs/test_scenarios Say | Expect tables, replay each row via chat.py
204
205
  ├── improve.py — `cinna improve`: improvement requests users shared about your agents (list/show/download/status)
205
206
  ├── local_import.py — `cinna agent import`: the Local Agent Kit go-cloud step
206
207
  ├── kit_contract.py — the Local Agent Kit contract as data (`.cinna-kit/layout.json`):
@@ -285,16 +286,17 @@ authoring convention.
285
286
  | Feature | Command surface | Docs |
286
287
  |---|---|---|
287
288
  | **Bootstrap & onboarding** | `cinna setup` / `set-token` / `login` / `list` / `status` / `disconnect[-all]` / `completion` / `dev` / `redev`; the no-TTY contract (`--no-input`, `--json`, exit codes, `CINNA_MUTAGEN_BIN`) | [business](features/bootstrap_onboarding/bootstrap_onboarding.md) · [tech](features/bootstrap_onboarding/bootstrap_onboarding_tech.md) · [acceptance](features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md) |
288
- | **Account workspace** | `cinna account` (setup, set-token, agents, status, refresh-context, user-workspace, credentials); desktop-managed workspaces | [business](features/account_workspace/account_workspace.md) · [tech](features/account_workspace/account_workspace_tech.md) · [acceptance](features/account_workspace/account_workspace_acceptance.md) |
289
- | **Agent management** | `cinna agent` (sync, unsync, create, restart-env, rebuild-env, show, status) | [business](features/agent_management/agent_management.md) · [tech](features/agent_management/agent_management_tech.md) · [acceptance](features/agent_management/agent_management_acceptance.md) |
289
+ | **Account workspace** | `cinna account` (setup, set-token, agents, status, refresh-context, user-workspace, credentials — `list` shows each credential's slot, `--json`); desktop-managed workspaces | [business](features/account_workspace/account_workspace.md) · [tech](features/account_workspace/account_workspace_tech.md) · [acceptance](features/account_workspace/account_workspace_acceptance.md) |
290
+ | **Agent management** | `cinna agent` (sync — which also starts the sync session, unsync, create, restart-env, rebuild-env — which waits for the health check, show — with each credential's slot, prompts pull / diff / push, model show / set — the model per mode, merged client-side and applied by a rebuild, status) | [business](features/agent_management/agent_management.md) · [tech](features/agent_management/agent_management_tech.md) · [acceptance](features/agent_management/agent_management_acceptance.md) |
290
291
  | **Agent schedules** | `cinna agent schedule` (list, generate, create, update, run, logs, delete) | [business](features/agent_schedules/agent_schedules.md) · [tech](features/agent_schedules/agent_schedules_tech.md) · [acceptance](features/agent_schedules/agent_schedules_acceptance.md) |
291
- | **Live sync** | `cinna sync` (status, conflicts, push, pull, resolve) + Mutagen transport | [business](features/live_sync/live_sync.md) · [tech](features/live_sync/live_sync_tech.md) · [acceptance](features/live_sync/live_sync_acceptance.md) |
292
+ | **Live sync** | `cinna sync` (status, conflicts `[--diff]`, push, pull, resolve) + Mutagen transport; the session is started by `cinna agent sync` so the first push has a baseline | [business](features/live_sync/live_sync.md) · [tech](features/live_sync/live_sync_tech.md) · [acceptance](features/live_sync/live_sync_acceptance.md) |
292
293
  | **Remote exec** | `cinna exec` | [business](features/remote_exec/remote_exec.md) · [tech](features/remote_exec/remote_exec_tech.md) · [acceptance](features/remote_exec/remote_exec_acceptance.md) |
293
- | **Remote chat** | `cinna chat` | [business](features/remote_chat/remote_chat.md) · [tech](features/remote_chat/remote_chat_tech.md) · [acceptance](features/remote_chat/remote_chat_acceptance.md) |
294
+ | **Remote chat** | `cinna chat` (incl. `--attach` / `--show` to recover or read an existing session; poll failures retried within `--timeout`) · `cinna agent scenarios list / run` (replay `docs/test_scenarios/` Say rows, one session per row) | <!-- nocheck: agent-workspace path --> [business](features/remote_chat/remote_chat.md) · [tech](features/remote_chat/remote_chat_tech.md) · [acceptance](features/remote_chat/remote_chat_acceptance.md) |
294
295
  | **Agent API** | `cinna agent-api` (enable, refresh, spec, call) · `cinna api` · `cinna connect agent-api` | [business](features/agent_api/agent_api.md) · [tech](features/agent_api/agent_api_tech.md) · [acceptance](features/agent_api/agent_api_acceptance.md) |
295
- | **Agent addons** | `cinna skills` (list, 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) |
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) |
296
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) |
297
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) |
298
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) |
299
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) |
300
302
 
@@ -154,8 +154,13 @@ each with its own token, registry entry, and Mutagen session.
154
154
  (the CLI sends no secret) in the active workspace and prints exactly which
155
155
  fields the user must complete plus the UI link. `--agent` attaches it in one
156
156
  step; `--workspace` overrides the target workspace.
157
- - `cinna account credentials list` shows credentials with their setup status
158
- (complete / needs setup) — metadata only.
157
+ - `cinna account credentials list` shows credentials with their type, **slot**,
158
+ setup status (complete / needs setup, plus a placeholder marker) and full id —
159
+ metadata only. The slot is the credential's service URI: the non-secret id a
160
+ skill's `credentials:` block names and a script looks the credential up by, so
161
+ it is the column that answers "which credential fills this skill's slot". The
162
+ hint under the table names `cinna account credentials update <id> --service-uri
163
+ <slot>`. `--json` prints the raw listing.
159
164
  - `cinna account credentials update <id>` edits metadata (name/notes/service-uri/
160
165
  sharing), never a secret. `cinna account credentials share-with-agent <id>
161
166
  --agent <ref>` attaches an existing credential. `cinna account credentials
@@ -161,6 +161,17 @@ the silent-secret and scope-drift bugs live.
161
161
  - **Watch for:** any secret-bearing field being sent from the CLI; the draft
162
162
  showing `complete` before the user fills it; the credential landing in the
163
163
  wrong workspace.
164
+ - **Then check the slot surfaces:**
165
+ ```
166
+ cinna account credentials update <cred-id> --service-uri stripe.com
167
+ cinna account credentials list | grep "Stripe Key"
168
+ cinna account credentials list --json | jq '.data[] | select(.id=="<cred-id>") | .service_uri'
169
+ ```
170
+ **Expected:** the table's `Slot` column reads `stripe.com` for that row (and `—`
171
+ for credentials without one), the full id is unbroken, and a placeholder shows
172
+ `placeholder`; `--json` prints only JSON and the jq query returns `"stripe.com"`.
173
+ **Watch for:** the slot missing from the table; `--json` output mixed with a
174
+ table or hint line; an id wrapped or elided at a narrow width.
164
175
 
165
176
  ### 9. Credential create `--agent` attaches in one step
166
177
 
@@ -216,6 +216,16 @@ Related (documented here as integration points): `cinna agent sync` →
216
216
  - `src/cinna/account.py:run_credentials_update()` — refuses an empty update;
217
217
  metadata fields only (`name`/`notes`/`service_uri`/`allow_sharing`).
218
218
  - `src/cinna/account.py:_credential_status_cell()` — complete / needs setup / —.
219
+ - `src/cinna/account.py:run_credentials_list()` — `--json` echoes the listing
220
+ untouched; otherwise the table adds a `Slot` column (`_credential_slot_cell()`,
221
+ the escaped `service_uri` or a dim dash), marks `is_placeholder`, never wraps the
222
+ id, and prints the `--service-uri` hint. Names and types go through `_esc()`.
223
+ (`tests/test_account.py:test_credentials_list_shows_each_slot`,
224
+ `test_credentials_list_json_prints_the_raw_listing`.)
225
+ - The account listing is also the authority for a linked credential's slot
226
+ elsewhere: `src/cinna/account.py:_fetch_linked_credentials()` overlays its
227
+ `service_uri` / `is_placeholder` / `status` by id onto the agent credential
228
+ route, which returns `service_uri: null` (see Agent Management).
219
229
 
220
230
  ## Config & registry
221
231
 
@@ -76,6 +76,29 @@ without `cinna api`, and without anyone typing a UUID.
76
76
  gone.
77
77
  5. When the skill half could not be read, the plugin rows still list and the
78
78
  reason is stated (`env_not_running`, `adapter_error`, `parse_error`).
79
+ 6. When any skill declares credential slots, a **Credentials** column lists each
80
+ slot: `✓` filled, `!` not usable yet with its reason, `?` unchecked. Beneath
81
+ the table every unusable slot gets its fix, and the note that a skill's
82
+ credential is checked only when its script asks for it — the agent keeps
83
+ working, that script fails.
84
+ - For a **catalog** install the platform already computed readiness
85
+ (`credential_issues`, one reason per slot: `not_linked`, `not_configured`,
86
+ `access_revoked`), and the CLI renders it as-is.
87
+ - For every **other** row an older platform computes nothing — a local skill
88
+ read `ok` while nothing carried its slot. The CLI checks the agent's linked
89
+ credentials itself: no credential with that service URI → `not_linked`; one of
90
+ another type → `type_mismatch`; only a placeholder or an unfilled one →
91
+ `not_configured`.
92
+ - A platform that judges local and bundle rows too sends `credential_issues`
93
+ for them, and its reason wins — except that it has no `type_mismatch`: a slot
94
+ it calls `not_linked` while a linked credential of another type carries it is
95
+ shown as `type_mismatch`, because drafting a second credential on a taken
96
+ slot would be the wrong fix.
97
+ - The remedy is specific: a linked credential of the declared type with no slot
98
+ is named with the `credentials update <id> --service-uri <slot>` command;
99
+ otherwise the `credentials create … --service-uri <slot> --agent <agent>` draft.
100
+ - A linked credential shared by someone else whose slot this account cannot see
101
+ makes the slot `?`, never `not_linked` — it may well be the carrier.
79
102
 
80
103
  ### Publish a skill to the catalog
81
104
 
@@ -598,6 +598,40 @@ elided, at any terminal width.
598
598
  found`; the resolution note landing on stdout and corrupting a JSON pipe; a
599
599
  non-agent sub-route under `agents/` being rejected instead of passed through.
600
600
 
601
+ ### 24. A local skill's credential slot is checked, not assumed
602
+
603
+ **Goal** — `cinna skills list` says whether a local skill's declared slot is
604
+ actually filled; the platform reports `credential_issues` for catalog installs
605
+ only, so a local skill used to read `● ok` with nothing carrying its slot.
606
+
607
+ **Setup** — `AGENT` has a linked `api_token` credential with **no** service URI,
608
+ and its workspace holds `skills/acceptance-slot/SKILL.md` declaring
609
+ `credentials:` with `- slot: acceptance-token.example` / `type: api_token`, pushed
610
+ with `cinna sync push --agent <slug>`.
611
+
612
+ **Steps**
613
+
614
+ ```bash
615
+ cinna skills list <AGENT>
616
+ cinna account credentials update <CRED_ID> --service-uri acceptance-token.example
617
+ cinna skills list <AGENT>
618
+ cinna agent show <AGENT> | sed -n '/Connected credentials/,$p'
619
+ cinna skills list <AGENT> --json | jq '.addons[] | select(.name=="acceptance-slot") | .credential_issues'
620
+ ```
621
+
622
+ **Expected** — the first list shows a `Credentials` column with
623
+ `! acceptance-token.example (not_linked)` and, beneath, the exact command
624
+ `cinna account credentials update <CRED_ID> --service-uri acceptance-token.example`
625
+ naming the linked token. After running it, the row reads `✓ acceptance-token.example`
626
+ with no remedy block, and `agent show` prints `slot: acceptance-token.example` for
627
+ that credential. `--json` is the unmodified payload (`credential_issues` stays `[]`
628
+ for a local skill — the CLI's check never leaks into it).
629
+
630
+ **Watch for** — `✓` before the slot is set; `not_linked` after it is set (the
631
+ agent credential route returns `service_uri: null`, so the slot must be read from
632
+ the account listing); a `Credentials` column on an agent whose skills declare no
633
+ slot; the readiness lookup running under `--json`.
634
+
601
635
  ## Cross-cutting invariants
602
636
 
603
637
  - No secret value is ever printed, and a skill folder that holds one cannot be
@@ -65,7 +65,26 @@
65
65
  first unpublished skill the caller may share.
66
66
  - `src/cinna/account.py:_print_addons()` — one table row per addon; prints the
67
67
  `counts` line and warns when `skills_error` is set, so a partial list is never
68
- mistaken for a complete one.
68
+ mistaken for a complete one. Adds the `Credentials` column (and
69
+ `_print_credential_readiness()` beneath) only when some row declares a slot, so
70
+ an agent without any keeps its shape.
71
+ - `src/cinna/account.py:run_skills_list()` fetches `_fetch_linked_credentials()`
72
+ only when `_needs_linked_credentials()` — a **non-catalog** row declares a slot —
73
+ and never under `--json` (the raw payload stays raw).
74
+ - `src/cinna/account.py:_declared_slots()` — the slots a row's `skills[].credentials`
75
+ declare (first declaration of a slot wins).
76
+ - `src/cinna/account.py:_slot_readiness()` — `(state, credential)` per slot: a
77
+ `credential_issues` entry for the slot wins (its `reason`), except a `not_linked`
78
+ whose slot every linked carrier holds with another type, which reads
79
+ `type_mismatch` (the platform has no such reason); a catalog row with no
80
+ entry is `ready` (the platform computed it); otherwise matched against the linked
81
+ credentials by `service_uri` → `not_linked` / `type_mismatch` / `not_configured` /
82
+ `ready`, and `unknown` when the listing is `None` or a `_SLOT_UNVERIFIED`
83
+ credential could be the carrier.
84
+ - `src/cinna/account.py:_addon_credentials_cell()` / `_slot_remedy()` /
85
+ `_print_credential_readiness()` — the column cell (amber, never red: an unfilled
86
+ skill slot never blocks the agent), the per-state command, and the block under
87
+ the table.
69
88
  - `src/cinna/account.py:_addon_status_cell()` — colours `ok` / `warning` /
70
89
  `error` and puts the server's `status_code` in the column: codes are the
71
90
  contract, and a code keeps the row one line.
@@ -193,10 +212,18 @@ uuid}`).
193
212
  All four routes are ordinary platform routes reached through the account escape
194
213
  hatch, `POST /api/v1/cli/account/api-proxy`:
195
214
 
215
+ - `GET /api/v1/agents/{agent_id}/credentials` and the account's
216
+ `GET /api/v1/cli/account/credentials` — read together by
217
+ `_fetch_linked_credentials()` for slot readiness: the first says which
218
+ credentials are linked, the second supplies each one's `service_uri`,
219
+ `is_placeholder` and `status` by id, because the first returns `service_uri:
220
+ null` for a credential that has a slot (observed on a live instance).
196
221
  - `GET /api/v1/agents/{agent_id}/addons` — the deduplicated projection
197
222
  (`AgentAddonsPublic`). Consumed fields: `addons[]` (`AddonPublic`: `key`,
198
223
  `kind`, `source`, `name`, `display_name`, `version`, `marketplace_name`,
199
- `status`, `status_code`, `orphan`, `can_share`, `published_package_id`, and
224
+ `status`, `status_code`, `orphan`, `can_share`, `published_package_id`,
225
+ `credential_issues` (`slot` + `reason`, computed for catalog rows only),
226
+ `skills[].credentials` (`slot`, `type`, `description`), and
200
227
  **`link`**), `counts` (`plugins`, `skills`, `local_skills`), and
201
228
  `skills_error`. `link` is an `AgentPluginLinkWithUpdateInfo`: `id`,
202
229
  `installed_version`, `latest_version`, `has_update`, `disabled`,