cinna-cli 0.2.2__tar.gz → 0.2.4__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 (86) hide show
  1. cinna_cli-0.2.4/.claude/commands/cinna-cli.feature.doc.md +174 -0
  2. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/PKG-INFO +37 -4
  3. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/README.md +36 -3
  4. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/docs/README.md +195 -7
  5. cinna_cli-0.2.4/docs/features/account_workspace/account_workspace.md +207 -0
  6. cinna_cli-0.2.4/docs/features/account_workspace/account_workspace_acceptance.md +287 -0
  7. cinna_cli-0.2.4/docs/features/account_workspace/account_workspace_tech.md +255 -0
  8. cinna_cli-0.2.4/docs/features/agent_api/agent_api.md +185 -0
  9. cinna_cli-0.2.4/docs/features/agent_api/agent_api_acceptance.md +224 -0
  10. cinna_cli-0.2.4/docs/features/agent_api/agent_api_tech.md +162 -0
  11. cinna_cli-0.2.4/docs/features/agent_management/agent_management.md +149 -0
  12. cinna_cli-0.2.4/docs/features/agent_management/agent_management_acceptance.md +232 -0
  13. cinna_cli-0.2.4/docs/features/agent_management/agent_management_tech.md +160 -0
  14. cinna_cli-0.2.4/docs/features/agent_schedules/agent_schedules.md +155 -0
  15. cinna_cli-0.2.4/docs/features/agent_schedules/agent_schedules_acceptance.md +218 -0
  16. cinna_cli-0.2.4/docs/features/agent_schedules/agent_schedules_tech.md +136 -0
  17. cinna_cli-0.2.4/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +192 -0
  18. cinna_cli-0.2.4/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +239 -0
  19. cinna_cli-0.2.4/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +188 -0
  20. cinna_cli-0.2.4/docs/features/doctor/doctor.md +162 -0
  21. cinna_cli-0.2.4/docs/features/doctor/doctor_acceptance.md +263 -0
  22. cinna_cli-0.2.4/docs/features/doctor/doctor_tech.md +154 -0
  23. cinna_cli-0.2.4/docs/features/git_versioning/git_versioning.md +170 -0
  24. cinna_cli-0.2.4/docs/features/git_versioning/git_versioning_acceptance.md +264 -0
  25. cinna_cli-0.2.4/docs/features/git_versioning/git_versioning_tech.md +137 -0
  26. cinna_cli-0.2.4/docs/features/live_sync/live_sync.md +153 -0
  27. cinna_cli-0.2.4/docs/features/live_sync/live_sync_acceptance.md +234 -0
  28. cinna_cli-0.2.4/docs/features/live_sync/live_sync_tech.md +199 -0
  29. cinna_cli-0.2.4/docs/features/mcp_integration/mcp_integration.md +166 -0
  30. cinna_cli-0.2.4/docs/features/mcp_integration/mcp_integration_acceptance.md +192 -0
  31. cinna_cli-0.2.4/docs/features/mcp_integration/mcp_integration_tech.md +145 -0
  32. cinna_cli-0.2.4/docs/features/remote_chat/remote_chat.md +152 -0
  33. cinna_cli-0.2.4/docs/features/remote_chat/remote_chat_acceptance.md +221 -0
  34. cinna_cli-0.2.4/docs/features/remote_chat/remote_chat_tech.md +159 -0
  35. cinna_cli-0.2.4/docs/features/remote_exec/remote_exec.md +124 -0
  36. cinna_cli-0.2.4/docs/features/remote_exec/remote_exec_acceptance.md +183 -0
  37. cinna_cli-0.2.4/docs/features/remote_exec/remote_exec_tech.md +106 -0
  38. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/pyproject.toml +1 -1
  39. cinna_cli-0.2.4/scripts/check_docs_references.py +242 -0
  40. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/account.py +171 -26
  41. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/bootstrap.py +161 -17
  42. cinna_cli-0.2.4/src/cinna/chat.py +476 -0
  43. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/client.py +187 -22
  44. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/config.py +122 -2
  45. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/context.py +67 -0
  46. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/doctor.py +195 -23
  47. cinna_cli-0.2.4/src/cinna/git_versioning.py +584 -0
  48. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/main.py +653 -68
  49. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +14 -1
  50. cinna_cli-0.2.4/src/cinna/templates/CHAT_TESTING.md +56 -0
  51. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/templates/CLAUDE.md.template +6 -1
  52. cinna_cli-0.2.4/src/cinna/templates/GIT_VERSIONING.md +110 -0
  53. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_account.py +78 -6
  54. cinna_cli-0.2.4/tests/test_chat.py +406 -0
  55. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_config.py +21 -0
  56. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_context.py +51 -0
  57. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_doctor.py +143 -8
  58. cinna_cli-0.2.4/tests/test_git_versioning.py +539 -0
  59. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_main.py +33 -0
  60. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/uv.lock +1 -1
  61. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/.github/workflows/publish.yml +0 -0
  62. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/.gitignore +0 -0
  63. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/LICENSE.md +0 -0
  64. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/docs/interface.md +0 -0
  65. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/docs/mutagen_capabilities.md +0 -0
  66. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/__init__.py +0 -0
  67. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/auth.py +0 -0
  68. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/console.py +0 -0
  69. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/errors.py +0 -0
  70. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/logging.py +0 -0
  71. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/mcp_proxy.py +0 -0
  72. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/mutagen_runtime.py +0 -0
  73. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/sync.py +0 -0
  74. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/sync_session.py +0 -0
  75. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/sync_ssh_shim.py +0 -0
  76. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/sync_tui.py +0 -0
  77. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/src/cinna/templates/__init__.py +0 -0
  78. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/__init__.py +0 -0
  79. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/conftest.py +0 -0
  80. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_auth.py +0 -0
  81. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_bootstrap.py +0 -0
  82. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_client.py +0 -0
  83. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_mutagen_runtime.py +0 -0
  84. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_sync.py +0 -0
  85. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_sync_session.py +0 -0
  86. {cinna_cli-0.2.2 → cinna_cli-0.2.4}/tests/test_sync_ssh_shim.py +0 -0
