octwin-cli 0.3.0 → 0.6.0

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,72 @@ Format: [Keep a Changelog](https://keepachangelog.com/) — newest first, bucket
5
5
  **Added · Changed · Deprecated · Removed · Fixed · Security**. The platform-wide view lives in the
6
6
  repo root [`CHANGELOG.md`](../../CHANGELOG.md); this file is the CLI-only cut that ships with the package.
7
7
 
8
+ ## [0.6.0] - 2026-08-09
9
+
10
+ ### Changed
11
+ - **`octwin cases` is now `octwin work`, and it works again.** The platform's work-inbox
12
+ consolidation (2026-08-08) replaced the case-only surface with `/work` over every entity a pack
13
+ declares worked, and renamed the scopes to `work:read`/`work:write` — which left every `octwin
14
+ cases` call a silent 404 in a published CLI. The command family is renamed to match the platform:
15
+ `octwin work [recordId] [--queues]`, with writes `assign` / `note` / `decide` (the declared
16
+ operator actions, `--dry-run` previews) and `stage <id> --to <s>` riding the one platform-wide
17
+ stage verb (`POST …/xrm/records/:id/stage`, needs `records:write`). `transition` is gone with the
18
+ route it called.
19
+ - **`octwin orders transition` rides the same stage verb.** `POST …/orders/:ref/transition` was
20
+ retired server-side in the same consolidation; the CLI now resolves the order's record id from the
21
+ detail read and moves the stage through `…/xrm/records/:id/stage` (scope: `records:write`).
22
+
23
+ ### Added
24
+ - **A route guard so this cannot rot silently again**: `src/lib/cli-routes.test.ts` extracts every
25
+ `/api/self/**` URL the CLI builds and asserts it (method included) against the platform's dumped
26
+ route table — the gap that let both breakages above ship.
27
+
28
+ ## [0.5.1] - 2026-08-01
29
+
30
+ ### Fixed
31
+ - **`validate --remote` blamed the platform's version for a bad `--project`.** Every 404 from
32
+ `POST /api/self/p/packs/validate` printed *"this platform has no /packs/validate endpoint yet
33
+ (older version)"*. That was accurate when the route resolved nothing, but it now resolves the
34
+ tenant and project **before** validating — and an unknown project, or one outside a token's pin,
35
+ answers 404 by design. So a typo in `--project` sent you looking for a version mismatch instead of
36
+ at the flag. The two cases are now told apart by the response **body**, not the status: a missing
37
+ route is Fastify's `error: 'Not Found'` and keeps the old wording, while the platform's own
38
+ `project '<slug>' not found under tenant` is printed as-is, with the flags to check.
39
+
40
+ ## [0.5.0] - 2026-08-01
41
+
42
+ ### Added
43
+ - **`octwin seed [--pack <packId>]`** — apply the pack's demo/reference data to the project it is
44
+ installed on, without redeploying: `xrm.yaml` `demo:` records + scheduling availability, the
45
+ commerce catalog, and the demo operator topology. Reports what **each kind** produced.
46
+ Previously seeding was reachable only as `deploy --seed`, because the platform's seed endpoint was
47
+ keyed on an install id, guarded platform-admin, and carried no tenant/project segments — so the
48
+ `/api/self/**` surface could not reach it and a `pack:deploy` token never could. Re-seeding meant
49
+ a full redeploy or asking an operator. Idempotent and cheap to re-run: records upsert, and
50
+ existing media is REUSED rather than regenerated, so a second pass reports zero images.
51
+
52
+ ## [0.4.0] - 2026-08-01
53
+
54
+ ### Added
55
+ - **`octwin projects create` / `octwin projects rm`** — a **disposable end-to-end environment** from
56
+ the CLI, which is what marketplace developers have been missing. `octwin deploy` has always needed
57
+ a project that already existed and the CLI could only *list* them, so standing up a throwaway
58
+ full deployment meant opening the console or asking an operator. Now:
59
+ ```bash
60
+ octwin projects create "Scratch" # → slug `scratch`
61
+ octwin deploy --project scratch --seed # publish + install + demo data
62
+ octwin chat "hi" --project scratch # talk to it (--script for a whole conversation)
63
+ octwin projects rm scratch --yes # throw it away
64
+ ```
65
+ A throwaway environment is deliberately **not a special kind of thing** — it is an ordinary
66
+ project in your own workspace, so it inherits your plan, entitlements, RBAC and teardown with no
67
+ separate lifecycle. `create` derives the URL slug from the name (`--slug` pins one, `--pack`
68
+ installs an already-published pack). `rm` is a HARD delete — the project and everything cascading
69
+ from it, no undo, not the same as archiving — so **without `--yes` it only prints what would be
70
+ destroyed**, making the dry run the default; the impact list is derived from `pg_constraint`, the
71
+ same payload the console's confirm dialog renders. Both need `projects:write`, which a
72
+ `pack:deploy` token does **not** confer — the CLI names that scope in the 403 hint.
73
+
8
74
  ## [0.3.0] - 2026-07-31
9
75
 
10
76
  ### Added
@@ -191,7 +257,7 @@ repo root [`CHANGELOG.md`](../../CHANGELOG.md); this file is the CLI-only cut th
191
257
  **flags → env (`PACK_PLATFORM_URL`/`PACK_TENANT`/`PACK_PROJECT`/`PACK_TOKEN`) → saved login**.
192
258
  An existing credentials file simply has no `default_url` until the next `octwin login` — which is
193
259
  exactly what the "no platform url" error now tells you to run. CI is unaffected (it passes
194
- `PACK_PLATFORM_URL` + `PACK_TOKEN` as env and never had a `pack.json`).
260
+ `PACK_PLATFORM_URL` + `PACK_TOKEN` as env and never had a `pack.json` — that file is retired).
195
261
 
