cinna-cli 0.1.6__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. cinna_cli-0.2.0/PKG-INFO +371 -0
  2. cinna_cli-0.2.0/README.md +334 -0
  3. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/docs/mutagen_capabilities.md +21 -2
  4. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/pyproject.toml +1 -1
  5. cinna_cli-0.2.0/src/cinna/account.py +2054 -0
  6. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/bootstrap.py +129 -55
  7. cinna_cli-0.2.0/src/cinna/client.py +693 -0
  8. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/config.py +5 -0
  9. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/errors.py +10 -0
  10. cinna_cli-0.2.0/src/cinna/main.py +1784 -0
  11. cinna_cli-0.2.0/src/cinna/mcp_proxy.py +255 -0
  12. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/sync_session.py +288 -4
  13. cinna_cli-0.2.0/src/cinna/templates/ACCOUNT_CLAUDE.md.template +162 -0
  14. cinna_cli-0.2.0/tests/test_account.py +2853 -0
  15. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_client.py +49 -1
  16. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_main.py +178 -0
  17. cinna_cli-0.2.0/tests/test_sync_session.py +602 -0
  18. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/uv.lock +1 -1
  19. cinna_cli-0.1.6/PKG-INFO +0 -234
  20. cinna_cli-0.1.6/README.md +0 -197
  21. cinna_cli-0.1.6/src/cinna/client.py +0 -191
  22. cinna_cli-0.1.6/src/cinna/main.py +0 -786
  23. cinna_cli-0.1.6/src/cinna/mcp_proxy.py +0 -151
  24. cinna_cli-0.1.6/tests/test_sync_session.py +0 -290
  25. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/.github/workflows/publish.yml +0 -0
  26. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/.gitignore +0 -0
  27. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/LICENSE.md +0 -0
  28. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/docs/README.md +0 -0
  29. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/docs/interface.md +0 -0
  30. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/__init__.py +0 -0
  31. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/auth.py +0 -0
  32. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/console.py +0 -0
  33. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/context.py +0 -0
  34. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/logging.py +0 -0
  35. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/mutagen_runtime.py +0 -0
  36. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/sync.py +0 -0
  37. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/sync_ssh_shim.py +0 -0
  38. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/sync_tui.py +0 -0
  39. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/templates/CLAUDE.md.template +0 -0
  40. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/src/cinna/templates/__init__.py +0 -0
  41. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/__init__.py +0 -0
  42. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/conftest.py +0 -0
  43. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_auth.py +0 -0
  44. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_bootstrap.py +0 -0
  45. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_config.py +0 -0
  46. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_context.py +0 -0
  47. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_mutagen_runtime.py +0 -0
  48. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_sync.py +0 -0
  49. {cinna_cli-0.1.6 → cinna_cli-0.2.0}/tests/test_sync_ssh_shim.py +0 -0