@@ -0,0 +1,174 @@
1
+ ---
2
+ description: Create or update cinna-cli feature documentation (business / tech / acceptance).
3
+ ---
4
+
5
+ ## User Input
6
+
7
+ ```text
8
+ $ARGUMENTS
9
+ ```
10
+
11
+ Feature name, description, or existing doc path to create/refactor.
12
+
13
+ ## Task
14
+
15
+ Create or refactor feature documentation under `docs/features/` following the
16
+ layered structure below. cinna-cli is a **Python CLI** (source in `src/cinna/`,
17
+ tests in `tests/`) that drives local agent development against a remote platform
18
+ API — there is no frontend/backend split to document. Keep that in mind: file
19
+ references point into `src/cinna/…` and `tests/…`, not `backend/`/`frontend/`.
20
+
21
+ **If given an existing doc path** — refactor it into the correct structure (split
22
+ into business / tech / acceptance files as needed, move under
23
+ `docs/features/{feature}/`).
24
+ **If given a feature name** — create new documentation by exploring the codebase
25
+ first (`src/cinna/`, the `cinna <group>` command surface in `src/cinna/main.py`,
26
+ relevant tests).
27
+
28
+ ## Documentation Architecture
29
+
30
+ ### Layer 1 — Project index (`docs/README.md`)
31
+
32
+ The single concise entry point: project purpose, glossary, architecture, command
33
+ surface, and a **Feature Registry** linking each documented feature to its folder.
34
+ When you create/update a feature doc, add/update its row in the registry.
35
+
36
+ ### Layer 2 — Feature folders (`docs/features/{feature}/`)
37
+
38
+ ```
39
+ docs/
40
+ ├── README.md # Layer 1 — project index + feature registry
41
+ └── features/
42
+ └── {feature}/ # one folder per feature (snake_case)
43
+ ├── {feature}.md # Layer 3a — business logic / reasoning (required)
44
+ ├── {feature}_tech.md # Layer 3b — implementation, file refs (optional)
45
+ └── {feature}_acceptance.md # Layer 3c — real-usage e2e scenarios (optional)
46
+ ```
47
+
48
+ Feature-folder naming: snake_case, descriptive (`git_versioning`, `live_sync`,
49
+ `remote_exec`, `account_workspace`, `remote_chat`).
50
+
51
+ ### Layer 3 — Feature documentation files
52
+
53
+ #### 3a. Business logic: `{feature}.md`
54
+
55
+ Explains **WHAT** the feature does and **WHY**, from a product/user perspective.
56
+ A reader should understand purpose, flows, and rules without reading code.
57
+
58
+ Required sections:
59
+ 1. **Purpose** — 1–2 sentences: what it does for the user.
60
+ 2. **Mental model / core concepts** — key terms and the model the user must hold
61
+ (for cinna-cli, almost always: how local files, the remote container, and any
62
+ external system relate; what is local vs remote vs on-demand).
63
+ 3. **User flows** — numbered steps for the main ways users interact (commands run,
64
+ what happens, what they see).
65
+ 4. **Business rules** — constraints, state/lifecycle rules, guardrails, failure
66
+ semantics (what is *fail-loud*, what is auto vs manual, direction guards…).
67
+ 5. **Architecture overview** — a simple text diagram of the component flow, e.g.
68
+ `cinna git <verb> → git_versioning.py → real git → remote`.
69
+ 6. **Integration points** — how it connects to other features (link their docs).
70
+
71
+ Style: concise bullets, no code blocks, focus on behavior and reasoning.
72
+
73
+ #### 3b. Technical details: `{feature}_tech.md`
74
+
75
+ Deep-dive for developers: **HOW** it's implemented, with file references.
76
+
77
+ Required sections:
78
+ 1. **File locations** — every `src/cinna/…` module + the tests that cover it.
79
+ 2. **Command surface** — `cinna <group> <verb>` → the function in
80
+ `src/cinna/main.py` that implements it, one line each.
81
+ 3. **Key functions & flow** — module path + function names with a brief purpose
82
+ (e.g. `src/cinna/git_versioning.py:link()` — the link sequence).
83
+ 4. **Config & registry** — fields written to `.cinna/config.json` and
84
+ `~/.cinna/agents.json` (the latter referenced as a path, it's runtime state).
85
+ 5. **External contracts** — platform API endpoints consumed, and any external
86
+ tool invoked (git, mutagen) with the exact invariants relied on.
87
+ 6. **Edge cases & guardrails** — the non-obvious behaviors a maintainer must
88
+ preserve, each tied to the code that enforces it.
89
+
90
+ Style: heavy use of `src/cinna/file.py:function()` references. <!-- nocheck --> **No
91
+ code blocks** — only file/function references.
92
+
93
+ #### 3c. Acceptance scenarios: `{feature}_acceptance.md` — **the e2e test catalog**
94
+
95
+ The catalog of **real-usage scenarios** a testing agent executes against a *live*
96
+ environment (a real backend + real container + real external systems) — **not**
97
+ unit tests. This is what catches the bugs unit tests miss: conflicting pushes,
98
+ multi-agent layout collisions, registry drift across commands, tarball/commit
99
+ divergence, stale state across command sequences.
100
+
101
+ Write it so an autonomous agent can pick it up and run each scenario end-to-end.
102
+
103
+ Required sections:
104
+ 1. **Preconditions** — what the agent needs: a live platform URL, an account
105
+ workspace or setup token, at least one (ideally two) agents configured for the
106
+ feature, any external accounts/credentials, and the editable install
107
+ (`which cinna` → repo `src/cinna`).
108
+ 2. **Scenario catalog** — a numbered list. Each scenario has:
109
+ - **Goal** — the real user intent being exercised.
110
+ - **Setup** — starting state.
111
+ - **Steps** — the exact `cinna …` (and supporting `git`/`cinna exec`) commands.
112
+ - **Expected** — observable outcome (output text, file/remote/registry/env
113
+ state). Be specific enough to assert.
114
+ - **Watch for** — the failure modes / regressions this scenario is designed to
115
+ surface (the "why this scenario exists").
116
+ 3. **Cross-cutting invariants** — properties that must hold across *all* scenarios
117
+ (e.g. credentials never committed; a command that re-writes the registry must
118
+ not drop another command's state; fail-loud, never silent-clobber).
119
+ 4. **Cleanup** — how to leave the live environment tidy afterward.
120
+
121
+ Style: imperative, runnable. Real commands in fenced blocks are encouraged here
122
+ (unlike the other layers). Prefer scenarios grounded in actual runs — when a real
123
+ test discovers a defect, **add the scenario that reproduces it** so it becomes a
124
+ permanent regression check.
125
+
126
+ ### Minimal documentation
127
+
128
+ Not every feature needs all three files. Start with `{feature}.md`. Add `_tech.md`
129
+ when implementation detail would clutter the business doc or spans many modules.
130
+ Add `_acceptance.md` when the feature has **real-environment behavior worth
131
+ exercising e2e** (anything touching sync, git, the container, schedules, or
132
+ multi-agent/multi-command state — i.e. most non-trivial cinna-cli features).
133
+
134
+ ## Style rules
135
+
136
+ **DO**
137
+ - Use file refs: `src/cinna/git_versioning.py:link()`, `tests/test_git_versioning.py`
138
+ - Use command refs: `cinna git push` — push the agent branch (ff-only)
139
+ - Use endpoint refs: `GET /api/v1/cli/git-coordinates`
140
+ - Link related docs: `See [Live Sync](../live_sync/live_sync.md)` <!-- nocheck -->
141
+ - Concise bullets; simple text architecture diagrams
142
+ - In `_acceptance.md`, write real runnable commands
143
+
144
+ **DON'T**
145
+ - Put code snippets in `{feature}.md` / `{feature}_tech.md`
146
+ - Duplicate content between the business and tech files
147
+ - Reference container/home paths (`/app/workspace/…`, `~/.cinna/…`) as if repo
148
+ files — they are illustrative; the checker skips them, but be intentional
149
+
150
+ ## Process
151
+
152
+ 1. **Scope** — new feature doc or refactor of an existing one?
153
+ 2. **Folder** — map to `docs/features/{feature}/`.
154
+ 3. **Explore** — read the relevant `src/cinna/` modules, the `cinna` command
155
+ surface, and the covering tests.
156
+ 4. **Write** — always `{feature}.md`; add `_tech.md` / `_acceptance.md` per the
157
+ rules above.
158
+ 5. **Update `docs/README.md`** — add/refresh the Feature Registry entry.
159
+ 6. **Validate references** — run the checker on the files you touched:
160
+ ```
161
+ python3 scripts/check_docs_references.py --files docs/features/{feature}/{feature}.md docs/features/{feature}/{feature}_tech.md docs/features/{feature}/{feature}_acceptance.md
162
+ ```
163
+ Fix every broken reference before finishing. For *illustrative* paths that are
164
+ not real repo files (container/home/convention paths), append `<!-- nocheck -->`
165
+ to that line.
166
+ 7. **Run the test suite** — `pytest -q` must stay green (the docs describe shipped
167
+ behavior; if a doc claims behavior the tests don't cover, add or point to the
168
+ test).
169
+
170
+ ## Output
171
+
172
+ Write to `docs/features/{feature}/`. Report what was created/updated, any old
173
+ files replaced (don't delete automatically — report them), the reference-check
174
+ result, and the test-suite status.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cinna-cli
3
- Version: 0.2.2
3
+ Version: 0.2.4
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
@@ -255,6 +255,30 @@ cinna api PATCH agents/3fa85f64-5717-4562-b3fc-2c963f66afa6 --json '{"descriptio
255
255
  cinna api POST tasks --data @task.json
256
256
  ```
257
257
 
258
+ ### `cinna chat [--agent <ref>] [--resume <session_id>] [--file PATH ...] [MESSAGE...]`
259
+
260
+ Talk to an agent through a **real platform session** — the same conversation pipeline production uses (permission checks, agent-env calls, the model/SDK the platform selects), not a local mock. Built for a local coding agent to test the agent it is building: it can prepare a prompt, attach files, and read the reply back as structured data.
261
+
262
+ Run it from the account workspace (or any synced agent folder under it). The reply is observed by **polling** the backend rather than reading a live stream, so it is robust to streaming/transport quirks.
263
+
264
+ - `--agent <name|slug|id>` picks the agent; omit it inside a synced agent workspace to infer it. `--resume <session_id>` continues an existing conversation instead of opening a new one (default mode for a new session is `conversation`; `--mode building` opens a building session).
265
+ - The message is the positional argument; if omitted it is read from stdin, or you are prompted for it interactively in a TTY.
266
+ - `--file PATH` (repeatable) uploads a local file and attaches it to the message.
267
+ - Output is **NDJSON** by default — one JSON event per line (`session`, `upload`, `message`, `status`, `done`), trivially parseable by another agent. `--pretty` switches to a human-readable transcript.
268
+ - 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.
269
+ - 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.
270
+ - `--interval` / `--timeout` tune the poll cadence and the maximum wait for a turn. Ctrl-C interrupts the agent's turn and exits.
271
+
272
+ ```bash
273
+ cinna chat --agent crm-agent "Summarize today's leads"
274
+ cinna chat --agent crm-agent --file report.csv "Validate this export"
275
+ cinna chat --resume 3fa85f64-5717-4562-b3fc-2c963f66afa6 "Now break it down by region"
276
+ echo "ping" | cinna chat --agent crm-agent # message from stdin
277
+ cinna chat --agent crm-agent "hi" | jq -c 'select(.event=="message")'
278
+ ```
279
+
280
+ The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`.
281
+
258
282
  ### `cinna dev`
259
283
 
260
284
  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`.
@@ -320,16 +344,25 @@ It detects and fixes:
320
344
  - **Halted sessions** — sessions stopped on `halted-on-root-deletion` (the local `workspace/` root was deleted) while the agent dir is otherwise intact. Terminated; `cinna dev` recreates a clean one.
321
345
  - **Dead-remote sessions** — sessions stuck retrying a remote env that no longer exists (`connecting-beta` / beta polling error). Mutagen has **no** "give up after N failures" option — a session retries forever until paused or terminated — so `doctor` is the cleanup path for these. Terminated.
322
346
  - **Orphaned sessions** — `cinna-*` sessions with no registry entry at all. Terminated.
347
+ - **Active sessions** — the healthy, still-watching sessions left over from past `cinna dev` runs. They are not broken, but they keep the shared Mutagen daemon busy and are recreated on demand, so doctor offers to clear them as a separate step.
323
348
  - **Expired tokens** — for **account-managed** workspaces (those under an account root), the CLI token is re-minted automatically through the parent account token, no pasting required. **Standalone** workspaces (set up via `cinna setup`) can only be refreshed with a pasted setup token, so they are reported with a `cinna set-token` hint rather than changed.
324
349
  - **Expired account token** — a sub-agent token can only be re-minted while the **account** token that mints it is still valid. When the account token has itself expired, doctor probes it once and surfaces a single _"renew the account token — run `cinna login`"_ finding (listing the blocked sub-agents) instead of a pile of re-mints that would all fail with 401. Run `cinna login`, then re-run `cinna doctor` to re-mint the dependents.
325
350
 
326
351
  ```bash
327
- cinna doctor # diagnose, then apply all fixes behind one confirmation
352
+ cinna doctor # diagnose, then walk the repair steps (each defaults to Yes)
328
353
  cinna doctor --dry-run # report problems only; change nothing
329
- cinna doctor --yes # apply every fix non-interactively
354
+ cinna doctor --yes # accept every step non-interactively
330
355
  ```
331
356
 
332
- The diagnosis is split into two tables: **Will fix** (everything doctor can repair — deleted-workspace cleanup, halted/dead/orphaned session termination, account token re-mints) and **No automatic fix — manual action needed** (standalone expired tokens, which need a pasted setup token and are never touched). Everything actionable is applied together behind a single `Apply N fix(es)?` confirmation, so the count always matches the "Will fix" table.
357
+ `doctor` first prints the live `cinna-*` session inventory — each session tagged with the **agent** and **folder** it serves — so you can see what's running before deciding anything. Findings it can't fix itself (standalone expired tokens) are listed under **No automatic fix — manual action needed** and never touched.
358
+
359
+ The repair then runs as three ordered, independently-confirmed steps, each defaulting to **Yes**:
360
+
361
+ 1. **Delete stalled sessions** — deleted-workspace cleanup plus halted / dead / orphaned session termination.
362
+ 2. **Terminate active sessions** — clear the healthy leftovers from the inventory above (recreated on the next `cinna dev`).
363
+ 3. **Refresh tokens** — re-mint expired account-managed tokens.
364
+
365
+ `--yes` accepts all three; `--dry-run` shows the tables and changes nothing.
333
366
 
334
367
  ### `cinna disconnect`
335
368
 
@@ -218,6 +218,30 @@ cinna api PATCH agents/3fa85f64-5717-4562-b3fc-2c963f66afa6 --json '{"descriptio
218
218
  cinna api POST tasks --data @task.json
219
219
  ```
220
220
 
221
+ ### `cinna chat [--agent <ref>] [--resume <session_id>] [--file PATH ...] [MESSAGE...]`
222
+
223
+ Talk to an agent through a **real platform session** — the same conversation pipeline production uses (permission checks, agent-env calls, the model/SDK the platform selects), not a local mock. Built for a local coding agent to test the agent it is building: it can prepare a prompt, attach files, and read the reply back as structured data.
224
+
225
+ Run it from the account workspace (or any synced agent folder under it). The reply is observed by **polling** the backend rather than reading a live stream, so it is robust to streaming/transport quirks.
226
+
227
+ - `--agent <name|slug|id>` picks the agent; omit it inside a synced agent workspace to infer it. `--resume <session_id>` continues an existing conversation instead of opening a new one (default mode for a new session is `conversation`; `--mode building` opens a building session).
228
+ - The message is the positional argument; if omitted it is read from stdin, or you are prompted for it interactively in a TTY.
229
+ - `--file PATH` (repeatable) uploads a local file and attaches it to the message.
230
+ - Output is **NDJSON** by default — one JSON event per line (`session`, `upload`, `message`, `status`, `done`), trivially parseable by another agent. `--pretty` switches to a human-readable transcript.
231
+ - 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.
232
+ - 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.
233
+ - `--interval` / `--timeout` tune the poll cadence and the maximum wait for a turn. Ctrl-C interrupts the agent's turn and exits.
234
+
235
+ ```bash
236
+ cinna chat --agent crm-agent "Summarize today's leads"
237
+ cinna chat --agent crm-agent --file report.csv "Validate this export"
238
+ cinna chat --resume 3fa85f64-5717-4562-b3fc-2c963f66afa6 "Now break it down by region"
239
+ echo "ping" | cinna chat --agent crm-agent # message from stdin
240
+ cinna chat --agent crm-agent "hi" | jq -c 'select(.event=="message")'
241
+ ```
242
+
243
+ The session id is printed in the first `session` event — capture it to drive a multi-turn conversation with `--resume`.
244
+
221
245
  ### `cinna dev`
222
246
 
223
247
  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`.
@@ -283,16 +307,25 @@ It detects and fixes:
283
307
  - **Halted sessions** — sessions stopped on `halted-on-root-deletion` (the local `workspace/` root was deleted) while the agent dir is otherwise intact. Terminated; `cinna dev` recreates a clean one.
284
308
  - **Dead-remote sessions** — sessions stuck retrying a remote env that no longer exists (`connecting-beta` / beta polling error). Mutagen has **no** "give up after N failures" option — a session retries forever until paused or terminated — so `doctor` is the cleanup path for these. Terminated.
285
309
  - **Orphaned sessions** — `cinna-*` sessions with no registry entry at all. Terminated.
310
+ - **Active sessions** — the healthy, still-watching sessions left over from past `cinna dev` runs. They are not broken, but they keep the shared Mutagen daemon busy and are recreated on demand, so doctor offers to clear them as a separate step.
286
311
  - **Expired tokens** — for **account-managed** workspaces (those under an account root), the CLI token is re-minted automatically through the parent account token, no pasting required. **Standalone** workspaces (set up via `cinna setup`) can only be refreshed with a pasted setup token, so they are reported with a `cinna set-token` hint rather than changed.
287
312
  - **Expired account token** — a sub-agent token can only be re-minted while the **account** token that mints it is still valid. When the account token has itself expired, doctor probes it once and surfaces a single _"renew the account token — run `cinna login`"_ finding (listing the blocked sub-agents) instead of a pile of re-mints that would all fail with 401. Run `cinna login`, then re-run `cinna doctor` to re-mint the dependents.
288
313
 
289
314
  ```bash
290
- cinna doctor # diagnose, then apply all fixes behind one confirmation
315
+ cinna doctor # diagnose, then walk the repair steps (each defaults to Yes)
291
316
  cinna doctor --dry-run # report problems only; change nothing
292
- cinna doctor --yes # apply every fix non-interactively
317
+ cinna doctor --yes # accept every step non-interactively
293
318
  ```
294
319
 
295
- The diagnosis is split into two tables: **Will fix** (everything doctor can repair — deleted-workspace cleanup, halted/dead/orphaned session termination, account token re-mints) and **No automatic fix — manual action needed** (standalone expired tokens, which need a pasted setup token and are never touched). Everything actionable is applied together behind a single `Apply N fix(es)?` confirmation, so the count always matches the "Will fix" table.
320
+ `doctor` first prints the live `cinna-*` session inventory — each session tagged with the **agent** and **folder** it serves — so you can see what's running before deciding anything. Findings it can't fix itself (standalone expired tokens) are listed under **No automatic fix — manual action needed** and never touched.
321
+
322
+ The repair then runs as three ordered, independently-confirmed steps, each defaulting to **Yes**:
323
+
324
+ 1. **Delete stalled sessions** — deleted-workspace cleanup plus halted / dead / orphaned session termination.
325
+ 2. **Terminate active sessions** — clear the healthy leftovers from the inventory above (recreated on the next `cinna dev`).
326
+ 3. **Refresh tokens** — re-mint expired account-managed tokens.
327
+
328
+ `--yes` accepts all three; `--dry-run` shows the tables and changes nothing.
296
329
 
297
330
  ### `cinna disconnect`
298
331
 
@@ -198,7 +198,8 @@ main.py (CLI commands — Click)
198
198
  │
199
199
  ├── bootstrap.py — setup orchestration
200
200
  ├── account.py — account workspace; `cinna login` (device auth), `cinna account`, `cinna agent`
201
- ├── doctor.py — `cinna doctor`: reconcile registry ↔ Mutagen, repair stale state, refresh tokens
201
+ ├── doctor.py — `cinna doctor`: reconcile registry ↔ Mutagen, delete stalled / terminate active sessions, refresh tokens
202
+ ├── chat.py — `cinna chat`: session-backed conversation testing (poll + NDJSON) over the api-proxy
202
203
  ├── config.py — .cinna/config.json: load/save/find
203
204
  ├── auth.py — JWT storage, Authorization headers
204
205
  ├── client.py — PlatformClient: HTTP + SSE stream_exec
@@ -216,12 +217,21 @@ main.py (CLI commands — Click)
216
217
 
217
218
  ### Local Directory Layout
218
219
 
219
- After `cinna setup` (agent name normalized, e.g. "HR Manager Agent" → `hr-manager-agent/`):
220
+ After `cinna setup` (agent name normalized, e.g. "HR Manager Agent" → `hr-manager-agent`),
221
+ every new checkout uses the **Model-A nested layout** (`config.compute_agent_layout`):
222
+ a clone-root dir holds the agent at `<subdir>/`, so the folder is already shaped like
223
+ the agent's git repo whether or not Git Versioning is enabled (see "Git Versioning"
224
+ below). `<subdir>` defaults to the agent slug. If the clone-root dir `<slug>/` is
225
+ already taken by a **different** agent (two names normalizing to the same slug), the
226
+ clone root falls back to `<slug>-<shorthash>/` (the agent id's short hash) so the two
227
+ don't collide; re-running setup for the *same* agent still reports "already set up".
220
228
 
221
229
  ```
222
- hr-manager-agent/ (workspace root)
230
+ hr-manager-agent/ (clone root — becomes the git working tree once linked)
231
+ └── hr-manager-agent/ (workspace root == the repo's <subdir>/ node)
223
232
  .cinna/
224
- config.json (agent config, CLI token, mutagen_version pin)
233
+ config.json (agent config, CLI token, mutagen_version pin, git{} layout)
234
+ cinna.agent.json (backend-owned manifest; present once git-versioned)
225
235
  workspace/ (continuously synced with remote /app/workspace)
226
236
  scripts/ (bundle-owned — shipped in published revisions)
227
237
  docs/ (bundle-owned)
@@ -249,13 +259,146 @@ Per-user global state (one copy, shared across every agent workspace):
249
259
 
250
260
  ```
251
261
  ~/.cinna/
252
- agents.json (agent_id → {platform_url, cli_token, workspace_path}; 0600)
262
+ agents.json (agent_id → {platform_url, cli_token, workspace_path,
263
+ git?:{clone_path, subdir, repo_url, ref, …}}; 0600)
253
264
  mutagen-ssh/
254
265
  ssh (bash wrapper — execs cinna-sync-ssh; 0755)
255
266
  ```
256
267
 
257
268
  ---
258
269
 
270
+ ## Feature Registry
271
+
272
+ Each feature is documented under `docs/features/{feature}/` as a layered set:
273
+ `{feature}.md` (business logic / reasoning), `{feature}_tech.md` (implementation +
274
+ file refs), and `{feature}_acceptance.md` (live e2e scenarios). See
275
+ [cinna-cli.feature.doc](../.claude/commands/cinna-cli.feature.doc.md) for the
276
+ authoring convention.
277
+
278
+ | Feature | Command surface | Docs |
279
+ |---|---|---|
280
+ | **Bootstrap & onboarding** | `cinna setup` / `set-token` / `login` / `list` / `status` / `disconnect[-all]` / `completion` / `dev` / `redev` | [business](features/bootstrap_onboarding/bootstrap_onboarding.md) · [tech](features/bootstrap_onboarding/bootstrap_onboarding_tech.md) · [acceptance](features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md) |
281
+ | **Account workspace** | `cinna account` (setup, agents, status, refresh-context, user-workspace, credentials) | [business](features/account_workspace/account_workspace.md) · [tech](features/account_workspace/account_workspace_tech.md) · [acceptance](features/account_workspace/account_workspace_acceptance.md) |
282
+ | **Agent management** | `cinna agent` (sync, unsync, create, restart-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) |
283
+ | **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) |
284
+ | **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) |
285
+ | **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) |
286
+ | **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) |
287
+ | **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) |
288
+ | **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) |
289
+ | **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) |
290
+
291
+ The sections below (Git Versioning, Sync Transport, Remote Exec, Remote Chat,
292
+ Bootstrap Flow) remain as in-README quick references and backend contracts; the
293
+ feature folders above are the authoritative deep dives.
294
+
295
+ ---
296
+
297
+ ## Git Versioning
298
+
299
+ > Full feature docs: [git_versioning](features/git_versioning/git_versioning.md)
300
+ > (business logic), [_tech](features/git_versioning/git_versioning_tech.md)
301
+ > (implementation), [_acceptance](features/git_versioning/git_versioning_acceptance.md)
302
+ > (live e2e scenarios). This section is the quick reference + backend contract.
303
+
304
+ A git-versioned agent has **two independent sync layers** on the same folder:
305
+ **Mutagen** keeps `workspace/` mirrored to the running container in near-real-time
306
+ (it ignores `.git`), and **git** durably versions the same files against the agent's
307
+ external remote. They meet only at the remote. All git ops are local and run with the
308
+ developer's **own** git/SSH credentials — the platform's deploy key never reaches the
309
+ CLI. (The agent-facing version of this guidance is shipped into each checkout as the
310
+ on-demand `GIT_VERSIONING.md`, referenced conditionally from `CLAUDE.md`.)
311
+
312
+ Because new checkouts already use the Model-A nested layout, enabling Git Versioning
313
+ later needs no re-download or file move — just a link:
314
+
315
+ ```
316
+ cinna git status # is this agent git-versioned? linked? working-tree status
317
+ cinna git link # init the clone, sparse-checkout <subdir>, fetch + reset --mixed
318
+ cinna git commit -m "…" [--push] # stage the subdir + commit (honors .gitignore)
319
+ cinna git push # fast-forward only; rejected pushes tell you to pull --rebase
320
+ cinna git pull # rebase the remote in; Mutagen mirrors it into the running env
321
+ cinna git log # recent commits touching this agent's subdir
322
+ cinna git checkout <ref> [--reload] # restore a past version's workspace/ files into
323
+ # the tree (uncommitted) + flush to the running env via Mutagen
324
+ # — debug/rollback without committing
325
+ cinna git unlink # stop offering git helpers (keeps .git + history)
326
+ ```
327
+
328
+ `cinna setup` / `cinna agent sync` auto-run `git link` when the agent is already
329
+ git-versioned, so the developer gets a working tree from the first checkout.
330
+ `--agent <ref>` targets a synced child from the account root (like `cinna sync`).
331
+
332
+ Key behaviors: `link` uses `git reset --mixed` (never `--hard`) so the backend's
333
+ in-flight changes survive as ordinary uncommitted edits; pushes are fast-forward-only
334
+ and never auto-forced; a `sync_direction=pull` agent refuses local pushes; and a legacy
335
+ *flat* workspace that becomes git-versioned is **not** auto-converted (link prints a
336
+ disconnect + re-sync instruction).
337
+
338
+ ### Backend contract (cinna-core)
339
+
340
+ The CLI consumes one discovery endpoint; the agent is derived from the per-agent
341
+ token, so the path has **no `{agent_id}`**:
342
+
343
+ ```
344
+ GET /api/v1/cli/git-coordinates (Auth: per-agent CLI JWT)
345
+ ```
346
+
347
+ Response (`CliGitCoordinates` — `client.get_git_coordinates`, modelled by
348
+ `git_versioning.GitCoordinates`). `vcs_enabled=false` ⇒ all other fields null; a 404
349
+ (older backend) is treated as `vcs_enabled=false`:
350
+
351
+ ```jsonc
352
+ {
353
+ "vcs_enabled": true, // false ⇒ agent has no git source
354
+ "repo_url": "git@github.com:acme/agents.git",
355
+ "subdir": "hr-bot", // null ⇒ agent lives at the repo root
356
+ "ref": "main",
357
+ "sync_direction": "bidirectional", // "pull" | "push" | "bidirectional"
358
+ "last_synced_commit": "a1b2c3…", // SHA the backend last imported/pushed; may be null
359
+ "auth_hint": "ssh" // "ssh" | "https" — which local cred the DEV needs
360
+ }
361
+ ```
362
+
363
+ The remote repo stores each agent as the `schema_version`-2 bundle snapshot — this is
364
+ the layout `link` reconciles against (`reset --mixed` brings the manifest + `.gitignore`
365
+ from the ref; `workspace/**` stays the live copy):
366
+
367
+ ```
368
+ <repo-root>/<subdir>/
369
+ ├── cinna.agent.json # backend-owned manifest (prompts, SDK config, schedules,
370
+ │ # plugin specs, required_credential_specs, content_hash…)
371
+ ├── workspace/ # the editable agent files (scripts/, docs/, …)
372
+ └── .gitignore # auto-generated; excludes credentials/, app-data/, logs/,
373
+ # databases/, uploads/, plugins-derived, __pycache__, *.pyc…
374
+ ```
375
+
376
+ Contract rules the CLI honors:
377
+
378
+ - **Two-writer, fast-forward-only.** Backend (deploy key) and developer (own creds)
379
+ push the same ref; both ff-only, no auto-merge. A rejected dev push ⇒ surface
380
+ `git pull --rebase`, never force.
381
+ - **Backend-owned manifest.** `cinna.agent.json` is regenerated by the backend from
382
+ the DB on every backend push/connect — the CLI commits it as-is and never invents
383
+ values (it lacks the DB/env inputs). Editing prompt **files** under
384
+ `workspace/docs/` flows back into the DB via the platform's prompt-sync.
385
+ - **Never committable** (the committed `.gitignore` + a local `.git/info/exclude`
386
+ enforce it; the CLI never `git add -f`): `credentials/`, `app-data/`, logs,
387
+ databases, `uploads/`, plugins-derived files, `__pycache__/`, `*.pyc`, plus the
388
+ CLI's own `.cinna/` (holds the token) and generated guides.
389
+ - **Deploy key is host-side only** and never leaves the backend; `git-coordinates`
390
+ deliberately omits all key material — the dev authenticates with their own
391
+ git/SSH (`auth_hint` only advises which).
392
+ - **Backend adoption of dev pushes.** After a dev push the backend is behind; it
393
+ adopts the change when the user clicks **Pull** on the agent's Git Versioning card
394
+ or via the configured GitOps webhook — the CLI cannot trigger it.
395
+
396
+ The backend half lives in cinna-core — see its `docs/agents/agent_git_versioning/` <!-- nocheck: cross-repo (cinna-core) path -->
397
+ plus `backend/app/api/routes/cli.py` (`CliGitCoordinates` / `_git_auth_hint`),
398
+ `GitSourceService`, and `SSHKeyService`; that repo owns the authoritative spec.
399
+
400
+ ---
401
+
259
402
  ## Sync Transport
