@openwop/cli 1.0.1 → 1.2.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.
Files changed (4) hide show
  1. package/README.md +268 -10
  2. package/dist/cli.js +17663 -1722
  3. package/dist/openwop.js +17640 -1722
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -19,8 +19,15 @@ The CLI is a host-agnostic **control plane**: every group drives one protocol su
19
19
  | **Memory & workspace** | `memory` · `workspace` · `prompts` |
20
20
  | **Automation & messaging** | `cron` · `webhooks` · `messaging` · `relay` · `notifications` · `notify` |
21
21
  | **Observability & admin** | `analytics` (`usage`) · `account` · `admin` · `brand` · `conformance` |
22
- | **Product surfaces** | `crm` · `csm` · `comments` · `sharing` · `forms` · `email` · `chat-widget` · `marketplace` · `kb` · `cms` · `documents` · `projects` · `strategy` · `advisors` · `campaigns-orchestration` · `notebooks` · `podcasts` · `priority-matrix` |
22
+ | **Product surfaces** | `crm` · `csm` · `comments` · `sharing` · `forms` · `email` · `chat-widget` · `marketplace` · `kb` · `cms` · `documents` · `projects` · `strategy` · `advisors` · `campaigns-orchestration` · `notebooks` · `podcasts` · `priority-matrix` · `docs` · `knowledge-sync` · `entities` · `creative-briefs` · `creative-video` · `production` · `tutorials` · `walkthroughs` · `widgets` · `ui-state` · `ui-plugin` · `canvas-collab` · `workflow-collab` · `canvas-packs` · `present` |
23
+ | **Commerce & sales** | `commerce` · `commerce-connect` · `promotions` · `recommendations` · `dealers` · `commissions` · `territories` · `sales-maps` (+ `crm` extensions) |
24
+ | **Marketing** | `brand-kits` · `campaign-brief` · `campaign-connectors` · `campaign-intel` · `campaign-journeys` · `cdp` · `destination-sync` · `discovery` · `funnels` · `webinars` · `public` |
25
+ | **Operator administration** | `vault` · `developer-keys` · `billing` · `environments` · `custom-domains` · `site-config` · `runtime-posture` · `maintenance` · `menu-config` |
26
+ | **Operations & work management** | `operations` · `service-desk` · `job-search` · `kicktodo` · `dashboard` · `bi` · `insights-suite` · `intent-ledger` · `work-graph` · `work-selection` · `tasks` · `model-router` · `dev` (+ `strategy` / `priority-matrix` / `projects` / `goals` / `workforces` / `roster` / `profiles` / `twin` / `agent-ops` / `analytics` / `marketplace` / `connections` / `workspace` extensions) |
23
27
  | **Protocol surfaces (RFC)** | `a2a` · `triggers` · `goals` · `proposals` · `export` / `import` |
28
+ | **Protocol + run operations** | `content` (RFC 0103) · `dispatch` (RFC 0118) · `openapi` · `agent-knowledge` · `compat-endpoints` (RFC 0108) · `host-events` · `client-support` (+ `runs` / `interrupts` / `workflows` / `approvals` / `reviews` / `webhooks` / `prompts` / `catalog` extensions) |
29
+ | **Conversations & messaging** | `chat` (sessions/messages/search/export/tools) · `assistant` · `channels` · `scheduled-chats` · `voice` · `ai` · `computer-use` · `whatsapp` · `agent-author` · `workflow-author` · `workflow-proposals` (+ `a2a`, `notifications` extensions) |
30
+ | **Settings & policy** | `capability-firewall` · `heartbeat` · `settings` (+ `cms` / `email` / `kb` / `forms` / `chat-widget` / `consent` / `approvals` / `profiles` / `advisors` / `campaigns-orchestration` / `notifications` / `workflows` / `kanban` / `job-search` extensions) |
24
31
 
25
32
  > **`0.18.x`:** the catalog now covers the full app feature surface — the agent
26
33
  > platform (`agent-profile`, `agent-packs`, `agent-allowlists`, `agent-ops`,
@@ -30,16 +37,70 @@ The CLI is a host-agnostic **control plane**: every group drives one protocol su
30
37
  > `triggers`, `goals`, `proposals`, `export`/`import`). See [`CHANGELOG.md`](./CHANGELOG.md)
31
38
  > for the per-group detail.
32
39
 
