cinna-cli 0.3.0__tar.gz → 0.4.1__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.
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/PKG-INFO +173 -6
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/README.md +172 -5
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/README.md +13 -6
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/account_workspace/account_workspace.md +85 -7
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/account_workspace/account_workspace_acceptance.md +117 -3
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/account_workspace/account_workspace_tech.md +98 -12
- cinna_cli-0.4.1/docs/features/agent_addons/agent_addons.md +346 -0
- cinna_cli-0.4.1/docs/features/agent_addons/agent_addons_acceptance.md +639 -0
- cinna_cli-0.4.1/docs/features/agent_addons/agent_addons_tech.md +416 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_api/agent_api.md +17 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_api/agent_api_tech.md +3 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_management/agent_management.md +26 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_management/agent_management_acceptance.md +39 -4
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_management/agent_management_tech.md +30 -4
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding.md +44 -6
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding_acceptance.md +45 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/bootstrap_onboarding/bootstrap_onboarding_tech.md +109 -6
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/pyproject.toml +1 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/account.py +2216 -35
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/bootstrap.py +1 -2
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/chat.py +1 -1
- cinna_cli-0.4.1/src/cinna/cli_version.py +184 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/client.py +388 -1
- cinna_cli-0.4.1/src/cinna/console.py +187 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/doctor.py +46 -3
- cinna_cli-0.4.1/src/cinna/errors.py +249 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/local_import.py +1 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/main.py +639 -25
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/mutagen_runtime.py +40 -9
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/sync.py +4 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/sync_session.py +2 -1
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/sync_tui.py +6 -9
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/templates/ACCOUNT_CLAUDE.md.template +31 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/templates/CLAUDE.md.template +9 -5
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/conftest.py +10 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_account.py +2015 -1
- cinna_cli-0.4.1/tests/test_cli_version.py +150 -0
- cinna_cli-0.4.1/tests/test_client.py +471 -0
- cinna_cli-0.4.1/tests/test_onboarding.py +800 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/uv.lock +1 -1
- cinna_cli-0.3.0/src/cinna/console.py +0 -39
- cinna_cli-0.3.0/src/cinna/errors.py +0 -66
- cinna_cli-0.3.0/tests/test_client.py +0 -196
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/.claude/commands/cinna-cli.feature.doc.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/.github/workflows/publish.yml +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/.gitignore +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/LICENSE.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_api/agent_api_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_schedules/agent_schedules.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_schedules/agent_schedules_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/agent_schedules/agent_schedules_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/doctor/doctor.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/doctor/doctor_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/doctor/doctor_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/git_versioning/git_versioning.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/git_versioning/git_versioning_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/git_versioning/git_versioning_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/improvement_requests/improvement_requests.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/improvement_requests/improvement_requests_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/improvement_requests/improvement_requests_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/live_sync/live_sync.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/live_sync/live_sync_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/live_sync/live_sync_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/local_agent_import/local_agent_import.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/local_agent_import/local_agent_import_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/local_agent_import/local_agent_import_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/mcp_integration/mcp_integration.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/mcp_integration/mcp_integration_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/mcp_integration/mcp_integration_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_chat/remote_chat.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_chat/remote_chat_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_chat/remote_chat_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_exec/remote_exec.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_exec/remote_exec_acceptance.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/features/remote_exec/remote_exec_tech.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/interface.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/docs/mutagen_capabilities.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/scripts/check_docs_references.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/__init__.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/auth.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/config.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/context.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/git_versioning.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/improve.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/kit_contract.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/logging.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/mcp_proxy.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/sync_ssh_shim.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/templates/CHAT_TESTING.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/templates/GIT_VERSIONING.md +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/src/cinna/templates/__init__.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/__init__.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_auth.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_bootstrap.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_chat.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_config.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_context.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_doctor.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_git_versioning.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_improve.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_kit_contract.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_local_import.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_main.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_mutagen_runtime.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_sync.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/tests/test_sync_session.py +0 -0
- {cinna_cli-0.3.0 → cinna_cli-0.4.1}/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.
|
|
3
|
+
Version: 0.4.1
|
|
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
|
|
@@ -63,7 +63,11 @@ Your Editor / Claude Code
|
|
|
63
63
|
## Prerequisites
|
|
64
64
|
|
|
65
65
|
- **Python 3.10+**
|
|
66
|
-
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install)
|
|
66
|
+
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install; set `CINNA_MUTAGEN_BIN=/abs/path/mutagen` to use a specific binary instead of the one on PATH)
|
|
67
|
+
|
|
68
|
+
### Cinna Desktop
|
|
69
|
+
|
|
70
|
+
[Cinna Desktop](https://github.com/opencinna/cinna-desktop) installs its **own pinned copy** of cinna-cli (with `uv` and Mutagen alongside, inside its data folder) and drives it as a child process to create and keep alive an account workspace under `<AgentsHome>/Cloud/<host>/` right after you sign in — no `cinna login`, no token to paste. That private copy is not on your `PATH` unless you opt in from the desktop's settings; installing cinna-cli yourself (`uv tool install cinna-cli`) for terminal use is fine and both operate on the same workspace. The version the platform pins is reported by `cinna account status` / `cinna doctor`.
|
|
67
71
|
|
|
68
72
|
## Getting Started
|
|
69
73
|
|
|
@@ -135,7 +139,7 @@ cinna login app.example.com --dir my-cinna # always into a named sub
|
|
|
135
139
|
# ✓ Account workspace ready.
|
|
136
140
|
```
|
|
137
141
|
|
|
138
|
-
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account
|
|
142
|
+
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account set-token` paste fallback.
|
|
139
143
|
|
|
140
144
|
### `cinna account setup <token_or_url>`
|
|
141
145
|
|
|
@@ -145,7 +149,7 @@ Initialize an **account workspace** — a multi-agent root from which you can di
|
|
|
145
149
|
curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -
|
|
146
150
|
```
|
|
147
151
|
|
|
148
|
-
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates
|
|
152
|
+
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates a folder named after the platform domain (override with `--dir`: an absolute path is used as is with parents created, a relative one lands under the current directory; an existing account workspace there is refused before the token is spent) containing:
|
|
149
153
|
|
|
150
154
|
```
|
|
151
155
|
my-cinna/
|
|
@@ -159,15 +163,28 @@ Setup also downloads the **context package** into `context/` — curated platfor
|
|
|
159
163
|
|
|
160
164
|
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.
|
|
161
165
|
|
|
166
|
+
`account setup`, `account set-token` and `account status` take `--no-input` (never prompt: defaults, or fail with code `needs_input`; also `CINNA_NO_INPUT=1`, accepted before or after the subcommand) and `--json` (one JSON object per line on stdout — progress `{"step","total","status","message"}` lines, then a final `{"result":"ok"|"error",…}`; implies `--no-input`). Exit codes are stable for every command: `0` ok, `10` setup token invalid/expired/used, `11` token for another account, `12` platform unreachable or 5xx, `1` anything else (the JSON `code` says what), `2` usage.
|
|
167
|
+
|
|
168
|
+
### `cinna account set-token <token_or_url>`
|
|
169
|
+
|
|
170
|
+
Refresh the **account** token in place from a fresh account setup token — the account counterpart of `cinna set-token`, and the paste alternative to `cinna login`. Run inside the account workspace; it re-exchanges under the stored machine name and rewrites only `account_token` (plus a refreshed platform/frontend URL) in `.cinna/account.json`. The active user workspace, machine name, `context/` and every synced child under `agents/` are untouched; run `cinna doctor` afterwards to re-mint expired child tokens. A token for a different account is refused (exit `11`) and nothing is written. Bare tokens reuse the stored platform URL.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cd my-cinna/
|
|
174
|
+
cinna account set-token 'curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -'
|
|
175
|
+
```
|
|
176
|
+
|
|
162
177
|
### `cinna account agents`
|
|
163
178
|
|
|
164
|
-
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/`.
|
|
179
|
+
List the agents your account can access (run from inside the account workspace). Ids are printed in full at any terminal width (the column folds rather than ellipsizing — a truncated UUID is a copy-paste trap that the API answers `404 not found` for). 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/`.
|
|
165
180
|
|
|
166
181
|
### `cinna account status`
|
|
167
182
|
|
|
168
183
|
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`.
|
|
169
184
|
|
|
170
|
-
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there.
|
|
185
|
+
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there. Likewise it compares the installed **cinna-cli version** with the one the platform pins (its `/.well-known/cinna-desktop` discovery document) and suggests `uv tool install cinna-cli==<pin>` when behind; no pin means "unknown", not an error. An **editable install** (`uv tool install -e`, `pip install -e`) is detected and labelled instead of compared — its metadata records the version it was installed at and never changes again, so pinning that number against the platform's would report skew that does not exist and explain missing features with a version that is not the code being run. It renders as `0.2.5 (editable checkout of /path/to/cinna-cli)`, with the pin named as context, and neither `cinna account status` nor `cinna doctor` nudges an upgrade.
|
|
186
|
+
|
|
187
|
+
With `--json` it prints a single line: `{"result":"ok","workspace",…,"token":"valid|expired|unreachable","synced_agents":N,"agents":[…],"context_package":{"local","remote","state"},"cli":{"installed","required","state"}}`.
|
|
171
188
|
|
|
172
189
|
### `cinna account refresh-context`
|
|
173
190
|
|
|
@@ -278,6 +295,150 @@ The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json
|
|
|
278
295
|
|
|
279
296
|
Where the folder has been published is recorded in `publications.json`, a **sibling** of `cinna-agent.json` holding one entry per Cinna instance — it cannot live inside the manifest, because each entry records a hash of the exported tree and the manifest is part of that tree. Every step is idempotent (agent by the entry whose `platform_url` matches the instance you are logged into, credentials by name, schedules by name), so a partial import is resumed with `--update` instead of duplicating anything. The publication is recorded **only after the push settled** — `--no-push`, a failed flush, or remaining conflicts leave it unrecorded, and the next run is a plain `--update`. A legacy `cloud` block is migrated into the ledger on the first write and is still read until then, so an older folder's `--update` never creates a second agent. `--dry-run` makes no platform call and writes nothing.
|
|
280
297
|
|
|
298
|
+
### `cinna skills list <agent> [--json]`
|
|
299
|
+
|
|
300
|
+
List everything an agent carries beyond its prompt, as one deduplicated list. An **addon** is either an installed plugin or a `skills/<name>/` folder — a `SKILL.md` plus its files that the engine loads on demand. The two overlap (a skill installed from the catalog is *also* a plugin link), and the platform owns the dedupe rule, so this prints the server's projection rather than folding the halves itself: one row per addon, with its kind, source (`marketplace` / `bundle` / `catalog` / `local`), status, name and version.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
cinna skills list crm-agent
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Agent: CRM Agent
|
|
308
|
+
Addons (3)
|
|
309
|
+
┏━━━┳━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
|
310
|
+
┃ # ┃ Kind ┃ Source ┃ Status ┃ Name ┃ Version ┃
|
|
311
|
+
┡━━━╇━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
|
|
312
|
+
│ 1 │ plugin │ marketplace │ ● ok │ pdf-tools (PDF Tools) │ 2.1.0 │
|
|
313
|
+
│ 2 │ skill │ catalog │ ● ok │ dad-jokes (Dad Jokes) │ 1.0.0 → 1.1.0 │
|
|
314
|
+
│ 3 │ skill │ local │ ● ok │ report · published │ 1.0.1 │
|
|
315
|
+
│ 4 │ skill │ local │ ! secrets │ draft │ │
|
|
316
|
+
└───┴────────┴─────────────┴───────────┴───────────────────────┴───────────────┘
|
|
317
|
+
1 plugin(s), 3 skill(s) (2 of them this agent's own).
|
|
318
|
+
|
|
319
|
+
! 1 installed addon(s) have a newer revision: dad-jokes
|
|
320
|
+
Update with: cinna skills update crm-agent dad-jokes
|
|
321
|
+
|
|
322
|
+
! draft (secrets): This skill holds files that look like key material.
|
|
323
|
+
.env
|
|
324
|
+
|
|
325
|
+
A blank version means no `version:` in the skill's SKILL.md — or an index built
|
|
326
|
+
before skills carried one, which fills in after the next refresh or publish.
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
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
|
+
|
|
331
|
+
### `cinna skills publish <agent> <name> [--visibility public|private|users] [--grant EMAIL ...] [--version V] [--notes TEXT] [--package-id ID] [--dry-run] [--yes] [--json]`
|
|
332
|
+
|
|
333
|
+
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).
|
|
334
|
+
|
|
335
|
+
**It publishes the agent's cloud workspace, not the folder you are standing in.** The files are read from the remote workspace on disk — which is why a *suspended* environment publishes fine, no container needs to be running — but an edit that has not synced yet is not there. Run `cinna sync push` first, or you publish the older remote copy as a revision you cannot take back.
|
|
336
|
+
|
|
337
|
+
**Without `--visibility` the package is private and nobody else sees it.** Say `--visibility public` for the catalog, or `--visibility users` with `--grant` for named people.
|
|
338
|
+
|
|
339
|
+
**The version is derived, not typed.** A skill's version is a line in its own `SKILL.md`, and the platform continues the series for you: the header's version if it has not been published yet, otherwise the next one after the newest release (the last run of digits incremented — `1.0.0`→`1.0.1`, `v3`→`v4`), or `1.0.0` for a skill nobody has versioned. The resolved version is written back into `skills/<name>/SKILL.md` on the environment before the snapshot, so the published bytes carry their own version and your next `cinna sync` brings the stamped header down. `--version` overrides it verbatim for one revision — after which the series continues from *that*. `--dry-run` prints the version, package id and revision number a publish would take, from the same code that will take them, and publishes nothing.
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
cinna skills publish crm-agent report --dry-run
|
|
343
|
+
cinna skills publish crm-agent report --visibility public \
|
|
344
|
+
--notes "Adds the quarterly rollup"
|
|
345
|
+
cinna skills publish crm-agent report --visibility users \
|
|
346
|
+
--grant alice@example.com --grant bob@example.com
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
Re-publish report from CRM Agent
|
|
351
|
+
Version: 1.0.2 (header 1.0.1, latest published 1.0.1)
|
|
352
|
+
Package: com.example.skill.report
|
|
353
|
+
Revision: 3
|
|
354
|
+
Publish? [Y/n]:
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
At a terminal that preview is shown and confirmed before the press; `--yes`, `--json` and `--no-input` publish straight away. `--package-id` is optional too — omitted, it is derived as `<reversed host>.skill.<name>`, with your own publisher slug appended when that id is already taken on the instance (`--dry-run` says when that happened, since a hex tail in your own package id has no other explanation).
|
|
358
|
+
|
|
359
|
+
A re-publish appends a revision to the same package, so `--package-id` (the reverse-DNS id, e.g. `com.acme.report`) is only for a first publish — a mismatch on a later one is refused rather than silently ignored. `--visibility` is likewise honoured on a first publish and on an explicit change; omitting it leaves the package as it is. `--grant` requires `--visibility users` and the CLI refuses the combination otherwise, before anything is written. The server would accept it — it stores the grant either way — but a package that is private or public never consults its grant list, so the publish would report success and share nothing, and a revision cannot be taken back. Within a `users` package `--grant` is strictly **additive**: it adds the addresses it names and never revokes the ones it omits (revoking is `cinna skills revoke`, so a stale publish cannot silently remove access), and an unknown address fails the whole publish rather than half-sharing it. On success the package id, revision and its version, visibility and catalog URL are printed, plus a line saying the version landed in `skills/<name>/SKILL.md` — and a warning instead when it could not be written there, because the header and the catalog have then diverged and the next publish continues from the catalog. A refusal is printed as the platform's own sentence with its code (`not_developer`, `foreign_install`, `no_environment`, `workspace_unavailable`, `package_id_immutable`, `skill_contains_secrets` — which also lists the offending files), and `--json` prints `{revision, package, catalog_url, skill_md_updated}` instead of the human block (`--dry-run --json` prints the preview payload).
|
|
360
|
+
|
|
361
|
+
### `cinna skills catalog [--search Q] [--mine] [--json]`
|
|
362
|
+
|
|
363
|
+
Browse the instance skills catalog: one row per package this account may see, with its reverse-DNS **package id**, display name, visibility and newest version. The package id — `com.acme.pdf-report`, not a UUID — is the reference every other package verb takes. A delisted package is marked as such beside its visibility.
|
|
364
|
+
|
|
365
|
+
The route takes no parameters — it answers the whole visible catalogue — so `--search` (matching the id, name and description) and `--mine` (packages this account can manage) narrow the rows locally. `--json` prints the filtered rows, not the raw envelope.
|
|
366
|
+
|
|
367
|
+
### `cinna skills show <package> [--revision N] [--json]`
|
|
368
|
+
|
|
369
|
+
One package in full: its display name, visibility, newest version and package UUID, then the revision table, then the `SKILL.md` of the newest revision (or the one `--revision` names). `<package>` is a package id, a display name, or a UUID. The `SKILL.md` is printed as plain text — it is someone else's file and may contain anything — and a content fetch that fails degrades the output rather than the command, because the package detail is the answer.
|
|
370
|
+
|
|
371
|
+
### `cinna skills revisions <package> [--json]`
|
|
372
|
+
|
|
373
|
+
A package's revisions, **newest first**: number, version, release date, size and the release notes given at publish time. A revision is immutable, so this is the question a publisher has before every publish — what is already out there — and the answer to it no longer requires `cinna api` and a UUID. Pair it with `cinna skills publish <agent> <name> --dry-run`, which says what the *next* one would be.
|
|
374
|
+
|
|
375
|
+
### `cinna skills files <package> [--revision N] [--json]`
|
|
376
|
+
|
|
377
|
+
The files one revision ships, with sizes and the total. A file list the server truncated says so.
|
|
378
|
+
|
|
379
|
+
There is no `download` verb, for two reasons: installing a skill lands it in the agent's own workspace, which sync brings down to the local mirror — so the bytes already arrive that way — and the archive routes are binary, which the JSON-only escape hatch could not carry anyway.
|
|
380
|
+
|
|
381
|
+
### `cinna skills install <agent> <package> [--revision N] [--conversation-only|--building-only] [--json]`
|
|
382
|
+
|
|
383
|
+
Install a catalog package onto an agent. `<agent>` is a name, slug or id; `<package>` is a package id, display name or UUID — the CLI resolves both, so neither a raw UUID nor a hand-built JSON body is needed.
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
cinna skills catalog --search jokes
|
|
387
|
+
cinna skills install crm-agent localhost.skill.dad-jokes
|
|
388
|
+
cinna skills install crm-agent localhost.skill.dad-jokes --revision 2 --conversation-only
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Omitting `--revision` installs whatever the catalog calls latest *now*; because a revision is immutable, the install pins bytes that will not change under the agent until `cinna skills update` moves it. Both modes are on unless `--conversation-only` / `--building-only` narrows where the skill is offered (naming both is refused — it would install a skill offered nowhere).
|
|
392
|
+
|
|
393
|
+
Installing something the agent already carries is answered as a sentence, not a JSON body: the platform's own `already_installed` refusal followed by either "already at the newest revision" or the `cinna skills update` that closes the gap. The `--json` error code stays `already_installed`.
|
|
394
|
+
|
|
395
|
+
### `cinna skills update <agent> <name> [--json]`
|
|
396
|
+
|
|
397
|
+
Move an installed skill to the package's newest revision, printing the version it moved from and to. `<name>` is the name `cinna skills list` prints; the plugin-link id the route actually addresses is resolved internally. The listing's `has_update` is *reported*, never used to skip the call — it comes from a cache, and the upgrade route is what decides.
|
|
398
|
+
|
|
399
|
+
Every install / uninstall / update / toggle also pushes the change into the agent's running environments, and that push can partly fail while the call itself succeeds. When it does, the command says how many environments did not take it and points at `cinna agent restart-env` — a green check alone would hide the one case where the catalog and the live agent disagree. An environment built *before* the feature existed is reported separately (`unsupported_syncs`): the link write is complete and there is nothing to retry, so that half points at `cinna agent rebuild-env` and suppresses the plain success line rather than offering a restart that cannot change the outcome.
|
|
400
|
+
|
|
401
|
+
### `cinna skills uninstall <agent> <name> [--yes] [--json]`
|
|
402
|
+
|
|
403
|
+
Remove an agent's copy of an installed skill. The package and its revisions are untouched — what the agent held was a copy, not a reference. Asks first unless `--yes`. An agent's *own* `skills/<name>/` folder is not an install, and the command says so rather than failing on a route that could never match it.
|
|
404
|
+
|
|
405
|
+
### `cinna skills toggle <agent> <name> [--enable|--disable] [--conversation-mode|--no-conversation-mode] [--building-mode|--no-building-mode] [--json]`
|
|
406
|
+
|
|
407
|
+
Enable or disable an installed skill, or change where it is offered, without removing it. Every switch defaults to "leave it alone" and only the ones named are sent, so `--disable` cannot silently reset the mode flags a previous call set. Naming no switch at all is a usage error rather than a no-op call. A disabled install still lists and still reports its version — it is not an error — so `cinna skills list` marks it `· disabled`.
|
|
408
|
+
|
|
409
|
+
### `cinna skills refresh <agent> [--json]`
|
|
410
|
+
|
|
411
|
+
Rebuild the agent's addon index, reporting how many skills were indexed. Everything else in this group reads the platform's cache — which is what makes it safe against a sleeping environment, and what makes a stale index possible. This is the remedy when `cinna skills list` reports `parse_error`, or shows no version for a skill whose `SKILL.md` has one. It is *not* the remedy for every reason code — see below. The plugin half is refreshed too where the platform offers that route; a platform without it still refreshes the skill half and says so.
|
|
412
|
+
|
|
413
|
+
A refresh that still could not read the index answers **200 with the reason** — so this prints the reason and the remedy *that reason* has, rather than a green check. The four codes do not share a fix, and both `skills refresh` and `skills list` route through the same table:
|
|
414
|
+
|
|
415
|
+
| Code | What it means | The fix it prints |
|
|
416
|
+
|---|---|---|
|
|
417
|
+
| `env_not_running` | The environment is asleep | Send it a message, or refresh again, to wake it |
|
|
418
|
+
| `adapter_error` | Up, but not answering | `cinna agent restart-env <agent>` |
|
|
419
|
+
| `adapter_unsupported` | Built before agent skills existed; no skills endpoint to answer | `cinna agent rebuild-env <agent>` |
|
|
420
|
+
| `parse_error` | Answered, but the index did not parse | `cinna skills refresh <agent>` |
|
|
421
|
+
|
|
422
|
+
An unrecognised code gets a generic "refresh again, then check the logs" and names **no** verb: a code whose fix this build cannot name is one where guessing a verb sends the caller round a loop that cannot close. That is exactly what the old copy did to `adapter_unsupported` — it printed one hardcoded remedy for every code, so a container missing the route was told to restart (which re-runs the same image) or, in `skills list`, to "Rebuild it with: cinna skills refresh" (which re-reads a route that is not there, and calls a refresh a rebuild).
|
|
423
|
+
|
|
424
|
+
### `cinna skills grants <package> [--json]` · `grant <package> --user EMAIL` · `revoke <package> --user EMAIL [--yes]`
|
|
425
|
+
|
|
426
|
+
Who is named on a package, and adding or removing one. Visibility and grants belong to the *package*, not to a revision, so changing them costs no new revision — this is the post-publish half of `cinna skills publish --grant`.
|
|
427
|
+
|
|
428
|
+
A grant list is stored on any package but only *consulted* on one whose visibility is `users`, so `grants` prints the visibility beside the rows and both verbs warn when the list is being ignored. `revoke` takes the same email `grant` did and resolves it to the user id the route actually addresses; an address that was never granted is a sentence naming who actually is.
|
|
429
|
+
|
|
430
|
+
### `cinna skills visibility <package> <public|private|users> [--json]`
|
|
431
|
+
|
|
432
|
+
Change who may see a package after it was published. Switching to `users` with nobody named warns that it shares the package with nobody — the one setting that looks like sharing and is not.
|
|
433
|
+
|
|
434
|
+
### `cinna skills delist <package> [--yes] [--json]`
|
|
435
|
+
|
|
436
|
+
Take a package out of the catalog. Agents that already installed it keep what they have: a revision they hold is a copy, not a reference. Asks first unless `--yes`. Deleting a package outright is still web-UI only.
|
|
437
|
+
|
|
438
|
+
### `cinna skills relist <package> [--json]`
|
|
439
|
+
|
|
440
|
+
Put a delisted package back. `delist` has no inverse route of its own — without this verb the only way back would be `cinna api`, which would make delisting the one door in this group that opens only outwards.
|
|
441
|
+
|
|
281
442
|
### `cinna connect agent-api --producer <agent> --consumer <agent> [--label TEXT] [--read-only]`
|
|
282
443
|
|
|
283
444
|
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.
|
|
@@ -302,8 +463,13 @@ Generic escape hatch into the platform API, authenticated with the account token
|
|
|
302
463
|
- 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.
|
|
303
464
|
- 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).
|
|
304
465
|
|
|
466
|
+
`<path>` accepts the same **agent references** the rest of the CLI does: a segment straight after `agents/` that is not already a UUID is resolved against the account's agent listing, and the substitution is announced on stderr so a `--json` stdout stream stays pure. Resolution is sugar and never breaks the hatch — a reference that does not resolve (or an agent listing that cannot be reached) leaves the path exactly as typed, because `agents/` is a route prefix as well as a collection.
|
|
467
|
+
|
|
468
|
+
A path segment carrying an **elided id** (`agents/f0506e24-3740-4fe3…/addons`, copied out of a table cell too narrow to print it whole) is refused locally, before any request. The API would answer `404 Agent not found` for it, which reads as a missing agent rather than a mangled id.
|
|
469
|
+
|
|
305
470
|
```bash
|
|
306
471
|
cinna api GET agents
|
|
472
|
+
cinna api GET agents/crm-agent/addons # resolved to agents/<uuid>/addons
|
|
307
473
|
cinna api GET agents --query limit=5
|
|
308
474
|
cinna api PATCH agents/3fa85f64-5717-4562-b3fc-2c963f66afa6 --json '{"description": "updated"}'
|
|
309
475
|
cinna api POST tasks --data @task.json
|
|
@@ -400,6 +566,7 @@ It detects and fixes:
|
|
|
400
566
|
- **Orphaned sessions** — `cinna-*` sessions with no registry entry at all. Terminated.
|
|
401
567
|
- **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.
|
|
402
568
|
- **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.
|
|
569
|
+
- **cinna-cli behind the platform pin** — one report-only finding per platform whose discovery document pins a different version. An **editable install** raises none: its recorded version is a snapshot of the day it was installed, not the code that runs, so "behind the pin" would be a confident wrong answer — and one that invites missing features to be misdiagnosed as version skew.
|
|
403
570
|
- **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.
|
|
404
571
|
|
|
405
572
|
```bash
|
|
@@ -26,7 +26,11 @@ Your Editor / Claude Code
|
|
|
26
26
|
## Prerequisites
|
|
27
27
|
|
|
28
28
|
- **Python 3.10+**
|
|
29
|
-
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install)
|
|
29
|
+
- **[Mutagen](https://mutagen.io)** (version pinned by the platform — `cinna setup` checks and prompts to install; set `CINNA_MUTAGEN_BIN=/abs/path/mutagen` to use a specific binary instead of the one on PATH)
|
|
30
|
+
|
|
31
|
+
### Cinna Desktop
|
|
32
|
+
|
|
33
|
+
[Cinna Desktop](https://github.com/opencinna/cinna-desktop) installs its **own pinned copy** of cinna-cli (with `uv` and Mutagen alongside, inside its data folder) and drives it as a child process to create and keep alive an account workspace under `<AgentsHome>/Cloud/<host>/` right after you sign in — no `cinna login`, no token to paste. That private copy is not on your `PATH` unless you opt in from the desktop's settings; installing cinna-cli yourself (`uv tool install cinna-cli`) for terminal use is fine and both operate on the same workspace. The version the platform pins is reported by `cinna account status` / `cinna doctor`.
|
|
30
34
|
|
|
31
35
|
## Getting Started
|
|
32
36
|
|
|
@@ -98,7 +102,7 @@ cinna login app.example.com --dir my-cinna # always into a named sub
|
|
|
98
102
|
# ✓ Account workspace ready.
|
|
99
103
|
```
|
|
100
104
|
|
|
101
|
-
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account
|
|
105
|
+
Use it when `cinna account status` or `cinna doctor` reports the account token has expired. Because the per-agent tokens minted from an account (`cinna agent sync`) can only be re-minted while the account token is valid, the flow is: `cinna login` (refresh the account), then `cinna doctor` (re-mint the dependent sub-agent tokens). If the platform doesn't expose the device-login endpoints yet, `cinna login` says so and points you at the `cinna account set-token` paste fallback.
|
|
102
106
|
|
|
103
107
|
### `cinna account setup <token_or_url>`
|
|
104
108
|
|
|
@@ -108,7 +112,7 @@ Initialize an **account workspace** — a multi-agent root from which you can di
|
|
|
108
112
|
curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -
|
|
109
113
|
```
|
|
110
114
|
|
|
111
|
-
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates
|
|
115
|
+
Accepts the same input forms as `cinna setup` (full curl command, URL, or bare token — bare tokens need `CINNA_PLATFORM_URL`). Creates a folder named after the platform domain (override with `--dir`: an absolute path is used as is with parents created, a relative one lands under the current directory; an existing account workspace there is refused before the token is spent) containing:
|
|
112
116
|
|
|
113
117
|
```
|
|
114
118
|
my-cinna/
|
|
@@ -122,15 +126,28 @@ Setup also downloads the **context package** into `context/` — curated platfor
|
|
|
122
126
|
|
|
123
127
|
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.
|
|
124
128
|
|
|
129
|
+
`account setup`, `account set-token` and `account status` take `--no-input` (never prompt: defaults, or fail with code `needs_input`; also `CINNA_NO_INPUT=1`, accepted before or after the subcommand) and `--json` (one JSON object per line on stdout — progress `{"step","total","status","message"}` lines, then a final `{"result":"ok"|"error",…}`; implies `--no-input`). Exit codes are stable for every command: `0` ok, `10` setup token invalid/expired/used, `11` token for another account, `12` platform unreachable or 5xx, `1` anything else (the JSON `code` says what), `2` usage.
|
|
130
|
+
|
|
131
|
+
### `cinna account set-token <token_or_url>`
|
|
132
|
+
|
|
133
|
+
Refresh the **account** token in place from a fresh account setup token — the account counterpart of `cinna set-token`, and the paste alternative to `cinna login`. Run inside the account workspace; it re-exchanges under the stored machine name and rewrites only `account_token` (plus a refreshed platform/frontend URL) in `.cinna/account.json`. The active user workspace, machine name, `context/` and every synced child under `agents/` are untouched; run `cinna doctor` afterwards to re-mint expired child tokens. A token for a different account is refused (exit `11`) and nothing is written. Bare tokens reuse the stored platform URL.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd my-cinna/
|
|
137
|
+
cinna account set-token 'curl -sL https://your-platform.com/api/cli-setup/account/TOKEN | python3 -'
|
|
138
|
+
```
|
|
139
|
+
|
|
125
140
|
### `cinna account agents`
|
|
126
141
|
|
|
127
|
-
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/`.
|
|
142
|
+
List the agents your account can access (run from inside the account workspace). Ids are printed in full at any terminal width (the column folds rather than ellipsizing — a truncated UUID is a copy-paste trap that the API answers `404 not found` for). 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/`.
|
|
128
143
|
|
|
129
144
|
### `cinna account status`
|
|
130
145
|
|
|
131
146
|
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`.
|
|
132
147
|
|
|
133
|
-
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there.
|
|
148
|
+
Also reports the workspace's **context package version** against the platform's current one — the orchestrator guides ship in that tree, so a workspace set up before a guide existed silently lacks it. When it is behind, the command says so and points at `cinna account refresh-context`; `cinna improve list` prints the same nudge, since its playbook lives there. Likewise it compares the installed **cinna-cli version** with the one the platform pins (its `/.well-known/cinna-desktop` discovery document) and suggests `uv tool install cinna-cli==<pin>` when behind; no pin means "unknown", not an error. An **editable install** (`uv tool install -e`, `pip install -e`) is detected and labelled instead of compared — its metadata records the version it was installed at and never changes again, so pinning that number against the platform's would report skew that does not exist and explain missing features with a version that is not the code being run. It renders as `0.2.5 (editable checkout of /path/to/cinna-cli)`, with the pin named as context, and neither `cinna account status` nor `cinna doctor` nudges an upgrade.
|
|
149
|
+
|
|
150
|
+
With `--json` it prints a single line: `{"result":"ok","workspace",…,"token":"valid|expired|unreachable","synced_agents":N,"agents":[…],"context_package":{"local","remote","state"},"cli":{"installed","required","state"}}`.
|
|
134
151
|
|
|
135
152
|
### `cinna account refresh-context`
|
|
136
153
|
|
|
@@ -241,6 +258,150 @@ The folder rules come from the kit's versioned contract, `.cinna-kit/layout.json
|
|
|
241
258
|
|
|
242
259
|
Where the folder has been published is recorded in `publications.json`, a **sibling** of `cinna-agent.json` holding one entry per Cinna instance — it cannot live inside the manifest, because each entry records a hash of the exported tree and the manifest is part of that tree. Every step is idempotent (agent by the entry whose `platform_url` matches the instance you are logged into, credentials by name, schedules by name), so a partial import is resumed with `--update` instead of duplicating anything. The publication is recorded **only after the push settled** — `--no-push`, a failed flush, or remaining conflicts leave it unrecorded, and the next run is a plain `--update`. A legacy `cloud` block is migrated into the ledger on the first write and is still read until then, so an older folder's `--update` never creates a second agent. `--dry-run` makes no platform call and writes nothing.
|
|
243
260
|
|
|
261
|
+
### `cinna skills list <agent> [--json]`
|
|
262
|
+
|
|
263
|
+
List everything an agent carries beyond its prompt, as one deduplicated list. An **addon** is either an installed plugin or a `skills/<name>/` folder — a `SKILL.md` plus its files that the engine loads on demand. The two overlap (a skill installed from the catalog is *also* a plugin link), and the platform owns the dedupe rule, so this prints the server's projection rather than folding the halves itself: one row per addon, with its kind, source (`marketplace` / `bundle` / `catalog` / `local`), status, name and version.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
cinna skills list crm-agent
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
Agent: CRM Agent
|
|
271
|
+
Addons (3)
|
|
272
|
+
┏━━━┳━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
|
|
273
|
+
┃ # ┃ Kind ┃ Source ┃ Status ┃ Name ┃ Version ┃
|
|
274
|
+
┡━━━╇━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
|
|
275
|
+
│ 1 │ plugin │ marketplace │ ● ok │ pdf-tools (PDF Tools) │ 2.1.0 │
|
|
276
|
+
│ 2 │ skill │ catalog │ ● ok │ dad-jokes (Dad Jokes) │ 1.0.0 → 1.1.0 │
|
|
277
|
+
│ 3 │ skill │ local │ ● ok │ report · published │ 1.0.1 │
|
|
278
|
+
│ 4 │ skill │ local │ ! secrets │ draft │ │
|
|
279
|
+
└───┴────────┴─────────────┴───────────┴───────────────────────┴───────────────┘
|
|
280
|
+
1 plugin(s), 3 skill(s) (2 of them this agent's own).
|
|
281
|
+
|
|
282
|
+
! 1 installed addon(s) have a newer revision: dad-jokes
|
|
283
|
+
Update with: cinna skills update crm-agent dad-jokes
|
|
284
|
+
|
|
285
|
+
! draft (secrets): This skill holds files that look like key material.
|
|
286
|
+
.env
|
|
287
|
+
|
|
288
|
+
A blank version means no `version:` in the skill's SKILL.md — or an index built
|
|
289
|
+
before skills carried one, which fills in after the next refresh or publish.
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
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
|
+
|
|
294
|
+
### `cinna skills publish <agent> <name> [--visibility public|private|users] [--grant EMAIL ...] [--version V] [--notes TEXT] [--package-id ID] [--dry-run] [--yes] [--json]`
|
|
295
|
+
|
|
296
|
+
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).
|
|
297
|
+
|
|
298
|
+
**It publishes the agent's cloud workspace, not the folder you are standing in.** The files are read from the remote workspace on disk — which is why a *suspended* environment publishes fine, no container needs to be running — but an edit that has not synced yet is not there. Run `cinna sync push` first, or you publish the older remote copy as a revision you cannot take back.
|
|
299
|
+
|
|
300
|
+
**Without `--visibility` the package is private and nobody else sees it.** Say `--visibility public` for the catalog, or `--visibility users` with `--grant` for named people.
|
|
301
|
+
|
|
302
|
+
**The version is derived, not typed.** A skill's version is a line in its own `SKILL.md`, and the platform continues the series for you: the header's version if it has not been published yet, otherwise the next one after the newest release (the last run of digits incremented — `1.0.0`→`1.0.1`, `v3`→`v4`), or `1.0.0` for a skill nobody has versioned. The resolved version is written back into `skills/<name>/SKILL.md` on the environment before the snapshot, so the published bytes carry their own version and your next `cinna sync` brings the stamped header down. `--version` overrides it verbatim for one revision — after which the series continues from *that*. `--dry-run` prints the version, package id and revision number a publish would take, from the same code that will take them, and publishes nothing.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
cinna skills publish crm-agent report --dry-run
|
|
306
|
+
cinna skills publish crm-agent report --visibility public \
|
|
307
|
+
--notes "Adds the quarterly rollup"
|
|
308
|
+
cinna skills publish crm-agent report --visibility users \
|
|
309
|
+
--grant alice@example.com --grant bob@example.com
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
Re-publish report from CRM Agent
|
|
314
|
+
Version: 1.0.2 (header 1.0.1, latest published 1.0.1)
|
|
315
|
+
Package: com.example.skill.report
|
|
316
|
+
Revision: 3
|
|
317
|
+
Publish? [Y/n]:
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
At a terminal that preview is shown and confirmed before the press; `--yes`, `--json` and `--no-input` publish straight away. `--package-id` is optional too — omitted, it is derived as `<reversed host>.skill.<name>`, with your own publisher slug appended when that id is already taken on the instance (`--dry-run` says when that happened, since a hex tail in your own package id has no other explanation).
|
|
321
|
+
|
|
322
|
+
A re-publish appends a revision to the same package, so `--package-id` (the reverse-DNS id, e.g. `com.acme.report`) is only for a first publish — a mismatch on a later one is refused rather than silently ignored. `--visibility` is likewise honoured on a first publish and on an explicit change; omitting it leaves the package as it is. `--grant` requires `--visibility users` and the CLI refuses the combination otherwise, before anything is written. The server would accept it — it stores the grant either way — but a package that is private or public never consults its grant list, so the publish would report success and share nothing, and a revision cannot be taken back. Within a `users` package `--grant` is strictly **additive**: it adds the addresses it names and never revokes the ones it omits (revoking is `cinna skills revoke`, so a stale publish cannot silently remove access), and an unknown address fails the whole publish rather than half-sharing it. On success the package id, revision and its version, visibility and catalog URL are printed, plus a line saying the version landed in `skills/<name>/SKILL.md` — and a warning instead when it could not be written there, because the header and the catalog have then diverged and the next publish continues from the catalog. A refusal is printed as the platform's own sentence with its code (`not_developer`, `foreign_install`, `no_environment`, `workspace_unavailable`, `package_id_immutable`, `skill_contains_secrets` — which also lists the offending files), and `--json` prints `{revision, package, catalog_url, skill_md_updated}` instead of the human block (`--dry-run --json` prints the preview payload).
|
|
323
|
+
|
|
324
|
+
### `cinna skills catalog [--search Q] [--mine] [--json]`
|
|
325
|
+
|
|
326
|
+
Browse the instance skills catalog: one row per package this account may see, with its reverse-DNS **package id**, display name, visibility and newest version. The package id — `com.acme.pdf-report`, not a UUID — is the reference every other package verb takes. A delisted package is marked as such beside its visibility.
|
|
327
|
+
|
|
328
|
+
The route takes no parameters — it answers the whole visible catalogue — so `--search` (matching the id, name and description) and `--mine` (packages this account can manage) narrow the rows locally. `--json` prints the filtered rows, not the raw envelope.
|
|
329
|
+
|
|
330
|
+
### `cinna skills show <package> [--revision N] [--json]`
|
|
331
|
+
|
|
332
|
+
One package in full: its display name, visibility, newest version and package UUID, then the revision table, then the `SKILL.md` of the newest revision (or the one `--revision` names). `<package>` is a package id, a display name, or a UUID. The `SKILL.md` is printed as plain text — it is someone else's file and may contain anything — and a content fetch that fails degrades the output rather than the command, because the package detail is the answer.
|
|
333
|
+
|
|
334
|
+
### `cinna skills revisions <package> [--json]`
|
|
335
|
+
|
|
336
|
+
A package's revisions, **newest first**: number, version, release date, size and the release notes given at publish time. A revision is immutable, so this is the question a publisher has before every publish — what is already out there — and the answer to it no longer requires `cinna api` and a UUID. Pair it with `cinna skills publish <agent> <name> --dry-run`, which says what the *next* one would be.
|
|
337
|
+
|
|
338
|
+
### `cinna skills files <package> [--revision N] [--json]`
|
|
339
|
+
|
|
340
|
+
The files one revision ships, with sizes and the total. A file list the server truncated says so.
|
|
341
|
+
|
|
342
|
+
There is no `download` verb, for two reasons: installing a skill lands it in the agent's own workspace, which sync brings down to the local mirror — so the bytes already arrive that way — and the archive routes are binary, which the JSON-only escape hatch could not carry anyway.
|
|
343
|
+
|
|
344
|
+
### `cinna skills install <agent> <package> [--revision N] [--conversation-only|--building-only] [--json]`
|
|
345
|
+
|
|
346
|
+
Install a catalog package onto an agent. `<agent>` is a name, slug or id; `<package>` is a package id, display name or UUID — the CLI resolves both, so neither a raw UUID nor a hand-built JSON body is needed.
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
cinna skills catalog --search jokes
|
|
350
|
+
cinna skills install crm-agent localhost.skill.dad-jokes
|
|
351
|
+
cinna skills install crm-agent localhost.skill.dad-jokes --revision 2 --conversation-only
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Omitting `--revision` installs whatever the catalog calls latest *now*; because a revision is immutable, the install pins bytes that will not change under the agent until `cinna skills update` moves it. Both modes are on unless `--conversation-only` / `--building-only` narrows where the skill is offered (naming both is refused — it would install a skill offered nowhere).
|
|
355
|
+
|
|
356
|
+
Installing something the agent already carries is answered as a sentence, not a JSON body: the platform's own `already_installed` refusal followed by either "already at the newest revision" or the `cinna skills update` that closes the gap. The `--json` error code stays `already_installed`.
|
|
357
|
+
|
|
358
|
+
### `cinna skills update <agent> <name> [--json]`
|
|
359
|
+
|
|
360
|
+
Move an installed skill to the package's newest revision, printing the version it moved from and to. `<name>` is the name `cinna skills list` prints; the plugin-link id the route actually addresses is resolved internally. The listing's `has_update` is *reported*, never used to skip the call — it comes from a cache, and the upgrade route is what decides.
|
|
361
|
+
|
|
362
|
+
Every install / uninstall / update / toggle also pushes the change into the agent's running environments, and that push can partly fail while the call itself succeeds. When it does, the command says how many environments did not take it and points at `cinna agent restart-env` — a green check alone would hide the one case where the catalog and the live agent disagree. An environment built *before* the feature existed is reported separately (`unsupported_syncs`): the link write is complete and there is nothing to retry, so that half points at `cinna agent rebuild-env` and suppresses the plain success line rather than offering a restart that cannot change the outcome.
|
|
363
|
+
|
|
364
|
+
### `cinna skills uninstall <agent> <name> [--yes] [--json]`
|
|
365
|
+
|
|
366
|
+
Remove an agent's copy of an installed skill. The package and its revisions are untouched — what the agent held was a copy, not a reference. Asks first unless `--yes`. An agent's *own* `skills/<name>/` folder is not an install, and the command says so rather than failing on a route that could never match it.
|
|
367
|
+
|
|
368
|
+
### `cinna skills toggle <agent> <name> [--enable|--disable] [--conversation-mode|--no-conversation-mode] [--building-mode|--no-building-mode] [--json]`
|
|
369
|
+
|
|
370
|
+
Enable or disable an installed skill, or change where it is offered, without removing it. Every switch defaults to "leave it alone" and only the ones named are sent, so `--disable` cannot silently reset the mode flags a previous call set. Naming no switch at all is a usage error rather than a no-op call. A disabled install still lists and still reports its version — it is not an error — so `cinna skills list` marks it `· disabled`.
|
|
371
|
+
|
|
372
|
+
### `cinna skills refresh <agent> [--json]`
|
|
373
|
+
|
|
374
|
+
Rebuild the agent's addon index, reporting how many skills were indexed. Everything else in this group reads the platform's cache — which is what makes it safe against a sleeping environment, and what makes a stale index possible. This is the remedy when `cinna skills list` reports `parse_error`, or shows no version for a skill whose `SKILL.md` has one. It is *not* the remedy for every reason code — see below. The plugin half is refreshed too where the platform offers that route; a platform without it still refreshes the skill half and says so.
|
|
375
|
+
|
|
376
|
+
A refresh that still could not read the index answers **200 with the reason** — so this prints the reason and the remedy *that reason* has, rather than a green check. The four codes do not share a fix, and both `skills refresh` and `skills list` route through the same table:
|
|
377
|
+
|
|
378
|
+
| Code | What it means | The fix it prints |
|
|
379
|
+
|---|---|---|
|
|
380
|
+
| `env_not_running` | The environment is asleep | Send it a message, or refresh again, to wake it |
|
|
381
|
+
| `adapter_error` | Up, but not answering | `cinna agent restart-env <agent>` |
|
|
382
|
+
| `adapter_unsupported` | Built before agent skills existed; no skills endpoint to answer | `cinna agent rebuild-env <agent>` |
|
|
383
|
+
| `parse_error` | Answered, but the index did not parse | `cinna skills refresh <agent>` |
|
|
384
|
+
|
|
385
|
+
An unrecognised code gets a generic "refresh again, then check the logs" and names **no** verb: a code whose fix this build cannot name is one where guessing a verb sends the caller round a loop that cannot close. That is exactly what the old copy did to `adapter_unsupported` — it printed one hardcoded remedy for every code, so a container missing the route was told to restart (which re-runs the same image) or, in `skills list`, to "Rebuild it with: cinna skills refresh" (which re-reads a route that is not there, and calls a refresh a rebuild).
|
|
386
|
+
|
|
387
|
+
### `cinna skills grants <package> [--json]` · `grant <package> --user EMAIL` · `revoke <package> --user EMAIL [--yes]`
|
|
388
|
+
|
|
389
|
+
Who is named on a package, and adding or removing one. Visibility and grants belong to the *package*, not to a revision, so changing them costs no new revision — this is the post-publish half of `cinna skills publish --grant`.
|
|
390
|
+
|
|
391
|
+
A grant list is stored on any package but only *consulted* on one whose visibility is `users`, so `grants` prints the visibility beside the rows and both verbs warn when the list is being ignored. `revoke` takes the same email `grant` did and resolves it to the user id the route actually addresses; an address that was never granted is a sentence naming who actually is.
|
|
392
|
+
|
|
393
|
+
### `cinna skills visibility <package> <public|private|users> [--json]`
|
|
394
|
+
|
|
395
|
+
Change who may see a package after it was published. Switching to `users` with nobody named warns that it shares the package with nobody — the one setting that looks like sharing and is not.
|
|
396
|
+
|
|
397
|
+
### `cinna skills delist <package> [--yes] [--json]`
|
|
398
|
+
|
|
399
|
+
Take a package out of the catalog. Agents that already installed it keep what they have: a revision they hold is a copy, not a reference. Asks first unless `--yes`. Deleting a package outright is still web-UI only.
|
|
400
|
+
|
|
401
|
+
### `cinna skills relist <package> [--json]`
|
|
402
|
+
|
|
403
|
+
Put a delisted package back. `delist` has no inverse route of its own — without this verb the only way back would be `cinna api`, which would make delisting the one door in this group that opens only outwards.
|
|
404
|
+
|
|
244
405
|
### `cinna connect agent-api --producer <agent> --consumer <agent> [--label TEXT] [--read-only]`
|
|
245
406
|
|
|
246
407
|
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.
|
|
@@ -265,8 +426,13 @@ Generic escape hatch into the platform API, authenticated with the account token
|
|
|
265
426
|
- 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.
|
|
266
427
|
- 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).
|
|
267
428
|
|
|
429
|
+
`<path>` accepts the same **agent references** the rest of the CLI does: a segment straight after `agents/` that is not already a UUID is resolved against the account's agent listing, and the substitution is announced on stderr so a `--json` stdout stream stays pure. Resolution is sugar and never breaks the hatch — a reference that does not resolve (or an agent listing that cannot be reached) leaves the path exactly as typed, because `agents/` is a route prefix as well as a collection.
|
|
430
|
+
|
|
431
|
+
A path segment carrying an **elided id** (`agents/f0506e24-3740-4fe3…/addons`, copied out of a table cell too narrow to print it whole) is refused locally, before any request. The API would answer `404 Agent not found` for it, which reads as a missing agent rather than a mangled id.
|
|
432
|
+
|
|
268
433
|
```bash
|
|
269
434
|
cinna api GET agents
|
|
435
|
+
cinna api GET agents/crm-agent/addons # resolved to agents/<uuid>/addons
|
|
270
436
|
cinna api GET agents --query limit=5
|
|
271
437
|
cinna api PATCH agents/3fa85f64-5717-4562-b3fc-2c963f66afa6 --json '{"description": "updated"}'
|
|
272
438
|
cinna api POST tasks --data @task.json
|
|
@@ -363,6 +529,7 @@ It detects and fixes:
|
|
|
363
529
|
- **Orphaned sessions** — `cinna-*` sessions with no registry entry at all. Terminated.
|
|
364
530
|
- **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.
|
|
365
531
|
- **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.
|
|
532
|
+
- **cinna-cli behind the platform pin** — one report-only finding per platform whose discovery document pins a different version. An **editable install** raises none: its recorded version is a snapshot of the day it was installed, not the code that runs, so "behind the pin" would be a confident wrong answer — and one that invites missing features to be misdiagnosed as version skew.
|
|
366
533
|
- **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.
|
|
367
534
|
|
|
368
535
|
```bash
|
|
@@ -137,6 +137,7 @@ Key properties:
|
|
|
137
137
|
A second token type (`token_type="cli-account"`) issued to an **account workspace** (`.cinna/account.json`). Scoped only to the `/account/*` routes — it discovers agents and mints per-agent CLI tokens (`cinna agent sync`), but cannot itself sync or exec. Same 7-day rolling expiry as a CLI token.
|
|
138
138
|
|
|
139
139
|
- **Refreshable without a paste** — `cinna login` runs an RFC 8628 device-authorization flow: the CLI prints a short code + URL, the user clicks **Authorize** in the browser (already signed in), and the CLI swaps the fresh token into `.cinna/account.json` in place. Run from an empty/new folder, the same command instead bootstraps a brand-new account workspace.
|
|
140
|
+
- **Refreshable from a setup token** — `cinna account set-token <token_or_url>` re-exchanges a fresh *account* setup token under the stored machine name and rewrites only `account_token` (same in-place swap). Bound to the same account: a different platform origin or token subject aborts with exit `11`. This is the path Cinna Desktop drives (`--no-input --json`) so the user never runs `cinna login`.
|
|
140
141
|
- **Mints child tokens** — per-agent tokens minted from it carry its id as provenance and are re-mintable via `POST /account/agents/{id}/mint` (used by `cinna agent sync` and `cinna doctor`).
|
|
141
142
|
|
|
142
143
|
### Knowledge Source
|
|
@@ -208,16 +209,17 @@ main.py (CLI commands — Click)
|
|
|
208
209
|
├── config.py — .cinna/config.json: load/save/find
|
|
209
210
|
├── auth.py — JWT storage, Authorization headers
|
|
210
211
|
├── client.py — PlatformClient: HTTP + SSE stream_exec
|
|
211
|
-
├── mutagen_runtime.py — detect/install Mutagen; gate on version match
|
|
212
|
+
├── mutagen_runtime.py — detect/install Mutagen; gate on version match; `CINNA_MUTAGEN_BIN` override
|
|
213
|
+
├── cli_version.py — installed vs platform-pinned cinna-cli version
|
|
212
214
|
├── sync_session.py — wrap the `mutagen` CLI (start/stop/status/conflicts)
|
|
213
215
|
├── sync_tui.py — live Textual TUI shown by `cinna dev` (Sync/Details/Conflicts tabs)
|
|
214
216
|
├── sync_ssh_shim.py — `cinna-sync-ssh` entry point (WebSocket transport)
|
|
215
217
|
├── sync.py — tarball/zip extraction helpers (initial clone only)
|
|
216
218
|
├── context.py — CLAUDE.md, BUILDING_AGENT.md, .mcp.json, opencode.json
|
|
217
219
|
├── mcp_proxy.py — MCP stdio server for knowledge_query
|
|
218
|
-
├── console.py — Rich helpers
|
|
220
|
+
├── console.py — Rich helpers + the `--json` / `--no-input` switches (prompt/confirm wrappers, JSON lines)
|
|
219
221
|
├── logging.py — cinna.log (rotating file handler)
|
|
220
|
-
└── errors.py — exception hierarchy
|
|
222
|
+
└── errors.py — exception hierarchy; `CinnaExit` = stable exit code + machine code
|
|
221
223
|
```
|
|
222
224
|
|
|
223
225
|
### Local Directory Layout
|
|
@@ -282,14 +284,15 @@ authoring convention.
|
|
|
282
284
|
|
|
283
285
|
| Feature | Command surface | Docs |
|
|
284
286
|
|---|---|---|
|
|
285
|
-
| **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) |
|
|
286
|
-
| **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) |
|
|
287
|
-
| **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) |
|
|
287
|
+
| **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) |
|
|
288
290
|
| **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) |
|
|
289
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) |
|
|
290
292
|
| **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) |
|
|
291
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) |
|
|
292
294
|
| **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) |
|
|
293
296
|
| **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) |
|
|
294
297
|
| **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) |
|
|
295
298
|
| **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) |
|
|
@@ -605,6 +608,8 @@ When a CLI token expires (or is revoked) the normal remedy is `cinna set-token <
|
|
|
605
608
|
| Method | Route | Auth | Purpose |
|
|
606
609
|
|--------|-------|------|---------|
|
|
607
610
|
| POST | `/api/cli-setup/{token}` | Token | Exchange setup token for CLI token |
|
|
611
|
+
| POST | `/api/cli-setup/account/{token}` | Token | Exchange an **account** setup token (`cinna account setup` / `cinna account set-token`); 4xx ⇒ exit 10, 5xx ⇒ exit 12 |
|
|
612
|
+
| GET | `/.well-known/cinna-desktop` | None | Desktop discovery document; `local_dev.cinna_cli_version` is the cinna-cli pin `cinna account status` / `cinna doctor` compare against (absent ⇒ "unknown") |
|
|
608
613
|
| GET | `/api/v1/cli/agents/{id}/workspace` | CLI JWT | One-shot tarball for initial clone |
|
|
609
614
|
| GET | `/api/v1/cli/agents/{id}/building-context` | CLI JWT | Assembled building prompt |
|
|
610
615
|
| POST | `/api/v1/cli/agents/{id}/knowledge/search` | CLI JWT | Knowledge base search (via MCP proxy) |
|
|
@@ -645,6 +650,8 @@ uv run ruff format --check src/
|
|
|
645
650
|
|
|
646
651
|
The CLI is published to [PyPI](https://pypi.org/project/cinna-cli/) by `.github/workflows/publish.yml`, which runs on any pushed tag matching `v*` (and via manual `workflow_dispatch`). It builds the sdist + wheel with `uv build`, runs `twine check`, then publishes through PyPI **Trusted Publishing** (OIDC — no stored API token) from the GitHub `pypi` environment.
|
|
647
652
|
|
|
653
|
+
Cinna Desktop installs a **pinned** version (`uv tool install cinna-cli==<version>`) — the version each cinna-core instance advertises as `local_dev.cinna_cli_version` in its discovery document (`CINNA_CLI_VERSION` setting). A release that changes the driver contract (exit codes, `--json` shapes, the three desktop-driven verbs) must be published to PyPI **before** cinna-core's pin moves to it.
|
|
654
|
+
|
|
648
655
|
### Cutting a release
|
|
649
656
|
|
|
650
657
|
Versioning is SemVer (`MAJOR.MINOR.PATCH`); a patch release is the common case. From a clean `main` with the changes you want to ship already merged:
|