260
403
 
261
404
  ### Wire path
@@ -356,6 +499,31 @@ To run an actual remote shell snippet (pipes, redirects, `&&`), pass it explicit
356
499
 
357
500
  ---
358
501
 
502
+ ## Remote Chat (`cinna chat`)
503
+
504
+ `cinna chat` lets a local coding agent **test the agent it is building** by driving a real platform conversation session — exercising the production path (permission checks, agent-env calls, the model/SDK the platform selects) rather than a local mock. It lives in `chat.py` and runs entirely through the **account workspace's api-proxy** (`AccountClient`), so it needs an account workspace (`.cinna/account.json`) — found by walking up from the cwd, exactly like the other account verbs, so it works from a synced `agents/<slug>/` folder too.
505
+
506
+ ### Why polling, not streaming
507
+
508
+ The platform's send-message route (`POST /sessions/{id}/messages/stream`) returns a **JSON ack immediately** and runs the agent turn asynchronously; the live events go out over a Socket.IO room *and* are persisted onto each message's `message_metadata.streaming_events`. The api-proxy is a buffered JSON hatch (it rejects `text/event-stream`), so `cinna chat` never reads the stream. Instead it:
509
+
510
+ 1. Creates the session (`POST /sessions/`, mode `conversation` by default) — or resumes the one passed to `--resume`.
511
+ 2. Uploads each `--file` and collects the returned file ids.
512
+ 3. Records the current message count as a cursor, then sends the message (`file_ids` carry the attachments).
513
+ 4. **Polls** `GET /sessions/{id}/messages?offset=<cursor>` (messages are ordered ascending by `sequence_number`, so `offset` is the cursor) and `GET …/messages/streaming-status` (`{is_streaming}`) until the turn settles — `is_streaming` false with no message flagged `streaming_in_progress`. A start-grace window covers env wake / queueing before the turn begins; an overall `--timeout` bounds the wait.
514
+
515
+ Each finalized message is emitted as one NDJSON line (`session` / `upload` / `message` / `status` / `done`); the in-progress assistant message is held back (its content is still growing) and emitted once final. Every `message` also carries the agent's reasoning/tool trace under **`events`** — the normalized `streaming_events` (thinking blocks, `tool` calls with their full `tool_input` payloads, tool results), with the bookkeeping/`attachment` entries stripped (attachments are surfaced separately). The final coalesced text stays in `content`; the trace shows *how* the agent got there. `--no-events` drops the trace; `--pretty` swaps NDJSON for a Rich transcript. Ctrl-C calls `POST …/messages/interrupt` and exits 130.
516
+
517
+ ### Attachments
518
+
519
+ Agents attach workspace files to replies via `<cinna_attach>` tags; the backend materializes them and both injects an `attachment` streaming event (`metadata.file_id` / `filename` / `mime_type` / `size`) and lists them under the message's `files[]` with `source == "agent_attachment"`. `chat.py` collects attachments from the streaming events (preferred) with the `files[]` list as a replay fallback, dedups by file id, and downloads each via the proxy (`GET /files/{id}/download`) into `./cinna-chat-files/<session_id>/`. Because the proxy buffers the response, downloads are bounded by its **8 MiB** response cap; larger files surface a clear `PlatformError` instead of a partial write.
520
+
521
+ ### File upload — the one dedicated route
522
+
523
+ The api-proxy is JSON-only and cannot carry a multipart body, and neither the account token nor a per-agent token may call `/files/upload` directly. So uploading a local attachment uses a dedicated account-CLI route, **`POST /api/v1/cli/account/files/upload`** (multipart, account-token auth), added alongside the other `/cli/account/*` routes; it creates a `File` owned by the account user and returns `FileUploadPublic` whose `id` goes into the message's `file_ids`. This is the only part of `cinna chat` that does not ride the api-proxy.
524
+
525
+ ---
526
+
359
527
  ## Bootstrap Flow