@@ -0,0 +1,371 @@
1
+ Metadata-Version: 2.4
2
+ Name: cinna-cli
3
+ Version: 0.2.0
4
+ Summary: Local development CLI for Cinna Core agents
5
+ Project-URL: Homepage, https://github.com/opencinna/cinna-cli
6
+ Project-URL: Repository, https://github.com/opencinna/cinna-cli
7
+ Project-URL: Issues, https://github.com/opencinna/cinna-cli/issues
8
+ Author-email: evgeny-l <evgeny-l@opencinna.io>
9
+ License: MIT
10
+ License-File: LICENSE.md
11
+ Keywords: agents,cinna,cli,developer-tools,mcp,mutagen
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: mcp>=1.0
28
+ Requires-Dist: rich>=13.0
29
+ Requires-Dist: textual>=0.50
30
+ Requires-Dist: websockets>=12.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: respx>=0.21; extra == 'dev'
35
+ Requires-Dist: ruff>=0.4; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # cinna-cli
39
+
40
+ Local development CLI for [Cinna Core](https://github.com/opencinna/cinna-core) agents.
41
+
42
+ Work on agent scripts, prompts, and webapps locally with your own editor and AI tools. The CLI keeps your workspace continuously synced with the remote agent environment, streams commands to it, and wires up MCP integration — so the platform is the single source of truth for runtime and credentials.
43
+
44
+ ## How It Works
45
+
46
+ Cinna Core agents run in managed cloud environments. `cinna-cli` does **not** run a local Docker container. Instead:
47
+
48
+ 1. **Continuous sync** — [Mutagen](https://mutagen.io) keeps `./workspace` bidirectionally synced with the remote agent env over a WebSocket tunnel to the platform.
49
+ 2. **Remote exec** — `cinna exec <cmd>` streams your command through the platform to the remote env, with live stdout/stderr and the remote process's exit code.
50
+ 3. **MCP integration** — the local MCP proxy gives Claude Code / opencode access to the agent's knowledge base.
51
+
52
+ ```
53
+ Your Editor / Claude Code
54
+ │
55
+ ▼
56
+ workspace/ ← edit locally
57
+ │
58
+ cinna sync (Mutagen) ◄──► Remote Agent Environment (no local container)
59
+ │
60
+ cinna exec <cmd> ── streaming output
61
+ ```
62
+
63
+ ## Prerequisites
64
+
65
+ - **Python 3.10+**
66
+ - **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install)
67
+
68
+ ## Getting Started
69
+
70
+ Setup is initiated from the Cinna Core platform UI. Click **"Local Development"** on your agent's page to get a bootstrap command:
71
+
72
+ ```bash
73
+ curl -s https://your-platform.com/api/cli-setup/TOKEN | python3 -
74
+ ```
75
+
76
+ This will:
77
+
78
+ 1. Install `cinna-cli` (via `uv`, `pipx`, or `pip`)
79
+ 2. Exchange the setup token for CLI credentials
80
+ 3. Verify / prompt-install the required Mutagen version
81
+ 4. Clone the workspace (one-shot tarball; Mutagen takes over afterwards)
82
+ 5. Generate `CLAUDE.md`, `BUILDING_AGENT.md`, `.mcp.json`, `opencode.json`, `.gitignore`, `mutagen.yml`
83
+ 6. Start the continuous sync session
84
+
85
+ After setup:
86
+
87
+ ```bash
88
+ cd hr-manager-agent/
89
+ cinna dev # start a foreground dev session (live sync + TUI)
90
+ claude # open Claude Code (MCP tools auto-configured)
91
+ cinna sync status # see sync state from another terminal
92
+ cinna exec python scripts/main.py # run a command in the remote env
93
+ cinna list # see every agent registered on this machine
94
+ ```
95
+
96
+ ## Commands
97
+
98
+ ### `cinna setup <token_or_url>`
99
+
100
+ Initialize a local workspace. Accepts the setup token, the URL, or the full curl command from the platform UI.
101
+
102
+ The agent directory name is normalized to lowercase with dashes ("HR Manager Agent" → `hr-manager-agent/`).
103
+
104
+ ### `cinna set-token <token_or_url>`
105
+
106
+ Refresh the CLI token on the current workspace without re-cloning. Run this from inside an existing agent directory when the stored token has expired — `cinna set-token` re-exchanges the setup token via `POST /api/cli-setup/{token}` and swaps the result into `.cinna/config.json` and `~/.cinna/agents.json` in place. Workspace files, `mutagen.yml`, and generated context files are left untouched.
107
+
108
+ Accepts the same input forms as `cinna setup` (curl command, URL, or bare token). When only a bare token is given, the platform URL is reused from the workspace's existing `.cinna/config.json` — so you can refresh each agent from inside its own directory even if different agents live on different platforms. The exchanged token must belong to the same agent as the workspace; mismatched agent IDs abort the refresh.
109
+
110
+ ```bash
111
+ cd hr-manager-agent/
112
+ cinna set-token yWo36tbkdAOzrALxOEKq31_OA2iMelEg
113
+ ```
114
+
115
+ ### `cinna account setup <token_or_url>`
116
+
117
+ Initialize an **account workspace** — a multi-agent root from which you can discover your agents and attach per-agent workspaces without going back to the UI. Setup is initiated from **Settings → Channels → Local Development** on the platform, which emits a `curl | python3` one-liner (same pattern as the per-agent flow):
118
+
119
+ ```bash
120
+ curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -
121
+ ```
122
+
123
+ Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates `my-cinna/` (override with `--dir`) containing:
124
+
125
+ ```
126
+ my-cinna/
127
+ .cinna/account.json # account CLI token + platform/frontend URLs (0600, do not commit)
128
+ CLAUDE.md # orchestrator guide for AI tools
129
+ context/ # platform docs, API reference, example scripts, worked playbooks
130
+ agents/ # one standard per-agent workspace per `cinna agent sync`
131
+ ```
132
+
133
+ Setup also downloads the **context package** into `context/` — curated platform docs (feature map at `context/platform/README.md`), a generated per-domain REST API reference (`context/api_reference/`), sample platform-API scripts (`context/examples/`), and worked end-to-end playbooks (`context/guides/`, e.g. `build-an-agentic-network.md`). The download is best-effort: if it fails, setup still succeeds with a warning and `cinna account refresh-context` fetches it later.
134
+
135
+ The account token is only used for the account-level endpoints (listing agents, minting per-agent tokens, the context package). Per-agent work always runs on each child workspace's own token. Revoking the account session in Settings disconnects every agent synced from it.
136
+
137
+ ### `cinna account agents`
138
+
139
+ List the agents your account can access (run from inside the account workspace). For each agent: display name + ID, building rights (`✓ can build`, `view-only`, or `foreign install` — installed bundles are publisher-managed and can't be synced), whether a remote environment is active, and whether a local workspace already exists under `agents/`.
140
+
141
+ ### `cinna account status`
142
+
143
+ One-shot summary of the account workspace: platform/frontend URLs, machine name, synced-agent count, and an account-token probe (`valid token` / `expired token` / `no connection`) — the account-level counterpart of `cinna status`.
144
+
145
+ ### `cinna account refresh-context`
146
+
147
+ Re-download the context package and replace the account workspace's `context/` tree (run from inside the account workspace). Use it when the platform ships updated docs or API reference. The existing tree is only removed after a successful download — a failed refresh warns and leaves the previous `context/` intact.
148
+
149
+ ### `cinna account user-workspace list | activate <name|id> | clear`
150
+
151
+ Choose the **active user workspace** for the account session. Workspace-scoped resources you create from the account workspace — new agents (`cinna agent create`) and the credentials they acquire — land in the active workspace, just like picking a workspace in the web sidebar before creating things. The selection is stored **client-side** in `.cinna/account.json`; the platform keeps no active-workspace state.
152
+
153
+ ```bash
154
+ cinna account user-workspace list # show workspaces, marking the active one
155
+ cinna account user-workspace activate Sales # by name or id
156
+ cinna account user-workspace activate default # clear back to the Default (unassigned) workspace
157
+ ```
158
+
159
+ ### `cinna account credentials list | types | create | update | delete | share-with-agent`
160
+
161
+ Draft and wire the credentials your agents need — **without ever handling secret values**. The account CLI scaffolds a credential as a *draft* and attaches it to an agent; the **user fills the secret in the web UI** (the draft shows as "needs setup" until then). This lets a local coding agent set up everything an agent requires and simply tell the user what to fill in — they don't have to think about what to create or share.
162
+
163
+ The account token can never read or write a credential's secret value — these verbs touch only metadata and structure.
164
+
165
+ ```bash
166
+ cinna account credentials types # types + the fields the user must fill
167
+ cinna account credentials create --name "Stripe Key" --type api_token \
168
+ --agent billing-agent # create a draft and attach it in one step
169
+ # → prints required fields (e.g. api_token) + a link to fill them in
170
+ cinna account credentials list # name, type, status (complete / needs setup)
171
+ cinna account credentials share-with-agent <cred_id> --agent crm-agent
172
+ cinna account credentials update <cred_id> --name "Stripe (live)"
173
+ cinna account credentials delete <cred_id> --yes
174
+ ```
175
+
176
+ A new draft lands in the account's [active user workspace](#cinna-account-user-workspace-list--activate-nameid--clear). Deletes reuse the platform's blast-radius gate (a publisher-provided credential in a published bundle with active installs needs `--force`). All write verbs require the `agent-developer` role.
177
+
178
+ ### `cinna agent create <name> [--description TEXT]`
179
+
180
+ Create a new agent on the platform from the account workspace — no UI interaction. Thin client: only the name (and optional description) is sent; the backend applies all defaults (default AI credentials, env template, environment creation) exactly as creating from the UI does. The agent is created in the account's [active user workspace](#cinna-account-user-workspace-list--activate-nameid--clear) (if one is set). Prints the created agent's ID and web UI link, plus a hint to attach a local workspace with `cinna agent sync <name>`. Requires the `agent-developer` role (403 otherwise). Template selection is not supported yet — agents always get the server default.
181
+
182
+ ```bash
183
+ cinna agent create "CRM Agent" --description "Tracks customer accounts"
184
+ cinna agent sync crm-agent
185
+ ```
186
+
187
+ ### `cinna agent sync <agent>`
188
+
189
+ 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:
190
+
191
+ ```bash
192
+ cd agents/hr-manager-agent/
193
+ cinna dev
194
+ ```
195
+
196
+ 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.
197
+
198
+ ### `cinna agent unsync <agent>`
199
+
200
+ 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.
201
+
202
+ ### `cinna connect agent-api --producer <agent> --consumer <agent> [--label TEXT] [--read-only]`
203
+
204
+ Wire one agent to another's REST API from the account workspace. Resolves both agents (name, slug, or ID), mints a producer API token, and attaches it to the consumer as a credential — which rides the consumer's normal credential sync into its remote environment, so no key ever touches your machine. Prints the credential ID, token prefix, base URL, and spec URL. `--read-only` restricts the consumer to read-only access; `--label` names the credential. Backend errors surface verbatim: 400 if the producer's REST API is disabled, 403/404 for ownership violations.
205
+
206
+ ```bash
207
+ cinna connect agent-api --producer crm-agent --consumer hr-manager-agent --read-only
208
+ ```
209
+
210
+ ### `cinna connect mcp --producer <agent> --consumer <agent> [--label TEXT] [--conversation-only|--building-only]`
211
+
212
+ Wire one agent to another's agent2agent MCP connector. The consumer is resolved from your agents; the producer is resolved against the platform's discoverable-connectors listing (it must expose an agent2agent MCP connector your account is allowed to consume — the error lists the discoverable options otherwise). By default the connection is enabled in both conversation and building modes; scope it with `--conversation-only` / `--building-only`. Prints the credential ID, endpoint, transport, and status — plus an authorize URL to open if the connector requires OAuth.
213
+
214
+ ```bash
215
+ cinna connect mcp --producer crm-agent --consumer hr-manager-agent --building-only
216
+ ```
217
+
218
+ ### `cinna api <METHOD> <path> [--json TEXT | --data @file.json] [--query k=v ...]`
219
+
220
+ Generic escape hatch into the platform API, authenticated with the account token (run from the account workspace). `<path>` is relative to the API root — `agents`, `agents/<id>` — no `/api/v1` prefix. The endpoint catalogue ships in the account workspace under `context/api_reference/`.
221
+
222
+ - `--json '<obj>'` or `--data @file.json` supply a JSON request body (mutually exclusive); repeatable `--query k=v` supplies query parameters (repeating a key builds a list).
223
+ - The inner response is passed through verbatim: the body prints to stdout (pretty-printed for JSON) and the exit code is `0` for 2xx and `1` for an inner 4xx/5xx — so it composes in shell pipelines.
224
+ - When the escape hatch itself refuses the call, the detail prints to stderr and the exit code is `2`: policy denials (credentials, user management, admin, CLI, MFA/auth, and streaming routes are excluded — shown as `blocked by platform policy: …`), rate limiting (429, with the Retry-After delay), and request/response size caps (413/502).
225
+
226
+ ```bash
227
+ cinna api GET agents
228
+ cinna api GET agents --query limit=5
229
+ cinna api PATCH agents/3fa85f64-5717-4562-b3fc-2c963f66afa6 --json '{"description": "updated"}'
230
+ cinna api POST tasks --data @task.json
231
+ ```
232
+
233
+ ### `cinna dev`
234
+
235
+ 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`.
236
+
237
+ ### `cinna redev`
238
+
239
+ Like `cinna dev`, but conflicts surfaced by the initial reconciliation are resolved automatically in favor of the **remote** version. Use it to resume work on an agent that was modified from the platform side while your local copy sat idle — same connection, same credentials, no re-setup; the remote data simply wins the startup divergence.
240
+
241
+ The displaced local versions are backed up under `.cinna/sync/redev-backup/<timestamp>/` before being overwritten. Only startup conflicts are auto-resolved — conflicts that arise later in the session are surfaced normally (Conflicts tab / `cinna sync conflicts`).
242
+
243
+ ```bash
244
+ cd hr-manager-agent/
245
+ cinna redev # remote wins the initial conflicts, then a normal dev session
246
+ ```
247
+
248
+ ### `cinna sync status | conflicts | push | pull | resolve`
249
+
250
+ 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.
251
+
252
+ - `status` — state, pending changes, conflict count. Warns loudly when conflicts mean your edits aren't fully live.
253
+ - `conflicts` — list conflicted paths (sourced from the Mutagen daemon, so it agrees with `status`; two-way-safe writes no `.conflict.*` files on disk).
254
+ - `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.
255
+ - `pull [--force]` — the mirror; `--force` resolves in favor of **remote** (e.g. after the backend regenerates managed files).
256
+ - `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.
257
+
258
+ ### `cinna exec <command…>`
259
+
260
+ Stream a command through the platform to the remote agent environment. Output streams back live; Ctrl+C aborts. Exit code matches the remote process.
261
+
262
+ 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/`.
263
+
264
+ 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 '…'`.
265
+
266
+ With `--agent <agent>`, run from an account workspace root against the named synced agent (name, slug, or ID) using that child workspace's own token — the agent must already be attached with `cinna agent sync`.
267
+
268
+ ```bash
269
+ cinna exec python scripts/main.py
270
+ cinna exec pip install pandas
271
+ cinna exec bash -c 'ls -la'
272
+ cinna exec python -c 'import sys; print(sys.argv)' "a b"
273
+ cinna exec --agent crm-agent python scripts/main.py # from the account root
274
+ ```
275
+
276
+ ### `cinna status`
277
+
278
+ One-shot summary of the agent + current sync state. Includes a backend probe (`GET /sync-runtime`) that reports whether the stored CLI token is still accepted — `valid token`, `expired token`, or `no connection`. Use `cinna set-token` to refresh an expired token.
279
+
280
+ ### `cinna list`
281
+
282
+ List every agent registered on this machine (from `~/.cinna/agents.json`). Three columns:
283
+
284
+ 1. **Agent** — display name on top, full agent ID below.
285
+ 2. **Location** — workspace path on top, platform UI link below. Missing directories are flagged in red.
286
+ 3. **Sync** — Mutagen session state on top (`active` / `paused` / `connecting` / `error`), plus a per-agent backend probe (`valid token` / `expired token` / `no connection`) on the bottom. The probes run in parallel with a short timeout so the view stays snappy even with many registered agents.
287
+
288
+ ### `cinna disconnect`
289
+
290
+ Stop sync, remove `.cinna/` config and generated files (`CLAUDE.md`, `BUILDING_AGENT.md`, `.mcp.json`, `opencode.json`, `mutagen.yml`). Workspace files are preserved.
291
+
292
+ ### `cinna disconnect-all`
293
+
294
+ Scan the current directory for every cinna workspace (directories containing `.cinna/config.json`), stop each sync session, and delete the directories entirely. Prompts for confirmation and prints a summary of what was removed.
295
+
296
+ ### `cinna completion [SHELL] [--install]`
297
+
298
+ Output or install shell completion for bash, zsh, or fish.
299
+
300
+ ## Workspace Structure
301
+
302
+ After setup, the agent directory looks like:
303
+
304
+ ```
305
+ my-agent/
306
+ .cinna/ # CLI config (do not edit)
307
+ config.json
308
+ workspace/ # Continuously synced with the remote env
309
+ scripts/ # Bundle-owned: agent Python scripts
310
+ docs/ # Bundle-owned: WORKFLOW/ENTRYPOINT/REFINER prompts
311
+ webapp/ # Bundle-owned: dashboard + data endpoints
312
+ knowledge/ # Bundle-owned: static integration docs
313
+ files/ # Bundle-owned: static publisher-shipped assets
314
+ app-data/ # Per-user persistent — NOT shipped in bundle revisions.
315
+ # Backed by a platform AppDataVolume keyed by (user_id, bundle_id);
316
+ # mounted on the platform at /app/workspace/app-data.
317
+ # Survives apply-update and uninstall/reinstall.
318
+ storage/ # long-lived runtime output (DBs, reports, derived data)
319
+ uploads/ # all user-supplied file uploads at runtime
320
+ # (chat attachments, task attachments, MCP uploads)
321
+ cache/ # disposable caches
322
+ credentials/ # Backend-managed; visible read-only on your side
323
+ workspace_requirements.txt
324
+ workspace_system_packages.txt
325
+ mutagen.yml # Sync rules (customizable)
326
+ CLAUDE.md # Local dev instructions for AI tools
327
+ BUILDING_AGENT.md # Building mode prompt pulled from the platform
328
+ .mcp.json # MCP config for Claude Code
329
+ opencode.json # MCP config for opencode
330
+ .gitignore # ignores workspace/credentials/ and workspace/app-data/
331
+ ```
332
+
333
+ **Persistence tiers** mirror the platform's bundle/install model:
334
+
335
+ - **Bundle-owned** folders (`scripts/`, `docs/`, `webapp/`, `knowledge/`, `files/`, `workspace_requirements.txt`, `workspace_system_packages.txt`) are part of what gets snapshotted when a new bundle revision is published. As the developer/publisher, your edits here become the next shipped revision.
336
+ - **`app-data/`** is the per-user persistent runtime volume. On the platform it lives in an `AppDataVolume` keyed by `(user_id, bundle_id)` — one volume per user per bundle, bind-mounted into the agent container at `/app/workspace/app-data`. It is **not** part of bundle revisions: when you publish, only the bundle-owned folders are snapshotted, and every user who installs your bundle gets their own fresh app-data volume. On the platform side the volume survives `apply-update` (bundle folders are overwritten, app-data is never touched) and uninstall/reinstall (orphaned, not deleted; reattaches by `bundle_id`). What you see synced to your local `workspace/app-data/` is your *own* developer install's app-data — useful for inspecting runtime output your scripts produce. It's gitignored by default since it's per-user runtime state, not bundle content.
337
+
338
+ Where scripts should put what:
339
+ - **`storage/`** — long-lived runtime state (databases, JSON, CSVs, generated reports). Anything the agent must keep across sessions and bundle updates.
340
+ - **`uploads/`** — every user-supplied file at runtime lands here automatically: chat attachments, task attachments, MCP `get_file_upload_url` uploads. Read from this folder, don't write to it from scripts.
341
+ - **`cache/`** — disposable caches the scripts may rebuild on demand.
342
+ - **`credentials/`** is managed by the backend and only readable on your side.
343
+
344
+ ## Working with AI Coding Tools
345
+
346
+ Setup generates MCP server configs for **Claude Code** (`.mcp.json`) and **opencode** (`opencode.json`), giving your AI tool a `knowledge_query` tool that searches the agent's knowledge base.
347
+
348
+ ```bash
349
+ cd my-agent/
350
+ claude # or: opencode
351
+ ```
352
+
353
+ ## Sync & Conflict Resolution
354
+
355
+ `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.
356
+
357
+ Large binary files and build artifacts are ignored by default (see `mutagen.yml`). Add your own ignores there if needed.
358
+
359
+ ## Development
360
+
361
+ ```bash
362
+ git clone https://github.com/opencinna/cinna-cli.git
363
+ cd cinna-cli
364
+ uv venv && uv pip install -e ".[dev]"
365
+ uv run pytest -v
366
+ uv run ruff check src/
367
+ ```
368
+
369
+ ## License
370
+
371
+ MIT