@wji.ai/cli 0.1.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.
@@ -0,0 +1,398 @@
1
+ ---
2
+ name: wji
3
+ description: Drive the WJI AI platform from the terminal with the `wji` CLI — sign in, manage workspaces and the fsnode/dataset tree, upload assets, generate images/video/audio and poll the results, and work on Infinite Canvas nodes (read the user's selected nodes, create generate nodes, connect references), and manage models, agents, prompt presets and your profile. Use whenever a task mentions WJI, wji-backend, a WJI workspace, canvas, fsnode, dataset node, or asks to generate media on WJI.
4
+ ---
5
+
6
+ # WJI CLI
7
+
8
+ `wji` is a thin, scriptable client over the WJI API. Every command accepts
9
+ `--json`, so prefer `--json` piped through `jq` when you need to read a value,
10
+ and the human table output when you are showing the user a result.
11
+
12
+ ## Before anything else
13
+
14
+ ```bash
15
+ wji auth whoami --json # confirms endpoint, credential, org context
16
+ ```
17
+
18
+ - `wji: command not found`: the CLI is not on PATH. From the `wji-cli` repo,
19
+ `npm run build`, then link it where the user can write without sudo —
20
+ `ln -s "$PWD/dist/index.js" ~/.local/bin/wji` (if `~/.local/bin` is on
21
+ PATH). `npm link` fails with `EACCES` when the global prefix is root-owned;
22
+ don't reach for `sudo`.
23
+
24
+ - Exit code `77` means the credential is missing or rejected. Tell the user to
25
+ run `wji auth login` (interactive) or export `WJI_API_KEY`. **Never ask the
26
+ user to paste a password into the conversation and never type one into
27
+ `--password` yourself** — `wji auth login` prompts without echoing.
28
+ - `wji config show` reveals which endpoint and profile are active. A local
29
+ backend is `wji config set endpoint http://localhost:3002` — `:3000` is the
30
+ web frontend, not the API.
31
+ - **Running several `wji` commands in parallel? Prefer an API key**
32
+ (`WJI_API_KEY`, or `wji auth key create <name> --save`). A JWT login rotates
33
+ its refresh token, and the server revokes *every* session if a refresh token
34
+ is ever replayed. The CLI serializes refreshes across processes, but a key
35
+ never refreshes at all. A JWT profile that keeps returning 401 needs one
36
+ `wji auth login`.
37
+
38
+ ## The mental model
39
+
40
+ ```
41
+ organization (X-Org-Id header, optional)
42
+ └── workspace wji ws
43
+ ├── apps (Dataset, Files, InfiniteCanvas, …)
44
+ └── fsnode tree wji fs
45
+ └── dataset nodes wji dataset
46
+ generation ─> history entry ─> assets wji gen / wji history / wji asset
47
+ ```
48
+
49
+ - A **workspace** scopes billing, quota and members.
50
+ - The **fsnode tree** is the file system inside a workspace: folders and files,
51
+ each with a free-form `content` JSON object.
52
+ - A **dataset node** is an fsnode with mimetype `workspace/dataset` whose
53
+ `content` carries `{ type, description }` — these are the "ideas"
54
+ (outline, screenplay, character, location, prop, outfit, scene, shot, other)
55
+ that feed generation. See *Character datasets* below.
56
+ - **Generation is asynchronous.** Submitting returns a history entry; the
57
+ assets inside it start `pending` and become `ready`.
58
+
59
+ ## Set a working context first
60
+
61
+ Most commands take `--workspace`, but setting a default is less error-prone:
62
+
63
+ ```bash
64
+ wji ws list
65
+ wji ws use <workspaceId>
66
+ ```
67
+
68
+ After that, `wji ws get`, `wji fs`, `wji gen` and `wji preset list` all default
69
+ to that workspace. Use `wji ws use` rather than repeating `--workspace`.
70
+
71
+ ## Reading and editing the tree
72
+
73
+ ```bash
74
+ wji ws fs # whole workspace tree
75
+ wji ws fs --app <appId> # one app's tree
76
+ wji fs tree <nodeId> --depth 2
77
+ wji fs ls <folderId>
78
+ wji fs get <nodeId> --json | jq .content
79
+
80
+ wji fs mkdir <parentId> characters --nickname 角色
81
+ wji dataset new <folderId> "Ada" -t character -d "a tired detective"
82
+ wji fs describe <nodeId> @description.md
83
+ wji fs set <nodeId> --images <assetId> <assetId>
84
+ ```
85
+
86
+ `wji fs set --content` **replaces** the whole content object. To change one
87
+ field, read it first (`wji fs get <id> --json | jq .content`), merge, then
88
+ write — or use `wji fs describe`, which merges `content.description` for you.
89
+
90
+ Several GET endpoints are cached server-side for 10 seconds, so a plain read
91
+ immediately after a write can come back stale. `wji fs describe` and
92
+ `wji preset update` already bypass that cache; if you hand-roll a
93
+ read-merge-write with `--json`, expect the read to lag briefly.
94
+
95
+ ## Generating media
96
+
97
+ Always pick the model from the live list rather than guessing a name:
98
+
99
+ ```bash
100
+ wji models list --feature image
101
+ wji models get <model> # ratios, max n, reference support, --set params
102
+ wji gen cost -t image -m <model> -n 4
103
+ ```
104
+
105
+ **Pass the value in the MODEL column to `-m`** — that is the model's `nickname`,
106
+ which is unique. The `name` column is shown only when it differs, and names do
107
+ collide across providers (two different `seedance-2.0` entries exist), so `-m`
108
+ with a bare name resolves to whichever the server picks first.
109
+
110
+ Then submit. Add `--wait` when the user is waiting on the result:
111
+
112
+ ```bash
113
+ wji gen image -m <modelName> -p "a rainy alley at dusk" -n 4 --ratio 16:9 --wait
114
+ wji gen video -m <modelName> -p "slow pan" -d 5 --start-image <assetId> --wait --timeout 1200
115
+ wji gen audio -m <modelName> -p "rain on a tin roof" --wait
116
+ ```
117
+
118
+ - References are `assetId[:label[:weight]]`: `--ref 65f0…:hero:0.6`. Reference
119
+ *assets*, not file paths — upload first with `wji asset upload`.
120
+ - Model-specific parameters go through `--set` (`--set quality=high`); read the
121
+ valid keys from `wji models get`.
122
+ - `--fsnode <id>` files the result onto a node; `--tags` labels the history.
123
+ - Video can take minutes. Without `--wait` you get a history id back:
124
+ `wji history get <id> --wait` resumes polling, and `--timeout` is in seconds.
125
+ - On timeout the task is usually still running — re-poll rather than
126
+ resubmitting, which would charge credits twice.
127
+ - `wji models get` prints the model's own parameter list with defaults and
128
+ allowed values. Only `--set` keys listed there take effect; anything else is
129
+ ignored silently.
130
+ - Billing inputs are server-owned and stripped from `--set` / `--values`:
131
+ `num_images`, `referenceImageCount`, `referenceVideoTotalDuration`,
132
+ `output_resolution` and every `*Info` field. Use `-n` for the count and the
133
+ real reference flags (`--ref`, `--ref-video`, …) for references.
134
+
135
+ ### Choosing a model (house guidance)
136
+
137
+ Use this to pick a model when the user hasn't named one, and to explain the
138
+ trade-off when they have. Exact nicknames differ between environments — always
139
+ confirm with `wji models list --feature <image|video>` and `wji models get`.
140
+
141
+ **Images:** prefer **GPT Image 2.5** (`gpt-image-2.5-sunburst` for new images
142
+ and big changes such as character sheets; `gpt-image-2.5-flare` for edits that
143
+ keep the composition), **Nano Banana 2** or **Nano Banana Pro**.
144
+
145
+ **Video — reference models over first/last-frame models.** A family usually
146
+ has both:
147
+
148
+ | Kind | Examples | Takes |
149
+ | --- | --- | --- |
150
+ | **Ref** (preferred) | `seedance-2.5-ref`, `seedance-2.0-ref`, `seedance-2.0-fast-ref`, `Wan 3.0 Ref`, `Wan 3.0 Prime Ref`, `minimax-h3-ref`, `minimax-h3-max-ref` | reference **images, videos and audio** together (e.g. a character sheet + a motion clip + a voice line) |
151
+ | First/last frame | `seedance-2.5`, `seedance-2.0`, `Wan 3.0`, `minimax-h3-i2v`, `minimax-h3-max-i2v` | only a start and/or end image |
152
+
153
+ Use a first/last-frame model only when the user explicitly wants a shot to
154
+ start or end on an exact frame. With a Ref model, pass images with `--ref`,
155
+ videos with `--ref-video` and audio with `--ref-audio` (or connect them on the
156
+ canvas); `wji models get` shows each model's caps (e.g. Wan 3.0 Ref: 10 images,
157
+ video/audio ≤ 15 s total).
158
+
159
+ **Video trade-offs** (best first):
160
+
161
+ | | Ranking |
162
+ | --- | --- |
163
+ | **Quality** | Seedance 2.5 › Seedance 2.0 ≈ Wan 3.0 › MiniMax H3 ≈ Seedance 2.0 Fast › MiniMax H3 Max |
164
+ | **Speed** (fastest first) | MiniMax H3 Max › Seedance 2.0 Fast › Wan 3.0 Prime › Seedance 2.0 ≈ Wan 3.0 › Seedance 2.5 |
165
+ | **Price** (cheapest first) | MiniMax H3 Max › Seedance 2.0 Fast › Wan 3.0 Prime › Seedance 2.0 ≈ Wan 3.0 › Seedance 2.5 |
166
+
167
+ So: **Seedance 2.5** for final, hero shots; **Seedance 2.0 / Wan 3.0** as the
168
+ balanced default; **Seedance 2.0 Fast / MiniMax H3 Max** for drafts, tests and
169
+ large batches. The ranking is a guide — quote the real number from
170
+ `wji gen cost` / `wji canvas gen` before spending.
171
+
172
+ ### Limits (per account)
173
+
174
+ | Limit | Value | When exceeded |
175
+ | --- | --- | --- |
176
+ | Submissions per minute | image 30 · video 10 · audio 20 | HTTP 429 |
177
+ | Queued + running jobs | FREE 3 · VIP 10 · SVIP 25 | HTTP 429 `排隊中的任務已達上限` |
178
+
179
+ **Never fire more generations at once than the queue allows.** Submit up to the
180
+ cap, wait for jobs to finish (`wji history get <id> --wait`), then submit the
181
+ next batch. A 429 means the request was rejected before anything was charged —
182
+ wait and resubmit; do not retry in a tight loop.
183
+
184
+ ```bash
185
+ wji history list --mode video
186
+ wji history download <historyId> -o ./out
187
+ ```
188
+
189
+ ## Character datasets
190
+
191
+ A character is only reusable across shots when its dataset carries all three:
192
+
193
+ 1. **Headshot** — a clean front-facing portrait on a plain background (sets
194
+ the face). Make it the dataset's `icon`.
195
+ 2. **Character sheet** — full-body front/side/back turnaround plus a few
196
+ expressions and outfit details, in the same outfit (sets body, clothes and
197
+ consistency). Generate it from the headshot with GPT Image 2.5 Sunburst.
198
+ 3. **Voice** — a short, clean audio sample of the character speaking (sets the
199
+ voice for Ref video models that take `--ref-audio`). Set it as
200
+ `primaryAudio`.
201
+
202
+ All three are assets attached to the dataset node (`images` holds images and
203
+ audio alike). When creating or reviewing a character, check which are missing
204
+ and offer to make them; when generating video of that character, pass the
205
+ headshot and sheet as image references and the voice as an audio reference to
206
+ a Ref model.
207
+
208
+ ```bash
209
+ wji fs get <datasetId> --scope full --json | jq '{images: [.images[]? | {id, type}], icon, primaryAudio}'
210
+ wji fs set <datasetId> --images <headshot> <sheet> <voice> --icon <headshot> --set primaryAudio=<voice>
211
+ ```
212
+
213
+ `--images` replaces the whole list — read the current list first and keep
214
+ what is already there.
215
+
216
+ ## Assets
217
+
218
+ ```bash
219
+ wji asset upload ./ref.png # returns an asset id
220
+ wji asset import https://example.com/x.jpg
221
+ wji asset status <id> <id> # pending | ready | cancelled
222
+ wji asset download <id> [<id>…] -o ./out # keeps the file extension, so you can view images
223
+ ```
224
+
225
+ - Uploaded assets attach to the default workspace unless you pass `--workspace`.
226
+ - `asset status` only returns assets you created or that sit in a workspace
227
+ you belong to; other ids are silently omitted (the CLI warns how many).
228
+ - `asset import` refuses private and internal addresses (`不允許存取該主機`).
229
+ Some public hosts also block server-side downloads (`無法下載或處理該圖片 URL`)
230
+ — download the file yourself and `wji asset upload` it instead.
231
+ - `.html`, `.svg` and script uploads are stored as `application/octet-stream`
232
+ and served as attachments, so they will not render inline.
233
+
234
+ ## Skills
235
+
236
+ Skills are SKILL.md bundles. **System skills** are built-in and read-only;
237
+ **user skills** are yours to author and attach to agents. Only `.md` files
238
+ persist server-side — scripts belong to system skills.
239
+
240
+ ```bash
241
+ wji skill system # built-in skills you can attach
242
+ wji skill push ./my-skill # zip a local folder (SKILL.md at root) and upload
243
+ wji skill list
244
+ wji skill pull <id> ./my-skill # write a bundle back to disk to edit it
245
+ wji skill get <id> # metadata + file list
246
+ ```
247
+
248
+ Attach skills to an agent and manage its version history:
249
+
250
+ ```bash
251
+ wji agent skill-add <agentId> system:image user:<skillId>
252
+ wji agent skills <agentId>
253
+ wji agent versions <agentId> # every edit auto-snapshots a version
254
+ wji agent restore <agentId> <versionId>
255
+ ```
256
+
257
+ Skill refs are `system:<key>` or `user:<skillId>` (a bare id means `user:`).
258
+ System keys currently include `image`, `document`, `workspace-dataset`,
259
+ `canvas` and `seedance-25` — confirm with `wji skill system`.
260
+ When authoring, edit a pulled folder and `skill push` it again, or
261
+ `skill update <id> --dir ./my-skill` to replace its files.
262
+
263
+ Bundle limits: at most 200 markdown files, 2MB per file, 20MB in total and a
264
+ 5MB zip; 50 user skills per account. `skill update --dir` sends files in the
265
+ request body, where each file is capped far lower, at **200,000 characters** —
266
+ use `skill push` for large files.
267
+
268
+ ## Canvas
269
+
270
+ An Infinite Canvas holds **nodes** (text, title, comment, image, video, audio…)
271
+ and **edges** between them. An edge into a media node makes the source one of
272
+ its **references**, numbered per kind in edge order: `@image1`, `@image2`,
273
+ `@video1`. A media node is either a **display** node (shows an existing asset)
274
+ or a **generate** node (prompt + model + settings; generating fills in its
275
+ asset).
276
+
277
+ **The link.** The user opens a canvas in the browser and presses the link
278
+ button in its top bar. That stores the open workspace, canvas and **the nodes
279
+ they have selected** on their account for 5 minutes (the tab renews it while
280
+ open). Every `wji canvas` command then targets that canvas; pass
281
+ `--canvas <id>` to work on another one (`wji canvas list`).
282
+
283
+ ```bash
284
+ wji canvas status # linked canvas + selected nodes (ids, asset URLs, settings)
285
+ wji canvas nodes # every node; * marks generate nodes
286
+ wji canvas get <nodeId> # full detail incl. references
287
+ wji asset download <assetId…> -o <dir> # then look at the images yourself
288
+
289
+ wji canvas add video --from <imgNode> <imgNode> -m <model> -r 16:9 -d 8 -p "@image1 … @image2 …"
290
+ wji canvas add text -t "shot list…" --at 0,600
291
+ wji canvas set <nodeId> -p "new prompt" # merges: other settings stay
292
+ wji canvas set <nodeId> -m <model> --resolution 720p --set seed=42
293
+ wji canvas connect <from> <to> / wji canvas disconnect <from> <to>
294
+ wji canvas gen <nodeId> --wait # costs credits — see Rules
295
+ wji canvas rm <nodeId…> # destructive — see Rules
296
+ ```
297
+
298
+ - **Match the CLI to the site the user is on before anything else.** The
299
+ link is stored on the backend the browser talks to, so the CLI must use the
300
+ same one. `Cannot GET /canvas-link` (404) means the active profile points at
301
+ a backend without this feature — typically profile `prod`
302
+ (`https://api.wji.ai`) while the user linked on `http://localhost:3000`
303
+ (API `http://localhost:3002`). Check `wji config show`, then tell the user
304
+ which profile to use (`wji config use <profile>`), or run the commands with
305
+ `WJI_ENDPOINT=… WJI_API_KEY=…` for that backend. Don't switch their
306
+ profile silently, and never run canvas commands against production when the
307
+ link URL is localhost.
308
+ - If `status` says *Not linked*, ask the user to open the canvas and press the
309
+ link button (and to select the nodes they mean). Don't guess a canvas.
310
+ - The selection is **what the user means by "these" / "the selected images"**.
311
+ Use those node ids for `--from`; use each node's `assetId` to download and
312
+ look at the picture before writing a prompt about it.
313
+ - Prompts are literal: `-p "@image1 …"` is text, not a file. Use
314
+ `--prompt-file` for a file and `-p -` for stdin.
315
+ - Pick the model from `wji models list --feature video` and read
316
+ `wji models get <model>` for its ratios, duration range and `--set` keys.
317
+ `add`/`set` validate against it, fill the model's defaults, and turn
318
+ auto-duration off when you pass `-d`.
319
+ - **A model the user names may not accept references.** Check the REFS column
320
+ of `wji models list`: a family often has a text-only model and a `Ref`
321
+ variant (`Wan 3.0` has none, `Wan 3.0 Ref` takes up to 10). If the request
322
+ builds on selected images, use the variant with references and say so —
323
+ otherwise the selection is silently ignored and the person or object in the
324
+ video will not match.
325
+ - Model nicknames can contain spaces (`"Wan 3.0 Ref"`) — quote them.
326
+ Parameter values are case-sensitive and differ per model (`480P` for Wan,
327
+ `480p` for Seedance); copy them from `wji models get`.
328
+ - Defaults you did not ask about still shape the result: the ratio falls back
329
+ to the workspace's (often 16:9 — ask or pick 9:16 for a portrait-style clip),
330
+ `audio` may default on, and **auto-duration** lets the model choose the
331
+ length. With auto-duration the cost `canvas gen` shows is an estimate for
332
+ the node's configured seconds; the final charge follows the real length.
333
+ Mention these when you report the node, and pass `-d` if the user needs a
334
+ fixed length or a fixed price.
335
+ - Take new ids from the command's own output (`wji --json canvas add … | jq
336
+ -r .id`), not by searching names — names repeat on a canvas. In zsh a
337
+ variable holding several ids is not word-split; pass the ids literally.
338
+ - Changes show up live in the user's open canvas; there's no need to ask them
339
+ to reload.
340
+ - `canvas gen` sends exactly what the canvas's own Generate button sends
341
+ (references in order, text-node references prefixed to the prompt). Nodes
342
+ referencing dataset, bundle, table or YouTube nodes must be generated from
343
+ the browser.
344
+
345
+ See `reference/canvas-recipes.md` for end-to-end examples.
346
+
347
+ ## Everything else
348
+
349
+ ```bash
350
+ wji preset list -k "hero" # usable presets; also `mine`, `public`, `workspace`
351
+ wji preset get <id> --json | jq -r .prompt
352
+ wji agent list # marketplace; `wji agent mine` for yours
353
+ wji profile show
354
+ wji profile wallet # credit balance before an expensive batch
355
+ wji org list && wji org use <orgId>
356
+ ```
357
+
358
+ ## Rules
359
+
360
+ - **Confirm before destroying — in the conversation, one target at a time.**
361
+ These commands delete, revoke or overwrite, and none can be undone from the
362
+ CLI: `ws rm`, `ws app rm`, `ws member rm`, `fs rm`, `dataset rm`,
363
+ `asset rm`, `history rm`, `preset rm`, `skill rm`, `skill update --dir`,
364
+ `agent rm`, `auth key rm`, `auth key revoke`, `config rm`, `canvas rm`.
365
+ They prompt `[y/N]` in a terminal, but when you run them there is no
366
+ terminal, so they refuse unless you pass `--yes`. **The user's reply in the
367
+ chat is the only confirmation there is.** Before running one:
368
+ 1. Look the target up and tell the user exactly what will go — name and id,
369
+ plus what goes with it: a workspace's apps and files, a folder's whole
370
+ subtree, the files `skill update --dir` replaces, anything still using an
371
+ API key, the credentials stored in a profile, the connections a canvas
372
+ node takes with it.
373
+ 2. Wait for an explicit yes to *those* targets. A broad instruction such as
374
+ "clean up" or "delete the old ones" is not approval: list what you found
375
+ and ask.
376
+ 3. Only then pass `--yes`. The approval covers the targets you listed, not
377
+ anything you find afterwards — new targets need a new question.
378
+ - **Overwrites don't prompt at all.** `fs set --content`, `--images` and
379
+ `--tags`, and the update commands' tag options, replace the whole value.
380
+ Read the current value first, and check with the user before replacing
381
+ anything they did not ask to change.
382
+ - **Generation costs credits.** Run `wji gen cost` first for anything large
383
+ (high `-n`, long video), show the user the number, and get agreement before
384
+ submitting a batch. `wji canvas gen` prints its exact cost and refuses
385
+ without `--yes`: run it once without `--yes` to get the number, tell the
386
+ user, and pass `--yes` only after they agree. Creating or editing a generate
387
+ node (`canvas add` / `canvas set`) costs nothing.
388
+ - **Never invent ids.** Look up workspace, node, asset and model ids with the
389
+ list commands; ids are Mongo ObjectIds, not names.
390
+ - **Stay inside the generation queue.** See *Limits* above — batch to the cap
391
+ and wait for completions rather than retrying 429s.
392
+ - **Lists are paginated.** `--limit` is capped at 100; `--limit -1` returns at
393
+ most 500 on most endpoints. Page with `--page` instead of assuming you got
394
+ everything.
395
+ - **Report failures honestly.** A failed generation surfaces as a non-zero exit
396
+ with the provider's message — pass it on rather than retrying silently.
397
+
398
+ See `reference/commands.md` for the full command and flag inventory.
@@ -0,0 +1,179 @@
1
+ # Canvas recipes
2
+
3
+ Worked examples for `wji canvas`. Each starts from the same place: the user has
4
+ the canvas open in the browser, has pressed the **link** button in its top bar,
5
+ and has selected the nodes they are talking about.
6
+
7
+ ```bash
8
+ wji canvas status # confirms the link and lists the selected nodes
9
+ ```
10
+
11
+ If it says *Not linked*, ask the user to press the link button (and select the
12
+ nodes) instead of guessing. If it fails with `Cannot GET /canvas-link`, the CLI
13
+ profile points at a different backend than the browser (e.g. `prod` while the
14
+ link URL is `localhost:3000`) — fix the profile first (see SKILL.md, Canvas).
15
+ The link lasts 5 minutes after the tab stops renewing it, so re-check `status`
16
+ if the user comes back later.
17
+
18
+ All ids below are placeholders — always take them from `status`, `nodes` or
19
+ `get`.
20
+
21
+ ---
22
+
23
+ ## 1. Selected images → suggest a video prompt → create the video node
24
+
25
+ > "Use the images I selected to make a video node. Suggest a prompt first."
26
+
27
+ 1. Read the selection and keep the image nodes, in the order the user
28
+ selected them (that becomes `@image1`, `@image2`):
29
+
30
+ ```bash
31
+ wji canvas status --json | jq '.selected[] | select(.kind=="image") | {id, name, assetId}'
32
+ ```
33
+
34
+ 2. Look at the pictures before writing about them:
35
+
36
+ ```bash
37
+ wji asset download <assetId1> <assetId2> -o /tmp/canvas-refs
38
+ ```
39
+
40
+ Open the downloaded files and describe what is actually there — subject,
41
+ setting, light, mood.
42
+
43
+ 3. Pick a model that takes image references and read its limits:
44
+
45
+ ```bash
46
+ wji models list --feature video -k <family> # REFS column must be non-empty
47
+ wji models get "<model>" # ratios, duration range, max references, --set keys (exact case)
48
+ ```
49
+
50
+ If the user asked for a model by family name ("wan 3.0", "seedance"), choose
51
+ the member that accepts references (`Wan 3.0 Ref`, `seedance-2.0-fast-ref`)
52
+ and tell them why.
53
+
54
+ 4. Settle the settings the user didn't mention: ratio (workspace default vs.
55
+ 9:16 for a portrait subject), fixed duration or auto, audio. Then propose
56
+ 2–3 prompts in the chat. Refer to the images as `@image1`,
57
+ `@image2`, matching the order you will connect them. Mention the model,
58
+ ratio and duration you would use. Wait for the user to pick or edit one.
59
+
60
+ 5. Create the node. Nothing is charged yet:
61
+
62
+ ```bash
63
+ wji canvas add video -n "Lake reunion" \
64
+ --from <imageNode1> <imageNode2> \
65
+ -m <model> -r 16:9 -d 8 --resolution 720p \
66
+ -p "@image1 paddles a canoe across a still turquoise lake at dawn; as she reaches the shore, @image2 trots down the forest path to greet her. Soft morning light, reflections, shallow depth of field."
67
+ ```
68
+
69
+ The node appears next to the images in the user's canvas, wired to both,
70
+ with the prompt and settings filled in. Tell the user its name and that it is
71
+ ready to generate from the canvas or from here (recipe 4).
72
+
73
+ ## 2. Write or rewrite the prompt of an existing generate node
74
+
75
+ > "This video node has two references wired in — write a better prompt for it."
76
+
77
+ ```bash
78
+ wji canvas get <videoNode> # prompt, model, settings, references with labels
79
+ wji canvas get <referenceNode> # for each reference: kind, assetId, text
80
+ wji asset download <assetId…> -o /tmp/canvas-refs
81
+ ```
82
+
83
+ Draft the prompt against the **labels `get` printed** (`@image1 ← <nodeId>`),
84
+ not against the order the user happened to mention things. Then:
85
+
86
+ ```bash
87
+ wji canvas set <videoNode> -p "…" # only the prompt changes; model and settings stay
88
+ ```
89
+
90
+ Text nodes connected into a generate node are sent ahead of the prompt as
91
+ `[node name]` + text. Don't repeat their content in the prompt.
92
+
93
+ ## 3. Change generation settings
94
+
95
+ > "Make it vertical, 10 seconds, 720p, and fix the seed."
96
+
97
+ ```bash
98
+ wji models get <model> # check 9:16 exists, duration range, seed key
99
+ wji canvas set <node> -r 9:16 -d 10 --resolution 720p --set seed=1234
100
+ ```
101
+
102
+ `set` rejects values the model does not support and names the valid ones. It
103
+ merges `--set` into the existing parameters. Passing `-d` switches the
104
+ model's auto-duration off.
105
+
106
+ To switch model, pass `-m`. Settings the new model does not support fall back to
107
+ its defaults; check with `wji canvas get <node>` and tell the user what changed.
108
+
109
+ ## 4. Generate directly
110
+
111
+ > "Go ahead and generate it."
112
+
113
+ ```bash
114
+ wji canvas gen <node> # prints the cost and refuses (no terminal)
115
+ ```
116
+
117
+ Tell the user the cost from that message. With auto-duration it is an
118
+ estimate for the node's configured seconds; say so, or set `-d` first for a
119
+ fixed price. Only after they agree:
120
+
121
+ ```bash
122
+ wji canvas gen <node> --yes --wait
123
+ ```
124
+
125
+ The result becomes the node's asset, so the user sees it on the canvas. Video
126
+ can take minutes: with a long wait, prefer submitting without `--wait` and
127
+ checking `wji canvas get <node>` (status `generating` → `done`/`failed`) later.
128
+ Never resubmit a node whose status is `generating` — that charges twice.
129
+
130
+ ## 5. Storyboard fan-out
131
+
132
+ > "Here are my two character images. Make one video node per shot for this
133
+ > 4-shot scene."
134
+
135
+ 1. Write the shot list in the chat and agree on it.
136
+ 2. Optionally drop the script on the canvas:
137
+
138
+ ```bash
139
+ wji canvas add text -n "Scene 3 shots" -t - < shots.txt
140
+ ```
141
+
142
+ 3. One generate node per shot, all wired to the same character images. Each
143
+ node is placed beside the references and below the previous one:
144
+
145
+ ```bash
146
+ wji canvas add video -n "Shot 1" --from <char1> <char2> -m <model> -r 16:9 -d 5 -p "…shot 1…"
147
+ wji canvas add video -n "Shot 2" --from <char1> <char2> -m <model> -r 16:9 -d 5 -p "…shot 2…"
148
+ ```
149
+
150
+ 4. Total the cost (`wji canvas gen <node>` for each, without `--yes`) before
151
+ offering to generate them all.
152
+
153
+ ## 6. Fix which image is `@image1`
154
+
155
+ References are numbered in connection order. To swap `@image1` and `@image2`,
156
+ reconnect the first one so it moves to the end:
157
+
158
+ ```bash
159
+ wji canvas get <node> # @image1 ← A, @image2 ← B
160
+ wji canvas disconnect <A> <node>
161
+ wji canvas connect <A> <node> # now @image1 ← B, @image2 ← A
162
+ wji canvas set <node> -p "…" # update the prompt to the new labels
163
+ ```
164
+
165
+ ## 7. Image variation from a selected image
166
+
167
+ > "Make a watercolor version of the selected photo."
168
+
169
+ ```bash
170
+ wji canvas add image -n "Watercolor" --from <photoNode> -m <imageModel> -r 16:9 \
171
+ -p "Turn @image1 into a soft watercolor illustration, keep the composition"
172
+ wji canvas gen <newNode> # cost → user agrees → --yes --wait
173
+ ```
174
+
175
+ ## Cleaning up
176
+
177
+ `wji canvas rm` deletes nodes and every connection touching them. It is on the
178
+ confirm list: name the nodes (and how many connections go with them) in the
179
+ chat, wait for a yes, then pass `--yes`.