40
+ > **Knowledge + content surfaces:** `documents` (+ `artifacts`, `locate`,
41
+ > templates catalog/assemble), `notebooks` (sources/transformations/chat/search),
42
+ > `podcasts` (shows + episode/speaker profiles), `knowledge-sync`, the `media`
43
+ > library (assets, collections, AI image edit/upscale, local-file `upload`),
44
+ > `entities` (+ anonymous `public` reads), `creative-briefs`, `creative-video`,
45
+ > `production`, and the smaller `tutorials` / `walkthroughs` / `widgets` /
46
+ > `ui-state` / `ui-plugin` / `canvas-collab` / `workflow-collab` / `canvas-packs`
47
+ > / `present` groups. Example:
48
+ >
49
+ > ```bash
50
+ > openwop media assets create ./logo.png --org org_1 --tags brand
51
+ > openwop entities types list --json
52
+ > openwop documents render doc_1 --org org_1 --format docx
53
+ > ```
54
+
55
+ > **Protocol + run operations:** `agents list|info`, `roster list` and
56
+ > `org-chart get|dept` now read the NORMATIVE `/v1/agents`, `/v1/agents/roster`
57
+ > and `/v1/agents/org-chart[/{departmentId}]`, falling back to the host-extension
58
+ > path only when the host does not serve the normative read (`--host` forces it,
59
+ > `--verbose` names the path that answered). New: `content` (RFC 0103
60
+ > `/v1/content/*`), `runs effects|revision|pin|unpin|redrive`, `interrupts
61
+ > inspect|respond`, `webhooks rotate-secret|dead-letters`, `catalog packs
62
+ > search|get|export`, `workflows archive|promote|revisions|rollback|stats|estimate|pins|debug-run|eval-set…`,
63
+ > `approvals sla-policy|email-pref|delegations`, `prompts library …`,
64
+ > `agent-knowledge`, `compat-endpoints`, `host-events`, `client-support`,
65
+ > `dispatch fanout`, `openapi`. Example:
66
+ >
67
+ > ```bash
68
+ > openwop content page pricing --locale es
69
+ > openwop runs effects run_123 --json
70
+ > openwop interrupts respond run_123 approve-gate --data-json '{"action":"approve"}'
71
+ > openwop workflows promote wf_123 && openwop workflows revisions wf_123
72
+ > openwop webhooks rotate-secret sub_1 --generate
73
+ > ```
74
+
33
75
  ## Protocol version support (v2 and v1)
34
76
 
35
77
  The CLI speaks the **OpenWOP wire directly** — no SDK dependency — and negotiates the protocol major once per invocation (`src/protocol.ts`, per `spec/v2/core/versioning.md` §1.5):
36
78
 