360
528
 
361
529
  ```
@@ -404,7 +572,7 @@ When a CLI token expires (or is revoked) the normal remedy is `cinna set-token <
404
572
 
405
573
  **Account tokens** refresh without a paste. `cinna login` (run inside an account workspace) drives the platform's RFC 8628 device-authorization flow: `POST /account/login/start` returns a short code + verification URL, the user clicks **Authorize** in the browser (already signed in), and the CLI polls `POST /account/login/poll` until it receives the fresh token, which it writes back into `.cinna/account.json` in place. The poll endpoint always returns HTTP 200 with a `status` field (`authorization_pending` / `slow_down` / `authorized` / `access_denied` / `expired_token`) — a deliberate divergence from RFC 8628's 400+`error` shape. Run from a fresh folder, the same command bootstraps a new account workspace instead of resuming one.
406
574
 
407
- **Bulk repair** is `cinna doctor`. It reconciles the `~/.cinna/agents.json` registry against the Mutagen daemon and heals the state that drifts as agents come and go — registry entries whose workspace was deleted, sessions halted on a deleted local root or stuck retrying a dead remote env, and orphaned sessions (Mutagen has no "stop after N failures" knob, so these retry forever until terminated). Expired **per-agent** tokens under an account workspace are re-minted automatically through the parent account token; when the **account** token has itself expired, doctor groups the blocked agents into a single "run `cinna login`" finding instead of attempting re-mints that would 401. Standalone agents are reported for a manual `cinna set-token`.
575
+ **Bulk repair** is `cinna doctor`. It reconciles the `~/.cinna/agents.json` registry against the Mutagen daemon and heals the state that drifts as agents come and go — registry entries whose workspace was deleted, sessions halted on a deleted local root or stuck retrying a dead remote env, and orphaned sessions (Mutagen has no "stop after N failures" knob, so these retry forever until terminated). It prints the live `cinna-*` session inventory up front — each tagged with the agent and folder it serves — then walks three ordered, separately-confirmed steps (each defaulting to Yes): **delete stalled sessions**, **terminate active sessions** (the healthy leftovers, recreated on the next `cinna dev`), and **refresh tokens**. Expired **per-agent** tokens under an account workspace are re-minted automatically through the parent account token; when the **account** token has itself expired, doctor groups the blocked agents into a single "run `cinna login`" finding instead of attempting re-mints that would 401. Standalone agents are reported for a manual `cinna set-token`.
408
576
 