196
262
  ## [0.1.17] - 2026-07-27
197
263
 
package/README.md CHANGED
@@ -1,210 +1,214 @@
1
- # octwin-cli
2
-
3
- > The **Octwin** external-pack developer CLI — scaffold, validate, deploy, and manage pure-YAML packs on your own tenant. By **CEQUENS**.
4
-
5
- [![npm version](https://img.shields.io/npm/v/octwin-cli.svg)](https://www.npmjs.com/package/octwin-cli)
6
- [![license](https://img.shields.io/npm/l/octwin-cli.svg)](https://www.npmjs.com/package/octwin-cli)
7
- [![node](https://img.shields.io/node/v/octwin-cli.svg)](https://nodejs.org)
8
-
9
- Octwin is a pack-pluggable conversational-agent platform for WhatsApp and web. A **pack** is a
10
- self-contained bot domain — its agent, conversation flows, prompts, and data model — declared
11
- entirely in YAML. `octwin-cli` lets you build a **pure-YAML pack** in your own repo and deploy it
12
- to a running Octwin platform to test live on your own tenant: no platform checkout, no build step,
13
- and nothing untrusted to run (a pure-YAML pack is declarative data, so the platform can safely run
14
- it alongside other tenants).
15
-
16
- > The npm package is **`octwin-cli`**; the command it installs is **`octwin`**.
17
-
18
- ## Requirements
19
-
20
- - **Node.js ≥ 20**
21
- - Access to an **Octwin platform** (its base URL), a **tenant** (your workspace) on it, and a
22
- **deploy token** (generated in the Octwin console — see [Authentication](#authentication)).
23
-
24
- ## Install
25
-
26
- ```bash
27
- # zero-install — always the latest version
28
- npx octwin-cli@latest <command>
29
-
30
- # …or install the `octwin` command globally
31
- npm install -g octwin-cli
32
- octwin <command>
33
- ```
34
-
35
- ## Quick start
36
-
37
- ```bash
38
- # 1. Scaffold a standalone pure-YAML pack (this is your repo)
39
- octwin init ./my-pack --id my-pack --description "My business bot"
40
- cd ./my-pack
41
- git init && git add -A && git commit -m "init pack"
42
-
43
- # 2. Author it — edit manifest.yaml, flows/tools/main.flow.yaml (+ its locale),
44
- # and prompts/identity.md. Everything is pure YAML.
45
-
46
- # 3. Point it at your platform one command, no config file
47
- # (Octwin console your workspace → API tokens → Generate)
48
- octwin login --url https://your-octwin.example.com --token oct_…
49
-
50
- # 4. Validate deployconfirm it's live
51
- octwin validate
52
- octwin deploy --seed # --seed also loads any demo data the pack declares
53
- octwin status # "✓ live and current" once it's warm
54
-
55
- # 5. Chat with it on your tenant (web widget / console test page). Edit and
56
- # `octwin deploy` again a redeploy hot-loads with no restart.
57
- ```
58
-
59
- ## Commands
60
-
61
- | Command | What it does |
62
- | --- | --- |
63
- | `octwin init <dir>` | Scaffold a new pure-YAML pack into `<dir>` (writes a starter `manifest.yaml`, flow, prompt, `.gitignore` and `README.md` — pack content only). Options: `--id`, `--description`, `--display-name`. |
64
- | `octwin validate` | Check the pack locally (structure + pure-YAML rules). `--remote` additionally runs the platform's **flow lint** — conventions the schema can't express, like an `assign:` whose value is a quoted literal, or a `$t()` key with no namespace. The lint needs a template-expanded `FlowDef`, which only the server builds, so it is a `--remote`-only check; a local ✓ does not cover it. |
65
- | `octwin login` | Save a deploy token for a platform URL **and make that URL the default target** (both stored in `~/.octwin/credentials.json`). `--url`, `--token`. |
66
- | `octwin whoami` | Verify the saved/passed token is valid for a tenant. `--url`, `--tenant`. |
67
- | `octwin deploy` | Upload + install the pack onto your tenant's project. `--seed` also runs the pack's demo seed. Reports the **marketplace-listing verdict** when the manifest carries `listing.public: true`. |
68
- | `octwin status` | Report what the platform has live for this pack installed version, the **content sha** the instance loaded vs. the one the catalog holds (a redeploy of the *same* version changes it), its flows, and whether it is live on the public marketplace. |
69
- | `octwin pull <packId>` | Write a **deployed** pack's source back to disk — the inverse of `deploy`, and how a pack pushed from one machine is recovered. Defaults to the version installed on the target project; `--version` overrides, `--dir` defaults to `./<packId>`, a non-empty dir needs `--force`. You may pull a pack your tenant **owns**. |
70
- | `octwin chat "msg"` | Drive a turn through the dev web channel and print **every render with its tap ids**. `--as <handle>` picks the test user; `--tap "<tap-id>"` presses a rendered button/list row; `--json` dumps the raw envelopes. |
71
- | `octwin logs` | List recent conversations (handle, status, last activity; `--as` filters), or show one conversation's full event timeline including what each turn rendered. `--json` for raw payloads. |
72
- | `octwin records` | Inspect the pack's XRM data (needs a `records:read` token). No args = list entities. |
73
- | `octwin cases` | Inspect casework (support tickets): the inbox, one case + its timeline and decisions, or `--queues` for queue keys + open counts. |
74
- | `octwin projects` | The `--project <slug>` values this token can name, with the plan's project cap. `--archived` includes archived ones. A `pack:deploy` token reaches itit names a project in every other command, so this turns "guess the slug" into "read the list". |
75
- | `octwin agents` | The agent roster with each agent's **effective** model / history window and **which layer set it** (project override platform default → pack manifest) — an operator platform default can override what your manifest declares. `--prompt` prints the exact system prompt the LLM sees. Needs `agents:read`. |
76
- | `octwin orders` | The orders a conversation produced. No args = the list; with a `reference_id` = line items, the subtotal/tax/shipping/discount/total breakdown, `payment_ref`, and the allowed transitions. Needs `orders:read` + the `orders` plan feature. |
77
- | `octwin analytics` | Stage-by-stage conversion for **any** entity declared with a `pipeline:` (`--overview` / `--milestones` / `--trends` / `--cost`; `--stage <id>` lists the records currently at a stage). Needs `records:read`. |
78
- | `octwin catalog` | Commerce products with price / availability / stock, plus the WhatsApp catalog binding. `--readiness` runs the Meta Graph checklist. Needs `catalog:read` + the `catalog` plan feature. |
79
- | `octwin scheduling` | The scheduling engine's state, or `--slots <resourceRecordId>` for the slots one bookable resource actually computes how you verify the availability rules `deploy --seed` created. Needs `scheduling:read`. |
80
- | `octwin media generate "<prompt>"` | AI-generate an image, store it as a public asset, and print its `MEDIA-` handle + serve URL. `--out` downloads the bytes (WhatsApp renders only `.png`/`.jpg`); `--size`; `--json`. Pairs with `octwin chat --media` to drive media-collect flows. Needs `media:generate`. |
81
- | `octwin platform-kb pull` | Pull the platform's capability reference into `.octwin/platform-kb/` for the **`octwin-pack`** Claude Code authoring plugin: guides as markdown, plus **one JSON file per capability** (`primitives/record_list.json`, `render-intents/carousel.json`, `declarations/xrm.json`, …) and an **`INDEX.md`** mapping every entry to its file — so a lookup is a small targeted read, not a whole catalog. |
82
- | `octwin test` | Alias for `octwin validate --remote` — the platform's full manifest + flow-DSL check. |
83
- | `octwin feedback` | Submit this pack's `FEEDBACK.md` to the platform team, with the pack version, your CLI version and the `content_hash` of the capability reference you pulled the two facts that separate a real platform gap from something already fixed or a stale KB. |
84
- | `octwin help` | Show usage. Every subcommand also answers `--help`. |
85
-
86
- ### Writing, not just reading
87
-
88
- Every read command above has a write half behind a **leading verb**, so `octwin cases` reads and
89
- `octwin cases note <id> "…"` writes. Each needs the matching `:write` scope — `octwin <cmd> --help`
90
- lists the verbs and their exact flags.
91
-
92
- | Command | Verbs |
93
- | --- | --- |
94
- | `octwin records` | `create <entity> --set k=v` · `patch <id> --entity <e>` · `stage <id> --to <s>` · `note <id> "…"` · `tasks` · `task complete <id>` |
95
- | `octwin cases` | `assign <id> --to user:<uuid>\|none` · `note` · `transition <id> --to <status>` · `decide <id> --action <a> [--dry-run]` |
96
- | `octwin orders` | `transition <ref> --to <status>` · `refund <ref> --force` |
97
- | `octwin catalog` | `availability <sku> --to "in stock"` · `stock <sku> [--set-on-hand n]` |
98
- | `octwin scheduling` | `rules --resource <id>` · `rule add\|rm` · `exception add\|rm` |
99
- | `octwin agents` | `set <ref> [--model m] [--enable-tool t] [--disable-tool t]` |
100
-
101
- `--set k=v` coerces JSON scalars (`--set rating=4.5` sends a number); `--fields-json` takes anything
102
- nested. Destructive verbs want `--force` rather than a prompt the CLI is non-interactive by
103
- design. `cases decide --dry-run` previews the customer-facing copy and the resulting status without
104
- committing, and needs only `cases:read`.
105
-
106
- Every command that talks to the platform accepts `--dir <path>` (the pack directory; defaults to
107
- the current directory) plus the target overrides `--url` / `--tenant` / `--project` / `--token`.
108
-
109
- ### Debugging a live conversation
110
-
111
- The platform keeps **one open conversation per `--as` handle**, so consecutive `octwin chat` calls
112
- with the same handle **continue the same conversation** — agent memory, suspended flows, and all:
113
-
114
- ```bash
115
- octwin chat "hi" --as tester1 # turn 1prints the menu with each row's tap id
116
- octwin chat --tap "t:invoke:my-flow:x=1" --as tester1 # turn 2 — press a rendered row
117
- octwin chat "3 bedrooms" --as tester1 # turn 3 — free text into the running flow
118
- octwin logs --as tester1 # find the conversation, then:
119
- octwin logs <conversationId> # the full timeline (taps, renders, tool events)
120
- ```
121
-
122
- ### Reading back the state your pack created
123
-
124
- `chat`/`logs` show what the bot *said*; these show what it *did*. A 401/403 on any of them names the
125
- token scope (and plan feature) that command needs, so you can mint a wider token instead of guessing.
126
-
127
- ```bash
128
- octwin agents # effective model per agent + which layer set it
129
- octwin agents my-pack::assistant --prompt # the exact system prompt the LLM sees
130
- octwin orders # then: octwin orders <reference_id>
131
- octwin analytics # then: octwin analytics <entity> [--stage <id>]
132
- octwin catalog # products + stock + the WhatsApp binding
133
- octwin scheduling --slots <resourceRecordId> # the slots your availability rules compute
134
- ```
135
-
136
- Three things worth knowing when you read the output:
137
-
138
- - **A `pending` payment is usually correct.** The forward payment lifecycle is **webhook-owned**, and a
139
- workspace with no gateway runs the credential-free `manual` driver — so `payment_request` takes its
140
- `empty` port and your flow should confirm pay-on-delivery. `octwin orders <ref>` says this inline.
141
- - **Your declared model may not be the one running.** An operator platform default overrides the pack
142
- manifest; `octwin agents` is where that becomes visible.
143
- - **An empty funnel has two causes** the entity has no `pipeline:`, or your token's role has no `view`
144
- grant on `record.<entity>`. The command prints both rather than a bare "no data".
145
-
146
- ## Configuration
147
-
148
- **`octwin login` is the configuration.** There is no config file in your pack — a pack directory
149
- holds pack content and nothing else, so the same repo deploys from any machine:
150
-
151
- ```bash
152
- octwin login --url https://your-octwin.example.com --token oct_…
153
- ```
154
-
155
- That stores the token *and* makes the URL your default target, in `~/.octwin/credentials.json`:
156
-
157
- ```jsonc
158
- {
159
- "default_url": "https://your-octwin.example.com", // set by the last `octwin login`
160
- "https://your-octwin.example.com": "oct_…" // token, keyed by platform url
161
- }
162
- ```
163
-
164
- Tenant and project need no setting at all — the **token carries its own tenant**, plus an optional
165
- project pin. `--tenant` / `--project` exist only as overrides (a multi-workspace human, or an
166
- unpinned token that must name a project).
167
-
168
- Each setting resolves **flag environment variable saved login**:
169
-
170
- | Setting | Flag | Env var | Saved login |
171
- | --- | --- | --- | --- |
172
- | Platform URL | `--url` | `PACK_PLATFORM_URL` | `default_url` |
173
- | Deploy token | `--token` | `PACK_TOKEN` | token for that URL |
174
- | Tenant slug *(override)* | `--tenant` | `PACK_TENANT` | *(from the token)* |
175
- | Project slug *(override)* | `--project` | `PACK_PROJECT` | *(from the token's pin)* |
176
-
177
- For **CI**, skip `login` entirely and pass `PACK_PLATFORM_URL` + `PACK_TOKEN` as environment
178
- variables (add `PACK_PROJECT` only if the token isn't pinned).
179
-
180
- ## Authentication
181
-
182
- You authenticate with a tenant-scoped **deploy token** (prefixed `oct_…`) — not a password and not
183
- an operator token. Generate it in the Octwin console (**your workspace → API tokens → Generate**).
184
- It is **least-privilege** (scope `pack:deploy`): it can deploy packs to your tenant but cannot
185
- manage members, billing, or other tenants, and it is revocable at any time.
186
-
187
- Add the optional **`media:generate`** scope to let a `--seed` deploy AI-generate seed images
188
- (for a demo record field like `photo: "generate:<prompt>"`); without it, such fields are seeded as
189
- text only.
190
-
191
- ## What a pack may contain
192
-
193
- A pack is **pure declarative data** — `.yaml` / `.yml` / `.md` / `.sql` / `.json` only. Executable
194
- code (`.ts`/`.js`), HTTP routes, DB clients, and custom primitives are **not** allowed (this is what
195
- makes an external pack safe to run on a shared platform; the server enforces it on deploy). For
196
- domain records, use Octwin's first-class storage modules **XRM** (records with stage pipelines),
197
- **catalog** (products), or **casework** (tickets) declared in `xrm.yaml` and `worklist.yaml`, so a
198
- pack needs **no database of its own**. (Casework rides `worklist.yaml`'s `work.<entity>` block;
199
- there is no ~~`cases.yaml`~~ grammar. `octwin platform-kb pull` ships the authoritative list of
200
- declaration files read its `INDEX.md` rather than this paragraph.)
201
-
202
- ## Links
203
-
204
- - **npm:** <https://www.npmjs.com/package/octwin-cli>
205
- - **Command help:** `octwin help` (each subcommand also answers `--help`)
206
- - **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
207
-
208
- ## License
209
-
210
- [MIT](./LICENSE) © CEQUENS
1
+ # octwin-cli
2
+
3
+ > The **Octwin** external-pack developer CLI — scaffold, validate, deploy, and manage pure-YAML packs on your own tenant. By **CEQUENS**.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/octwin-cli.svg)](https://www.npmjs.com/package/octwin-cli)
6
+ [![license](https://img.shields.io/npm/l/octwin-cli.svg)](https://www.npmjs.com/package/octwin-cli)
7
+ [![node](https://img.shields.io/node/v/octwin-cli.svg)](https://nodejs.org)
8
+
9
+ Octwin is a pack-pluggable conversational-agent platform for WhatsApp and web. A **pack** is a
10
+ self-contained bot domain — its agent, conversation flows, prompts, and data model — declared
11
+ entirely in YAML. `octwin-cli` lets you build a **pure-YAML pack** in your own repo and deploy it
12
+ to a running Octwin platform to test live on your own tenant: no platform checkout, no build step,
13
+ and nothing untrusted to run (a pure-YAML pack is declarative data, so the platform can safely run
14
+ it alongside other tenants).
15
+
16
+ > The npm package is **`octwin-cli`**; the command it installs is **`octwin`**.
17
+
18
+ ## Requirements
19
+
20
+ - **Node.js ≥ 20**
21
+ - Access to an **Octwin platform** (its base URL), a **tenant** (your workspace) on it, and a
22
+ **deploy token** (generated in the Octwin console — see [Authentication](#authentication)).
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ # zero-install — always the latest version
28
+ npx octwin-cli@latest <command>
29
+
30
+ # …or install the `octwin` command globally
31
+ npm install -g octwin-cli
32
+ octwin <command>
33
+ ```
34
+
35
+ ## Quick start
36
+
37
+ ```bash
38
+ # 1. Scaffold a standalone pure-YAML pack (this is your repo)
39
+ # `--id` is a BARE name the platform prefixes your workspace at deploy, so
40
+ # `my-pack` published by `acme` becomes `acme.my-pack` in the catalog. Take the
41
+ # obvious name; ids only collide within a workspace.
42
+ octwin init ./my-pack --id my-pack --description "My business bot"
43
+ cd ./my-pack
44
+ git init && git add -A && git commit -m "init pack"
45
+
46
+ # 2. Author it — edit manifest.yaml, flows/tools/main.flow.yaml (+ its locale),
47
+ # and prompts/identity.md. Everything is pure YAML.
48
+
49
+ # 3. Point it at your platform — one command, no config file
50
+ # (Octwin consoleyour workspace API tokens → Generate)
51
+ octwin login --url https://your-octwin.example.com --token oct_…
52
+
53
+ # 4. Validate deploy confirm it's live
54
+ octwin validate
55
+ octwin deploy --seed # --seed also loads any demo data the pack declares
56
+ octwin status # "✓ live and current" once it's warm
57
+
58
+ # 5. Chat with it on your tenant (web widget / console test page). Edit and
59
+ # `octwin deploy` again — a redeploy hot-loads with no restart.
60
+ ```
61
+
62
+ ## Commands
63
+
64
+ | Command | What it does |
65
+ | --- | --- |
66
+ | `octwin init <dir>` | Scaffold a new pure-YAML pack into `<dir>` (writes a starter `manifest.yaml`, flow, prompt, `.gitignore` and `README.md` — pack content only). Options: `--id`, `--description`, `--display-name`. |
67
+ | `octwin validate` | Check the pack locally (structure + pure-YAML rules). `--remote` runs **the same validation the platform runs to load your pack** every declaration file (`xrm.yaml`, `scheduling.yaml`, `worklist.yaml`, `roles.yaml`, `automation.yaml`, `integrations.yaml`, `surveys.yaml`, `taps.yaml`, `commands.yaml`, `journeys/`, `messages.<lang>.yaml`), the cross-file checks between them, and the **flow lint** — conventions the schema can't express, like an `assign:` whose value is a quoted literal or a `$t()` key with no namespace. These need template expansion and the platform's own schemas, which only the server has, so a local ✓ does not cover them. A `--remote` ✓ and a successful deploy are now the same answer by construction, not by convention. |
68
+ | `octwin login` | Save a deploy token for a platform URL **and make that URL the default target** (both stored in `~/.octwin/credentials.json`). `--url`, `--token`. |
69
+ | `octwin whoami` | Verify the saved/passed token is valid for a tenant. `--url`, `--tenant`. |
70
+ | `octwin deploy` | Upload + install the pack onto your tenant's project. `--seed` also runs the pack's demo seed. Reports the **marketplace-listing verdict** when the manifest carries `listing.public: true`. |
71
+ | `octwin status` | Report what the platform has live for this pack — installed version, the **content sha** the instance loaded vs. the one the catalog holds (a redeploy of the *same* version changes it), its flows, and whether it is live on the public marketplace. |
72
+ | `octwin pull <packId>` | Write a **deployed** pack's source back to disk — the inverse of `deploy`, and how a pack pushed from one machine is recovered. Defaults to the version installed on the target project; `--version` overrides, `--dir` defaults to `./<packId>`, a non-empty dir needs `--force`. You may pull a pack your tenant **owns**. |
73
+ | `octwin chat "msg"` | Drive a turn through the dev web channel and print **every render with its tap ids**. `--as <handle>` picks the test user; `--tap "<tap-id>"` presses a rendered button/list row; `--json` dumps the raw envelopes. |
74
+ | `octwin logs` | List recent conversations (handle, status, last activity; `--as` filters), or show one conversation's full event timelineincluding what each turn rendered. `--json` for raw payloads. |
75
+ | `octwin records` | Inspect the pack's XRM data (needs a `records:read` token). No args = list entities. |
76
+ | `octwin cases` | Inspect casework (support tickets): the inbox, one case + its timeline and decisions, or `--queues` for queue keys + open counts. |
77
+ | `octwin projects` | The `--project <slug>` values this token can name, with the plan's project cap. `--archived` includes archived ones. A `pack:deploy` token reaches it it names a project in every other command, so this turns "guess the slug" into "read the list". |
78
+ | `octwin agents` | The agent roster with each agent's **effective** model / history window and **which layer set it** (project override → platform default → pack manifest) — an operator platform default can override what your manifest declares. `--prompt` prints the exact system prompt the LLM sees. Needs `agents:read`. |
79
+ | `octwin orders` | The orders a conversation produced. No args = the list; with a `reference_id` = line items, the subtotal/tax/shipping/discount/total breakdown, `payment_ref`, and the allowed transitions. Needs `orders:read` + the `orders` plan feature. |
80
+ | `octwin analytics` | Stage-by-stage conversion for **any** entity declared with a `pipeline:` (`--overview` / `--milestones` / `--trends` / `--cost`; `--stage <id>` lists the records currently at a stage). Needs `records:read`. |
81
+ | `octwin catalog` | Commerce products with price / availability / stock, plus the WhatsApp catalog binding. `--readiness` runs the Meta Graph checklist. Needs `catalog:read` + the `catalog` plan feature. |
82
+ | `octwin scheduling` | The scheduling engine's state, or `--slots <resourceRecordId>` for the slots one bookable resource actually computes how you verify the availability rules `deploy --seed` created. Needs `scheduling:read`. |
83
+ | `octwin media generate "<prompt>"` | AI-generate an image, store it as a public asset, and print its `MEDIA-` handle + serve URL. `--out` downloads the bytes (WhatsApp renders only `.png`/`.jpg`); `--size`; `--json`. Pairs with `octwin chat --media` to drive media-collect flows. Needs `media:generate`. |
84
+ | `octwin platform-kb pull` | Pull the platform's capability reference into `.octwin/platform-kb/` for the **`octwin-pack`** Claude Code authoring plugin: guides as markdown, plus **one JSON file per capability** (`primitives/record_list.json`, `render-intents/carousel.json`, `declarations/xrm.json`, …) and **three maps** — `INDEX.md` (the corpus, by family and size), `SYMBOLS.md` (every name → its exact file; grep this), `OUTLINE.md` (every heading with its line number). **No token needed** — the reference is served anonymously. `--if-stale` skips the download when your copy is current (cheap enough for every session); `--check` writes nothing and exits 0 current / 2 stale / 1 could-not-tell. |
85
+ | `octwin test` | Alias for `octwin validate --remote` — the platform's full manifest + flow-DSL check. |
86
+ | `octwin feedback` | Submit this pack's `FEEDBACK.md` to the platform team, with the pack version, your CLI version and the `content_hash` of the capability reference you pulled — the two facts that separate a real platform gap from something already fixed or a stale KB. |
87
+ | `octwin help` | Show usage. Every subcommand also answers `--help`. |
88
+
89
+ ### Writing, not just reading
90
+
91
+ Every read command above has a write half behind a **leading verb**, so `octwin cases` reads and
92
+ `octwin cases note <id> "…"` writes. Each needs the matching `:write` scope — `octwin <cmd> --help`
93
+ lists the verbs and their exact flags.
94
+
95
+ | Command | Verbs |
96
+ | --- | --- |
97
+ | `octwin records` | `create <entity> --set k=v` · `patch <id> --entity <e>` · `stage <id> --to <s>` · `note <id> "…"` · `tasks` · `task complete <id>` |
98
+ | `octwin cases` | `assign <id> --to user:<uuid>\|none` · `note` · `transition <id> --to <status>` · `decide <id> --action <a> [--dry-run]` |
99
+ | `octwin orders` | `transition <ref> --to <status>` · `refund <ref> --force` |
100
+ | `octwin catalog` | `availability <sku> --to "in stock"` · `stock <sku> [--set-on-hand n]` |
101
+ | `octwin scheduling` | `rules --resource <id>` · `rule add\|rm` · `exception add\|rm` |
102
+ | `octwin agents` | `set <ref> [--model m] [--enable-tool t] [--disable-tool t]` |
103
+
104
+ `--set k=v` coerces JSON scalars (`--set rating=4.5` sends a number); `--fields-json` takes anything
105
+ nested. Destructive verbs want `--force` rather than a prompt — the CLI is non-interactive by
106
+ design. `cases decide --dry-run` previews the customer-facing copy and the resulting status without
107
+ committing, and needs only `cases:read`.
108
+
109
+ Every command that talks to the platform accepts `--dir <path>` (the pack directory; defaults to
110
+ the current directory) plus the target overrides `--url` / `--tenant` / `--project` / `--token`.
111
+
112
+ ### Debugging a live conversation
113
+
114
+ The platform keeps **one open conversation per `--as` handle**, so consecutive `octwin chat` calls
115
+ with the same handle **continue the same conversation** agent memory, suspended flows, and all:
116
+
117
+ ```bash
118
+ octwin chat "hi" --as tester1 # turn 1 — prints the menu with each row's tap id
119
+ octwin chat --tap "t:invoke:my-flow:x=1" --as tester1 # turn 2 press a rendered row
120
+ octwin chat "3 bedrooms" --as tester1 # turn 3 — free text into the running flow
121
+ octwin logs --as tester1 # find the conversation, then:
122
+ octwin logs <conversationId> # the full timeline (taps, renders, tool events)
123
+ ```
124
+
125
+ ### Reading back the state your pack created
126
+
127
+ `chat`/`logs` show what the bot *said*; these show what it *did*. A 401/403 on any of them names the
128
+ token scope (and plan feature) that command needs, so you can mint a wider token instead of guessing.
129
+
130
+ ```bash
131
+ octwin agents # effective model per agent + which layer set it
132
+ octwin agents my-pack::assistant --prompt # the exact system prompt the LLM sees
133
+ octwin orders # then: octwin orders <reference_id>
134
+ octwin analytics # then: octwin analytics <entity> [--stage <id>]
135
+ octwin catalog # products + stock + the WhatsApp binding
136
+ octwin scheduling --slots <resourceRecordId> # the slots your availability rules compute
137
+ ```
138
+
139
+ Three things worth knowing when you read the output:
140
+
141
+ - **A `pending` payment is usually correct.** The forward payment lifecycle is **webhook-owned**, and a
142
+ workspace with no gateway runs the credential-free `manual` driver so `payment_request` takes its
143
+ `empty` port and your flow should confirm pay-on-delivery. `octwin orders <ref>` says this inline.
144
+ - **Your declared model may not be the one running.** An operator platform default overrides the pack
145
+ manifest; `octwin agents` is where that becomes visible.
146
+ - **An empty funnel has two causes** — the entity has no `pipeline:`, or your token's role has no `view`
147
+ grant on `record.<entity>`. The command prints both rather than a bare "no data".
148
+
149
+ ## Configuration
150
+
151
+ **`octwin login` is the configuration.** There is no config file in your pack — a pack directory
152
+ holds pack content and nothing else, so the same repo deploys from any machine:
153
+
154
+ ```bash
155
+ octwin login --url https://your-octwin.example.com --token oct_…
156
+ ```
157
+
158
+ That stores the token *and* makes the URL your default target, in `~/.octwin/credentials.json`:
159
+
160
+ ```jsonc
161
+ {
162
+ "default_url": "https://your-octwin.example.com", // set by the last `octwin login`
163
+ "https://your-octwin.example.com": "oct_…" // token, keyed by platform url
164
+ }
165
+ ```
166
+
167
+ Tenant and project need no setting at all — the **token carries its own tenant**, plus an optional
168
+ project pin. `--tenant` / `--project` exist only as overrides (a multi-workspace human, or an
169
+ unpinned token that must name a project).
170
+
171
+ Each setting resolves **flag environment variable saved login**:
172
+
173
+ | Setting | Flag | Env var | Saved login |
174
+ | --- | --- | --- | --- |
175
+ | Platform URL | `--url` | `PACK_PLATFORM_URL` | `default_url` |
176
+ | Deploy token | `--token` | `PACK_TOKEN` | token for that URL |
177
+ | Tenant slug *(override)* | `--tenant` | `PACK_TENANT` | *(from the token)* |
178
+ | Project slug *(override)* | `--project` | `PACK_PROJECT` | *(from the token's pin)* |
179
+
180
+ For **CI**, skip `login` entirely and pass `PACK_PLATFORM_URL` + `PACK_TOKEN` as environment
181
+ variables (add `PACK_PROJECT` only if the token isn't pinned).
182
+
183
+ ## Authentication
184
+
185
+ You authenticate with a tenant-scoped **deploy token** (prefixed `oct_…`) not a password and not
186
+ an operator token. Generate it in the Octwin console (**your workspace → API tokens → Generate**).
187
+ It is **least-privilege** (scope `pack:deploy`): it can deploy packs to your tenant but cannot
188
+ manage members, billing, or other tenants, and it is revocable at any time.
189
+
190
+ Add the optional **`media:generate`** scope to let a `--seed` deploy AI-generate seed images
191
+ (for a demo record field like `photo: "generate:<prompt>"`); without it, such fields are seeded as
192
+ text only.
193
+
194
+ ## What a pack may contain
195
+
196
+ A pack is **pure declarative data**`.yaml` / `.yml` / `.md` / `.json` only. Executable
197
+ code (`.ts`/`.js`), HTTP routes, DB clients, custom primitives and **`.sql`** are **not** allowed
198
+ (this is what makes an external pack safe to run on a shared platform; the server enforces it on
199
+ deploy, and so does `octwin validate`). For
200
+ domain records, use Octwin's first-class storage modules **XRM** (records with stage pipelines),
201
+ **catalog** (products), or **casework** (tickets) — declared in `xrm.yaml` and `worklist.yaml`, so a
202
+ pack needs **no database of its own**. (Casework rides `worklist.yaml`'s `work.<entity>` block;
203
+ there is no ~~`cases.yaml`~~ grammar. `octwin platform-kb pull` ships the authoritative list of
204
+ declaration files — read its `INDEX.md` rather than this paragraph.)
205
+
206
+ ## Links
207
+
208
+ - **npm:** <https://www.npmjs.com/package/octwin-cli>
209
+ - **Command help:** `octwin help` (each subcommand also answers `--help`)
210
+ - **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
211
+
212
+ ## License
213
+
214
+ [MIT](./LICENSE) © CEQUENS