37
- - It reads `/.well-known/openwop` and selects the **highest major it implements that the host advertises** in `protocolVersions[]` — 2 when the host lists any `2.x`, otherwise 1.
38
- - Under major 2, every request for an operation named in `spec/v2/path-manifest.json` goes to the **unversioned path with `OpenWOP-Version: 2.0`** (`/v1/runs` → `/runs`). Host-proprietary routes the manifest does not name — the demo backend's `/v1/host/sample/*` — are sent exactly as written; they have no v2 home yet (`versioning.md` §5).
79
+ - It reads `/.well-known/openwop` once (asking for the v2 representation with `OpenWOP-Version: 2`; a host that doesn't serve major 2 answers `406` with the list it does serve) and selects the **highest major it implements that the host advertises** in `protocolVersions[]` — 2 when the host lists any `2.x`, otherwise 1.
80
+ - Under major 2, every request for an operation named in `spec/v2/path-manifest.json` goes to the **unversioned path with `OpenWOP-Version: 2.0`** (`/v1/runs` → `/runs`). Host-proprietary routes the manifest does not name — the reference host's `/v1/host/openwop-app/*` — go to the **unversioned root the host advertises** for that org under `extensions.*` (`{ "root": "/host/openwop-app/", "twin": "/v1/host/openwop-app/" }`, `versioning.md` §5), with **no** version header (a `/host/<org>/` path has no major). With no advertised root, the `/v1/host/<org>/…` twin is sent as written.
39
81
  - Under major 1 nothing changes: `/v1/…` paths, header-less, the v1 default the overlap guarantees.
40
82
  - `OPENWOP_PROTOCOL_MAJOR=1` or `=2` pins the major without probing discovery.
41
83
 
42
- `openwop doctor`'s `protocol` row reports `protocolVersions`, `preferredVersion`, and the major this process selected; it fails only when the host advertises neither major the CLI implements.
84
+ `openwop doctor`'s `protocol` row reports `protocolVersions`, `preferredVersion`, and the major this process selected; it fails when the host advertises neither major the CLI implements. Its `response version` row reports the `OpenWOP-Version` the host answered with and fails on a silent downgrade (`versioning.md` §1.4); its `min client` row fails when the host's `minClientVersion` is above the version the CLI speaks (2.0 / 1.1) — the host MAY then refuse requests with `426 client_version_unsupported` (§1.5).
85
+
86
+ What else the CLI does as a v2 client (audited against `spec/v2/core/*` at corpus `v2.42.6`):
87
+
88
+ | Obligation | Behaviour |
89
+ |---|---|
90
+ | Tenant-bound ids (`identity.md` §5) | A `<tenantId>/<id>` run id is sent in the projected wire form (`acme~2Fr1`) on every `/runs/{runId}…` path under major 2 — never `%2F`, which a decoding front door turns into a 404. Pass ids as the host prints them. |
91
+ | Error envelope (`errors.md`) | Errors print as `HTTP <status> <code>: <message>`; `426`/`406`/`429` add an actionable hint (`Retry-After` for 429). |
92
+ | Poll cursor (`events.md` §Poll) | `afterSequence` under major 2, `lastSequence` under major 1; `isTerminal` / `isComplete`. |
93
+ | SSE resume (`events.md` §Resuming with `Last-Event-ID`; v1 `stream-modes.md` §Resumption) | Every run stream (`runs events --follow` / `runs watch`, `chat`, `workflow-author`) remembers the last `id:` and, when the connection drops or closes before the terminal event, reconnects with `Last-Event-ID` after the server's `retry:` delay (doubling per attempt without progress, cap 30 s, 5 attempts). A close is first checked against the run's status, so a mode that never carries the terminal event (`messages`) ends cleanly. Events are deduped by `sequence`, so nothing prints twice even from a host that re-emits the resumption point. `--since N` / `--last-event-id ID` start mid-log: both majors send the `Last-Event-ID` header (neither defines a `since` stream parameter); v2 requires an integer id, v1's is sent verbatim. |
94
+ | Stream modes (`events.md` §Stream modes; v1 `stream-modes.md`) | `--stream-mode` `updates`, `values`, `messages`, `debug` or a comma list of `updates`/`messages`/`debug` → `?streamMode=`, validated against the spec pattern before any request (`values` never combines). A host `400 unsupported_stream_mode` is reported with its `details.supported`, never silently replaced by the (mode-less) poll fallback. `state.snapshot` and `ai.message.chunk` frames are rendered by their frame name; `event: batch` arrays are unpacked. |
95
+ | Event names (`events.md` §Types) | v1 and v2 names (`run.resuming` / `run.resume-started`, `agent.toolCalled` / `agent.tool-called`, …) render identically; the table is pinned to `spec/v2/event-codemap.json`. |
96
+ | `Idempotency-Key` (`idempotency.md`) | Sent on run create/fork, chat turns, interrupt resolve, and webhook / trigger / prompt creation; `--idempotency-key` on `runs create|fork` and `interrupts resolve`. |
97
+ | Interrupt resolve (`interrupt.md`) | Body is the closed `{ "resumeValue": … }`. |
98
+ | Discovery (`capabilities.md`) | `openwop capabilities` renders the v2 root (records by status, `minClientVersion`, `eventLogSchemaVersion`, `extensions`) from the negotiation read. |
99
+ | Run list (`runs.md` §List) | `runs list --cursor` / `--workflow-id`; the `nextCursor` hint is printed. |
100
+ | Stream origin (host extension; openwop-app ADR 0761) | Some front doors buffer event streams entirely — `https://app.openwop.dev/api` delivered **0 bytes of an event stream in 25 s** (measured 2026-09-27), and `runs.md` keeps `eventsUrl` on the request's origin, so the protocol cannot redirect. Every stream (`runs watch`, `chat`, `notifications stream`, `kanban watch`, `present`) is therefore read from the **stream origin**: `--stream-base-url` > `OPENWOP_STREAM_BASE_URL` > config `host.streamBaseUrl` > a host-advertised `extensions.*.streamBase` (accepted only if `https:` with no credentials/query/fragment, read from an `https:` host; loopback `http:` only for a loopback base) > `--base-url`. Non-stream requests always use `--base-url`. To keep streams on `--base-url` too (e.g. an egress proxy), set `--stream-base-url` to the same URL; `openwop doctor`'s **stream origin** row shows which origin is in use and why. |
101
+ | Stalled streams | A run stream that delivers **no bytes** (keep-alives included) for `--idle-timeout-ms` (default 45000; 0 disables) is aborted and resumed with `Last-Event-ID` — a half-open connection no longer hangs the command. `scripts/live-sse-resume.mjs` checks resume against a real run (`--mode drop|stall`). |
102
+
103
+ When the host's `minClientVersion` is above the CLI, every command prints one warning (from the discovery read it already made); refusing is left to the host (`426`). Not exposed: the `bufferMs` batching hint (batched frames from a host that batches anyway are consumed).
43
104
 
44
105
  The pre-1.0 `0.18.x` line was frozen v1-only; that decision was reversed with 1.0.0 (CHANGELOG). The frozen line stays on branch `cli-v1-frozen` for anyone who needs a client that never sends `OpenWOP-Version`.
45
106
 
@@ -74,7 +135,7 @@ The `onboard` wizard walks you through:
74
135
 
75
136
  1. **Host URL** — `https://app.openwop.dev/api` (shared demo), `http://localhost:8080` (local), or a custom URL.
76
137
  2. **AI provider** — `anthropic`, `openai`, `google`, or `minimax` (matches what the demo backend dispatches to).
77
- 3. **API key** — auto-detects `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GOOGLE_API_KEY` / `MINIMAX_API_KEY`, or hidden-input via raw-mode stdin. The key is POSTed to `/v1/host/sample/byok/secrets` on the configured host. **The key is never written to your local config file** — only a credential ref pointer is stored.
138
+ 3. **API key** — auto-detects `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GOOGLE_API_KEY` / `MINIMAX_API_KEY`, or hidden-input via raw-mode stdin. The key is POSTed to `/v1/host/openwop-app/byok/secrets` on the configured host. **The key is never written to your local config file** — only a credential ref pointer is stored.
78
139
  4. **Model** — provider-specific recommended defaults plus a custom option.
79
140
  5. **Test the connection** — verifies the credential ref appears in the host's BYOK list.
80
141
 
@@ -99,7 +160,7 @@ openwop providers remove openai
99
160
  openwop providers test anthropic
100
161
  ```
101
162
 
102
- `providers add` POSTs to `/v1/host/sample/byok/secrets`; `remove` DELETEs; `list` and `test` read.
163
+ `providers add` POSTs to `/v1/host/openwop-app/byok/secrets`; `remove` DELETEs; `list` and `test` read.
103
164
 
104
165
  ## Chat
105
166
 
@@ -116,6 +177,35 @@ openwop chat sample.chat.turn --no-stream --json
116
177
  - **Quitting** — `/exit`, `/quit`, or Ctrl-D (EOF).
117
178
  - **`--json`** — emits raw event records (one JSON object per event) instead of the pretty `assistant>` rendering.
118
179
  - Extra per-turn inputs (`--input k=v`, `--inputs-json`) ride along on every run, so you can pin a `credentialRef`, model, or other configurable input.
180
+
181
+ ### Conversations, channels & voice
182
+
183
+ `chat` is the ONE chat group: besides the REPL it drives the host's persistent
184
+ conversations (`/v1/host/openwop-app/chat/*`) — sessions, messages, reactions,
185
+ participants, feedback, search, export/import, and per-conversation tool scope.
186
+ Team channels, scheduled agent chats, the executive assistant, voice, and the AI
187
+ authoring surfaces each have their own group; every `--help` names the exact path.
188
+
189
+ ```bash
190
+ openwop chat sessions create --title "Launch plan" --type group --participant agent:core.openwop.agents.planner.default
191
+ openwop chat messages send <sessionId> --content "Summarize the thread"
192
+ openwop chat search "pricing" --limit 5 --json
193
+ openwop chat export <sessionId> --format md --output thread.md
194
+ openwop chat tools set <sessionId> --mode restricted --enable openwop:fs.read
195
+ openwop channels post <channelId> --content "@planner draft the agenda"
196
+ openwop channels stream <channelId> --max-events 5
197
+ openwop scheduled-chats create --org org_1 --conversation <id> --agent <agentId> --prompt "Weekly status" --cron "0 9 * * 1"
198
+ openwop assistant pending approve <actionId> --content-hash <hash-from-the-card>
199
+ openwop voice session audio <sessionId> --file hello.webm && openwop voice session commit <sessionId>
200
+ openwop workflow-author draft --intent "Every Monday, summarize open tickets and email me" --follow
201
+ openwop notifications stream --max-events 3
202
+ ```
203
+
204
+ Streams (`channels stream|presence`, `notifications stream`, `voice realtime
205
+ transcript`) stop after `--max-events` or `--timeout-ms` (default 30 s). Secrets
206
+ stay server-side: the realtime voice token is redacted unless `--reveal-token`,
207
+ and `ai bind-credential` reads the credential from a file or env var and prints
208
+ only the returned reference.
119
209
  ## Packs (signed node-pack registry)
120
210
 
121
211
  ```bash
@@ -136,7 +226,7 @@ These talk to the signed node-pack registry — a **separate surface** from the
136
226
 
137
227
  ## Messaging & relay
138
228
 
139
- Connect chat channels (Signal / WhatsApp / iMessage) to the host so inbound messages drive workflow runs and replies are delivered back. Channels are a **host-extension** surface (`/v1/host/sample/messaging`), not part of the normative OpenWOP wire — the protocol stays channel-agnostic.
229
+ Connect chat channels (Signal / WhatsApp / iMessage) to the host so inbound messages drive workflow runs and replies are delivered back. Channels are a **host-extension** surface (`/v1/host/openwop-app/messaging`), not part of the normative OpenWOP wire — the protocol stays channel-agnostic.
140
230
 
141
231
  ```bash
142
232
  openwop relay setup --channel signal # register + activate a device, store its token
@@ -182,9 +272,10 @@ openwop runs annotate <runId> --rating 5 [--note "great"] # attach a rating/labe
182
272
  openwop runs annotate <runId> --label triage --event-id <id>
183
273
  openwop runs debug-bundle <runId> [--max-events n] [--out bundle.json]
184
274
  openwop runs ancestry <runId> # RFC 0040 cross-host parent chain
275
+ openwop runs watch <runId> [--since N] [--stream-mode updates,messages] # SSE follow, auto-resumes on a drop
185
276
  ```
186
277
 
187
- `runs events --since N` maps to the spec-canonical `lastSequence` query param (events with `sequence > N`). `runs annotate` posts exactly one signal kind (`--rating 1-5` | `--label` | `--correction` | `--flag`), validated client-side. `runs debug-bundle --out <file>` saves the full event bundle to disk.
278
+ `runs events --since N` polls with the poll cursor (`afterSequence` under v2, `lastSequence` under v1; events with `sequence > N`). `runs events --follow` / `runs watch` stream over SSE instead, where `--since N` becomes the `Last-Event-ID` header (see §Protocol version support). `runs annotate` posts exactly one signal kind (`--rating 1-5` | `--label` | `--correction` | `--flag`), validated client-side. `runs debug-bundle --out <file>` saves the full event bundle to disk.
188
279
 
189
280
  ## Operator surfaces
190
281
 
@@ -268,7 +359,7 @@ Exit codes: `0` success · `1` host/HTTP error (including consent not enabled)
268
359
 
269
360
  ## MCP server mount
270
361
 
271
- An MCP client for the host's JSON-RPC server mount (RFC 0020) — a single JSON-RPC 2.0 endpoint at `POST /v1/host/sample/mcp` speaking modelcontextprotocol.io 2025-06-18. The mount is **host-controlled**: it's env-gated (`OPENWOP_MCP_SERVER_ENABLED`, **OFF by default**) and the CLI cannot toggle it. When the mount isn't exposed the endpoint 404s and these commands **fail closed legibly** (exit 2).
362
+ An MCP client for the host's JSON-RPC server mount (RFC 0020) — a single JSON-RPC 2.0 endpoint at `POST /v1/host/openwop-app/mcp` speaking modelcontextprotocol.io 2025-06-18. The mount is **host-controlled**: it's env-gated (`OPENWOP_MCP_SERVER_ENABLED`, **OFF by default**) and the CLI cannot toggle it. When the mount isn't exposed the endpoint 404s and these commands **fail closed legibly** (exit 2).
272
363
 
273
364
  ```bash
274
365
  openwop mcp ping # liveness probe of the mount
@@ -328,7 +419,7 @@ Identity `source` is one of `oidc | password | saml | scim | manual`. Exit codes
328
419
 
329
420
  ## Feature toggles
330
421
 
331
- `toggles` renders the caller's **resolved** feature-toggle assignments (a non-normative host extension under `/v1/host/sample/feature-toggles/assignments`). The **host** is the sole authority — it resolves every toggle server-side from the authenticated principal — and the CLI only *displays* what the host returns. It **never** computes, asserts, or overrides a toggle decision locally, and it does not author config (the superadmin config surface is intentionally not exposed). When the host doesn't serve the surface the command fails closed (exit 2).
422
+ `toggles` renders the caller's **resolved** feature-toggle assignments (a non-normative host extension under `/v1/host/openwop-app/feature-toggles/assignments`). The **host** is the sole authority — it resolves every toggle server-side from the authenticated principal — and the CLI only *displays* what the host returns. It **never** computes, asserts, or overrides a toggle decision locally, and it does not author config (the superadmin config surface is intentionally not exposed). When the host doesn't serve the surface the command fails closed (exit 2).
332
423
 
333
424
  ```bash
334
425
  openwop toggles list # every toggle's resolved state for you (incl. off)
@@ -443,6 +534,63 @@ openwop a2a task run_abc123 --json # the durable task's live state
443
534
 
444
535
  The record is content-free by design (state, `interruptKind`, push config — never run inputs/outputs/credentials); the CLI renders the host's resolved state and never derives one locally. Gated on `capabilities.a2a` (the durable read needs `durableTasks: true`). `task` exit codes: `0` completed · `3` submitted/working/input-required/auth-required · `1` failed/canceled/rejected or error.
445
536
 
537
+ ## Commerce & sales
538
+
539
+ Host-extension groups over the reference host's commerce and sales surfaces
540
+ (`/v1/host/openwop-app/{commerce,commerce-connect,promotions,recommendations,dealers,commissions,territories,sales-maps,crm}/…`,
541
+ plus the public visitor routes `public-store`, `public-recommendations`, `partner`,
542
+ `public-book`, `public-sign`, sent without auth). Each group's `--help` lists every
543
+ command with the exact method + path it hits. Org-scoped commands take `--org <orgId>`;
544
+ flags are the host's field names in kebab-case, and `--body`/`--body-file` supply a
545
+ full JSON body. Money amounts pass through exactly in the unit the host's field
546
+ names (`priceMinor`, `priceMajorUnits`, `price` …) — the CLI never computes a total.
547
+ Stripe Connect seller onboarding returns a hosted link only; no card or bank data
548
+ ever passes through the CLI.
549
+
550
+ ```bash
551
+ openwop commerce products list --org org_1 --q shirt
552
+ openwop commerce orders get ord_1 --org org_1 --json
553
+ openwop commerce public products --org org_1 # the anonymous storefront view
554
+ openwop commerce ucp token --org org_1 --client-id c_1 --client-secret-env UCP_SECRET
555
+ openwop commerce-connect seller onboard # prints the Stripe-hosted onboarding link
556
+ openwop promotions create --org org_1 --name "10% off 50+" --type cart_threshold --min-spend 50 --reward '{"kind":"percentage","value":10}'
557
+ openwop crm deals list --org org_1
558
+ openwop crm segments members seg_1 --json
559
+ openwop crm public-sign get <token>
560
+ openwop territories models activate mdl_1 --org org_1
561
+ openwop commissions statements pay st_1 --org org_1
562
+ ```
563
+
564
+ Destructive commands (deletes, refunds, cancels, voids) refuse without `--yes`.
565
+ Exit codes: `0` ok · `2` usage error / request rejected · `4` not signed in or not permitted · `1` server error.
566
+
567
+ ## Marketing surfaces
568
+
569
+ Marketing features on the reference host's `/v1/host/openwop-app/*` extension
570
+ (each is feature-toggled and org-scoped host-side; the CLI renders the host's decision):
571
+
572
+ ```bash
573
+ openwop brand-kits list --org org_1 # marketing brand kits (NOT `openwop brand`, the app-wide identity)
574
+ openwop campaign-brief briefs create --org org_1 --name "Q4 launch" --objective "Pipeline"
575
+ openwop campaign-connectors kpi --org org_1 --json # ad-platform performance roll-up
576
+ openwop campaign-intel plan-budget --org org_1 --total-budget-minor 500000 --target-conversions 200 --horizon-days 30
577
+ openwop cdp resolve --type email --value a@example.com
578
+ openwop destination-sync dry-run sync_1 --sample-json '{"email":"a@example.com"}'
579
+ openwop funnels publish fn_1 --org org_1
580
+ openwop webinars list --org org_1
581
+
582
+ # Anonymous visitor surfaces (no bearer sent) — test what your visitors see:
583
+ openwop public pages org_1
584
+ openwop public sitemap org_1
585
+ openwop public pricing --json
586
+ openwop funnels public view org_1 webinar
587
+ openwop forms public get form_1
588
+ openwop email public click <token> # prints the redirect target, does not follow it
589
+ ```
590
+
591
+ Destructive commands (`delete`, a live `campaign-intel apply`, an email
592
+ unsubscribe/preference change) refuse without `--yes`.
593
+
446
594
  ## Config
447
595
 
448
596
  `~/.openwop/config.json` (or `$OPENWOP_CONFIG_HOME/.openwop/`) stores the host URL, default provider, default model, and credential ref. **API keys are never stored locally.**
@@ -455,6 +603,116 @@ openwop config set defaultModel gpt-4o
455
603
  openwop config unset credentialRef
456
604
  ```
457
605
 
606
+ ## Identity & operator administration
607
+
608
+ Identity, RBAC, tenancy and operator surfaces of the reference host (all under
609
+ `/v1/host/openwop-app/…`; each group's `--help` names the exact path). Super-admin
610
+ surfaces (`vault`, `site-config get|set`, `runtime-posture`, `maintenance`,
611
+ `toggles admin`, `governance`, `billing` import/coupons/seats, `menu-config set tenant`,
612
+ `brand get|set|asset`) fail **closed** with exit `4` and say how to get a super-admin
613
+ principal (`OPENWOP_SUPERADMIN_TENANTS`); `admin …` needs the host admin token.
614
+ Secrets are refs only: vault values, the break-glass token and an anonymous session
615
+ cookie are read from a file or a no-echo prompt, never argv, and never printed. A
616
+ developer key's token is printed once, when the host issues it.
617
+
618
+ ```bash
619
+ openwop orgs invites org_1 create --email jo@acme.com --role editor
620
+ openwop orgs decide --principal user:jo --action runs:read # exit 0 allowed / 1 denied
621
+ openwop users me security
622
+ openwop vault list
623
+ openwop vault set billing:stripe-key --scope host --value-file ./stripe.key
624
+ openwop developer-keys create --name "CI deploy" --scope runs:write
625
+ openwop environments promote --from dev # exit 3 when queued for approval
626
+ openwop billing portal # a Stripe-hosted URL; no card data
627
+ openwop governance egress-rules set --mode allowlist --host api.stripe.com
628
+ openwop toggles admin set crm --status beta # read-modify-write
629
+ openwop admin run-retention hold t_acme --reason "legal hold"
630
+ ```
631
+
632
+ Not driven (browser or server-to-server legs): `POST /auth/saml/sso/acs` (IdP form
633
+ post), `POST /billing/webhook` (Stripe-signed), `POST /vault/secrets/:ref/reveal`
634
+ (returns plaintext). Exit codes: `0` ok · `1` server error · `2` usage error / request
635
+ rejected · `3` pending (approval queued, domain not yet live) · `4` not signed in / not permitted.
636
+
637
+ ## Operations & work management
638
+
639
+ Host-extension groups over the reference host's operations and work surfaces:
640
+ the operator console (`operations` — health, SLO, DLQ, dispatch outbox, webhook
641
+ delivery, saga compensation), the help desk (`service-desk`, plus the anonymous
642
+ `public` widget path), `job-search`, `kicktodo` readiness, your `dashboard`,
643
+ org `bi` metrics, `insights-suite`, a conversation's `intent-ledger`, ambient
644
+ `work-graph` suggestions, `work-selection` ranking, the run `tasks` deck, the
645
+ `model-router` switch, and the demo-only `dev ucp-merchant`. It also fills out
646
+ `strategy` (check-ins, versions, timeline, cadence, decisions, links),
647
+ `priority-matrix` (ideas, scores, intake, evidence, schedules, sessions,
648
+ scenarios, portfolio, federated peers), `projects` (knowledge, memory,
649
+ schedules, visibility, group chat), `goals` (arm / evaluate / record-run),
650
+ `workforces migration set`, `roster activity|check`, `profiles` (pins, avatar,
651
+ personal knowledge), `analytics` (trend, nav telemetry), `marketplace` (feature
652
+ bundles, pack enablement, certify, pack remove/restore) and `connections`
653
+ (delete, inbound webhook binding, provider catalog).
654
+
655
+ Each group's `--help` is generated from its route table and lists the exact
656
+ method + path every command hits. Flags are the host's field names in kebab-case;
657
+ writes also take `--body`/`--body-file`. Routes that REPLACE a whole document on
658
+ write (job-search steering, strategy cadence, bi metric definitions,
659
+ insights-suite config, profile contact) are read-modify-write, so flags you do not
660
+ pass keep their saved values. Secrets (a federated peer's bearer, an inbound
661
+ signing secret) are read from a file and never printed.
662
+
663
+ ```bash
664
+ openwop operations health --json # superadmin
665
+ openwop operations compensation run_42
666
+ openwop service-desk tickets org_1 --status open
667
+ openwop service-desk public send sdk_0123... --text "Hi" # the anonymous widget path
668
+ openwop strategy check-ins add s_1 kr_1 --value 42 --note "on track"
669
+ openwop priority-matrix ideas score l_1 c_1 --score reach=8 --score effort=3
670
+ openwop projects schedules add p_1 --cron-expr "0 9 * * 1" --workflow-id wf.weekly
671
+ openwop job-search steering set org_1 --roles "Staff Engineer" --remote --daily-cap 5
672
+ openwop bi metrics run org_1 open-deals --bucket week
673
+ openwop tasks deck
674
+ ```
675
+
676
+ Destructive commands refuse without `--yes`. Exit codes: `0` ok · `2` usage error /
677
+ not found / rejected · `4` not signed in or not permitted · `1` server error
678
+ (`kicktodo readiness` also exits `1` when the product reports `degraded`).
679
+
680
+ ## Residual host surfaces
681
+
682
+ The last host-extension routes the reference host serves, added as three new
683
+ groups — `capability-firewall` (composition rules, recent decisions, a read-only
684
+ `simulate`, and the super-admin platform baseline), `heartbeat` (the host-wide
685
+ agent heartbeat switch, super-admin) and `settings` (your personal token cap,
686
+ reasoning directive and privacy opt-outs) — and as route tables inside existing
687
+ groups: `cms` (scheduled publish/unpublish, version restore, review status, shared
688
+ sections, language settings, translator locale grants, per-locale publish, AI
689
+ section translation, page A/B experiments, and the page SEO head), `email` (sender
690
+ settings, provider status, bounce-webhook configs, campaign engagement), `kb`
691
+ (retrieval config, media-collection ingest, reindex drain/cancel), `forms`
692
+ (templates), `chat-widget tool-catalog`, `consent` (purpose vocabulary, re-admit an
693
+ erased subject), `approvals teams-pref`, `profiles memory-extraction`, `advisors`
694
+ (strategy context, shared knowledge), `campaigns-orchestration`
695
+ (workspace/versions/dispatches), `notifications preferences`, `workflows budget`,
696
+ `kanban column-limit|work-item-run` and `job-search answers`.
697
+
698
+ Replace-on-write documents (firewall rules, SEO head, heartbeat config,
699
+ notification preferences, personal settings, workflow budget) are
700
+ read-modify-write, so flags you do not pass keep their saved values. The email
701
+ webhook verification secret is read from a file and never printed.
702
+
703
+ ```bash
704
+ openwop capability-firewall simulate --org org_1 --next '{"egress":"safe-fetch"}' --seen '[{"safetyTier":"read"}]'
705
+ openwop cms schedule publish page_1 --org org_1 --at 2026-10-01T09:00:00Z
706
+ openwop cms experiments results page_1 pexp:1 --org org_1
707
+ openwop email webhooks add --org org_1 --provider postmark --verification-secret-file ./secret.txt
708
+ openwop notifications preferences set --quiet-hours --timezone Europe/Oslo
709
+ openwop workflows budget set wf_1 --daily-usd 10 --hard-cap
710
+ openwop settings prefs set --daily-token-cap 200000
711
+ ```
712
+
713
+ Exit codes: `0` ok · `2` usage error / not found / rejected · `4` not signed in or
714
+ not permitted (the super-admin surfaces say so) · `1` server error.
715
+
458
716
  ## Defaults
459
717
 
460
718
  - Host URL: `--base-url` > `OPENWOP_BASE_URL` > **saved config** (`onboard`'s `~/.openwop/config.json`) > `http://localhost:8080`. After `onboard`, everyday commands use the saved host with no flag.