409
577
  ### Authorization
410
578
 
@@ -434,13 +602,18 @@ When a CLI token expires (or is revoked) the normal remedy is `cinna set-token <
434
602
  | GET | `/api/v1/cli/agents/{id}/building-context` | CLI JWT | Assembled building prompt |
435
603
  | POST | `/api/v1/cli/agents/{id}/knowledge/search` | CLI JWT | Knowledge base search (via MCP proxy) |
436
604
  | GET | `/api/v1/cli/agents/{id}/sync-runtime` | CLI JWT | Required Mutagen version + hash (also used by `cinna list` / `cinna status` as a cheap token-validity probe) |
605
+ | GET | `/api/v1/cli/git-coordinates` | CLI JWT | Agent's git-versioning coordinates — **no `{id}`**, derived from the token (see "Git Versioning"). 404 on older backends ⇒ treated as not-versioned |
437
606
  | POST | `/api/v1/cli/agents/{id}/exec` | CLI JWT | Streaming SSE command execution |
438
607
  | WSS | `/api/v1/cli/agents/{id}/sync-stream` | CLI JWT | Mutagen transport tunnel |
439
608
  | POST | `/api/v1/cli/account/login/start` | None | Begin a `cinna login` device-authorization request |
440
609
  | POST | `/api/v1/cli/account/login/poll` | None | Poll a `cinna login` request — always HTTP 200 + `status` |
441
610
  | POST | `/api/v1/cli/account/agents/{id}/mint` | Account token | Mint a per-agent CLI token (`cinna agent sync`, `cinna doctor` re-mint) |
611
+ | POST | `/api/v1/cli/account/api-proxy` | Account token | Buffered JSON escape hatch — `cinna api`, and the transport for every `cinna chat` session/message call |
612
+ | POST | `/api/v1/cli/account/files/upload` | Account token | Multipart upload for `cinna chat --file` (the proxy can't carry multipart) |
613
+
614
+ `cinna chat` reaches the conversation API **through** the api-proxy (so these are inner routes, not CLI routes): `POST /sessions/`, `GET /sessions/{id}`, `GET /sessions/{id}/messages`, `POST /sessions/{id}/messages/stream`, `GET /sessions/{id}/messages/streaming-status`, `POST /sessions/{id}/messages/interrupt`, and `GET /files/{id}/download`.
442
615
 
443
- The account-workspace surface adds the broader `/api/v1/cli/account/*` route group (login, agents, credentials, connect, schedules, status, api-proxy); only the routes the sync / login / doctor paths use are listed here.
616
+ The account-workspace surface adds the broader `/api/v1/cli/account/*` route group (login, agents, credentials, connect, schedules, status, api-proxy, files/upload); only the routes the sync / login / doctor / chat paths use are listed here.
444
617
 
445
618
  Endpoints that were part of the old Docker-replica model (`build-context`, `workspace` POST, `workspace/manifest`, `credentials`) have been removed from the backend and from this CLI.
446
619
 
@@ -528,6 +701,21 @@ git push origin main && git push origin v0.1.5
528
701
 
529
702
  ---
530
703
 
704
+ ## Feature Documentation
705
+
706
+ Per-feature docs live under `docs/features/{feature}/` in up to three layers:
707
+ `{feature}.md` (business logic / reasoning), `{feature}_tech.md` (implementation +
708
+ file refs), `{feature}_acceptance.md` (live e2e scenarios a testing agent runs
709
+ against a real environment). Author new ones with the `/cinna-cli.feature.doc`
710
+ command (`.claude/commands/cinna-cli.feature.doc.md`) and validate references with
711
+ `scripts/check_docs_references.py`.
712
+
713
+ | Feature | Docs | Summary |
714
+ |---------|------|---------|
715
+ | Git Versioning (`cinna git`) | [business](features/git_versioning/git_versioning.md) · [tech](features/git_versioning/git_versioning_tech.md) · [acceptance](features/git_versioning/git_versioning_acceptance.md) | Version an agent's workspace with git against its external remote (commit/push/pull/rollback) alongside live Mutagen sync. |
716
+
717
+ ---
718
+
531
719
  ## Related Projects
532
720
 
533
721
  - **cinna-core** — the platform backend. Hosts the API routes this CLI calls, the agent runtime, env core, building mode, and the web UI. Source plan for this CLI feature: `cinna-core/docs/drafts/cinna-cli-live-sync_plan.md`.