@wji.ai/cli 0.4.0 → 0.5.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 (58) hide show
  1. package/README.md +48 -2
  2. package/dist/commands/backreel.js +260 -0
  3. package/dist/commands/canvas.js +588 -88
  4. package/dist/commands/class.js +395 -0
  5. package/dist/commands/npc.js +413 -0
  6. package/dist/commands/workspace.js +109 -24
  7. package/dist/core/members.js +54 -0
  8. package/dist/core/npc.js +108 -0
  9. package/dist/core/output.js +4 -2
  10. package/dist/index.js +8 -0
  11. package/package.json +1 -1
  12. package/skill/short-drama/SKILL.md +86 -8
  13. package/skill/short-drama/reference/action-bullet-time.md +47 -0
  14. package/skill/short-drama/reference/action-car-chase.md +51 -0
  15. package/skill/short-drama/reference/action-gun-fu.md +52 -0
  16. package/skill/short-drama/reference/action-historical-realist.md +50 -0
  17. package/skill/short-drama/reference/action-hk-kungfu.md +54 -0
  18. package/skill/short-drama/reference/action-street-brawl.md +49 -0
  19. package/skill/short-drama/reference/action-superhero.md +50 -0
  20. package/skill/short-drama/reference/action-wuxia-fantasy.md +51 -0
  21. package/skill/short-drama/reference/action.md +94 -0
  22. package/skill/short-drama/reference/cinematography-costume-dark.md +117 -0
  23. package/skill/short-drama/reference/cinematography-costume-idol.md +126 -0
  24. package/skill/short-drama/reference/cinematography-low-key.md +115 -0
  25. package/skill/short-drama/reference/cinematography-period-nostalgia.md +106 -0
  26. package/skill/short-drama/reference/cinematography-scifi-hard.md +63 -0
  27. package/skill/short-drama/reference/cinematography-scifi-soft.md +66 -0
  28. package/skill/short-drama/reference/cinematography-sweet-romance.md +175 -0
  29. package/skill/short-drama/reference/cinematography.md +83 -0
  30. package/skill/short-drama/reference/composition-art-first.md +74 -0
  31. package/skill/short-drama/reference/craft-shots.md +3 -1
  32. package/skill/short-drama/reference/craft-story.md +4 -1
  33. package/skill/short-drama/reference/format.md +94 -0
  34. package/skill/short-drama/reference/grammar-comedy.md +105 -0
  35. package/skill/short-drama/reference/grammar-faceslap.md +67 -0
  36. package/skill/short-drama/reference/grammar.md +103 -0
  37. package/skill/short-drama/reference/operations-cli.md +1 -1
  38. package/skill/short-drama/reference/schema.md +34 -3
  39. package/skill/short-drama/reference/stage-art.md +1 -1
  40. package/skill/short-drama/reference/stage-outline.md +21 -0
  41. package/skill/short-drama/reference/stage-script.md +10 -0
  42. package/skill/short-drama/reference/stage-storyboard.md +15 -0
  43. package/skill/short-drama/reference/story-angst.md +117 -0
  44. package/skill/short-drama/reference/story-comedy.md +136 -0
  45. package/skill/short-drama/reference/story-cultivation.md +109 -0
  46. package/skill/short-drama/reference/story-family.md +119 -0
  47. package/skill/short-drama/reference/story-horror.md +124 -0
  48. package/skill/short-drama/reference/story-mystery.md +127 -0
  49. package/skill/short-drama/reference/story-palace.md +103 -0
  50. package/skill/short-drama/reference/story-revenge.md +124 -0
  51. package/skill/short-drama/reference/story-scifi.md +112 -0
  52. package/skill/short-drama/reference/story-sweet.md +128 -0
  53. package/skill/short-drama/reference/story.md +127 -0
  54. package/skill/short-drama/scripts/selftest.mjs +809 -1
  55. package/skill/short-drama/scripts/short-drama.mjs +1608 -16
  56. package/skill/wji/SKILL.md +66 -2
  57. package/skill/wji/reference/commands.md +76 -15
  58. package/skill/wji-classroom/SKILL.md +161 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
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), manage workspace members, invitations and canvas owners, manage NPC City NPCs (profile, work history, soul, character document) and Backreel posts (drafts, publishing, cast and crew credits), and manage models, agents, prompt presets and your profile. Use whenever a task mentions WJI, wji-backend, a WJI workspace, canvas, fsnode, dataset node, NPC City, an NPC / resident, Backreel, or asks to generate media on WJI.
4
4
  ---
5
5
 
6
6
  # WJI CLI
@@ -332,6 +332,19 @@ A workspace's InfiniteCanvas app can hold several canvases (`wji canvas list`);
332
332
  `wji canvas create <name>` adds an empty one — e.g. one canvas per episode or
333
333
  per character set.
334
334
 
335
+ **Ownership.** A canvas can have an owner (a workspace member) and a
336
+ visibility: `members` (everyone in the workspace sees it) or `owner` (only
337
+ the owner and the workspace owner). `wji canvas list` shows both;
338
+ `wji canvas owner <canvasId> <member> --visibility owner` sets them — the
339
+ workspace owner only. Visibility hides, it does not lock: on a `members`
340
+ canvas any editor can edit. For a class of students (one canvas each, copy
341
+ work to all, collect results) use `wji class` — see the `wji-classroom` skill.
342
+
343
+ **Color tags.** `wji canvas tag red <nodeIds…> -l HW1` tags nodes and names
344
+ the color on that canvas; `--tag HW1` then filters `canvas nodes`,
345
+ `class status` and `class results`. `wji canvas copy <nodeIds…> --to
346
+ <canvasId…>` copies nodes with their connections and tags to other canvases.
347
+
335
348
  **The link.** The user opens a canvas in the browser and presses the link
336
349
  button in its top bar. That stores the open workspace, canvas and **the nodes
337
350
  they have selected** on their account for 5 minutes (the tab renews it while
@@ -414,6 +427,55 @@ wji canvas rm <nodeId…> # destructive — see Rules
414
427
 
415
428
  See `reference/canvas-recipes.md` for end-to-end examples.
416
429
 
430
+ ## NPC City and Backreel
431
+
432
+ **NPC City NPCs** (residents) belong to you, or to an organization when you
433
+ pass `--org`. Refer to one by id, `@handle` or name; an `@handle` that isn't
434
+ yours resolves in the public directory (read-only for you).
435
+
436
+ ```bash
437
+ wji npc list # yours; --public for the directory
438
+ wji npc get @mika # profile + numbered work history
439
+ wji npc create "Mika" --role Singer --genre "City pop" --handle mika.npc # private draft
440
+ wji npc set @mika --tagline "…" --tag tier=Rising --social ig=https://…
441
+ wji npc publish @mika # visibility public (unpublish = private)
442
+ wji npc job add @mika -t concert --title "Neon Night" --date 2026-10-01 --location Taipei
443
+ wji npc job set @mika 2 --detail "sold out" ; wji npc job rm @mika 3 -y
444
+ wji npc soul get @mika > soul.json ; wji npc soul set @mika '{"voice":{…}}'
445
+ wji npc doc export @mika -o mika.md # whole character in one file
446
+ wji npc doc apply @mika @mika.md --dry-run # see the diff, then without --dry-run
447
+ ```
448
+
449
+ - **Jobs** are the NPC's work history (concert, release, collaboration, brand,
450
+ event, ad, appearance) shown on its public page. They have no ids: the CLI
451
+ numbers them 1…n and rewrites the whole list, so list again before `job
452
+ set` / `job rm` if anything else may have changed it.
453
+ - `soul set` merges top-level keys only; a nested object you pass replaces
454
+ that whole key. Memories and albums are not part of the soul.
455
+ - `npc create` needs NPC City spawn permission on the account (a 403 says so);
456
+ only an admin can grant it. Admin actions — spawn permission, featured / hero
457
+ slider, moderation — are not in `wji`.
458
+ - `npc transfer send <npc> --to <email>` offers the NPC to someone; they
459
+ `npc transfer accept <id>` within 7 days. You lose it on acceptance.
460
+
461
+ **Backreel posts** are your film / project pages. `create` always makes a
462
+ draft; publishing needs a cover, media or an episode.
463
+
464
+ ```bash
465
+ wji backreel list # yours, drafts included; --all for published posts
466
+ wji backreel create "Harbour" -d @synopsis.txt --tags drama,short --cover <assetId>
467
+ wji backreel set <postId> --project-status in_production
468
+ wji backreel credit add <postId> --kind creative --name "Wayne" --role 導演
469
+ wji backreel credit add <postId> --npc @mika --role "飾 阿明" --job appearance
470
+ wji backreel publish <postId> # unpublish takes it offline
471
+ ```
472
+
473
+ - Credits (max 30) are rewritten whole in order; `credit rm` goes by number.
474
+ - `--npc` casts an NPC (the credit's `npcId`, name and avatar come from it);
475
+ `--job <type>` also adds the work to that NPC's history — only for your own
476
+ NPCs.
477
+ - `--description` takes plain text (turned into paragraphs) or HTML.
478
+
417
479
  ## Everything else
418
480
 
419
481
  ```bash
@@ -431,7 +493,9 @@ wji org list && wji org use <orgId>
431
493
  These commands delete, revoke or overwrite, and none can be undone from the
432
494
  CLI: `ws rm`, `ws app rm`, `ws member rm`, `fs rm`, `dataset rm`,
433
495
  `asset rm`, `history rm`, `preset rm`, `skill rm`, `skill update --dir`,
434
- `agent rm`, `auth key rm`, `auth key revoke`, `config rm`, `canvas rm`.
496
+ `agent rm`, `auth key rm`, `auth key revoke`, `config rm`, `canvas rm`,
497
+ `ws member link` (revokes the current share link), `npc rm`, `npc job rm`,
498
+ `npc doc apply`, `npc transfer send`, `backreel rm`, `backreel credit rm`.
435
499
  They prompt `[y/N]` in a terminal, but when you run them there is no
436
500
  terminal, so they refuse unless you pass `--yes`. **The user's reply in the
437
501
  chat is the only confirmation there is.** Before running one:
@@ -73,7 +73,11 @@ switch endpoint.
73
73
  | `ws favorite <id> [--off]` | `PUT /workspace/list/:id/favorite` |
74
74
  | `ws fs [id] [-a appId]` | `GET /workspace/list/:id/fs[/:appid]` |
75
75
  | `ws app list\|add <app> [-n]\|rm <appId> [-y]` | `POST/DELETE /workspace/list/:id/apps` |
76
- | `ws member list\|add <userId> [-r role]\|role <memberId> <role>\|rm <memberId> [-y]` | `/workspace/list/:id/member/*` |
76
+ | `ws member list [id] [-r role]` | members from `GET /workspace/list/:id` (there is no member-list endpoint): name, email, role, user id, membership id |
77
+ | `ws member add <userIds...> [-r editor\|viewer] [-w]` | `POST .../member/add-batch {users, role}` (≤50; existing members skipped). Org workspaces accept only org members |
78
+ | `ws member invite <emails...> [-r editor\|viewer] [-w]` | `POST /invitation/workspace/:id/invite-emails` (owner only, ≤50; commas/spaces split). Registered users are **added at once**, others get an emailed invitation — which also revokes the current share link. Reports added / invited / skipped / invalid |
79
+ | `ws member link [id] [-r role] [--show]` | `POST /invitation/create {targetType:'workspace', targetId, role}` (owner only; valid 7 days — the server rejects any `expiredAt`). One active link per workspace — a new one revokes the old. `--show` lists the active link (`GET /invitation/workspace/:id`) |
80
+ | `ws member role <member> <editor\|viewer> [-w]` / `ws member rm <members...> [-w] [-y]` | `PUT .../member/:memberId/role`, `DELETE .../member/:memberId`. `<member>` is a name, email, user id or membership id (ambiguous names are an error); the owner is refused. A removed member's canvases stay |
77
81
  | `ws quota [id] [--set k=v]` | `GET .../quota-usage`, `PUT .../quota` |
78
82
  | `ws stats [id]` | `GET /workspace/list/:id/stats` |
79
83
  | `ws templates` / `ws clone <templateId>` | `GET /workspace/start/templates`, `POST /workspace/create/:id` |
@@ -160,14 +164,17 @@ updates live.
160
164
  | --- | --- |
161
165
  | `canvas status` (`link`) | `GET /canvas-link`, then the selected nodes read fresh from the canvas |
162
166
  | `canvas unlink` | `DELETE /canvas-link`; the tab turns its button off at its next heartbeat (≤ 60s) |
163
- | `canvas list [-w]` | canvases under each InfiniteCanvas app: `GET /workspace/list/:id/fs/:appId` → `workspace-v2/canvases` children |
164
- | `canvas create <name> [-w] [--app]` | `POST /fsnode/create` a `workspace-v2/canvas` folder under that `canvases` folder with the web's initial content (`{data:{viewport, backgroundMode:'dots'}, metadata:{}}`) |
167
+ | `canvas list [-w] [-o member\|none]` | canvases under each InfiniteCanvas app: `GET /workspace/list/:id/fs/:appId` → `workspace-v2/canvases` children, with owner and visibility from `content.metadata`. Owner-only canvases of others are hidden unless you own the workspace |
168
+ | `canvas create <name> [-w] [--app] [-o member] [--visibility owner\|members]` | `POST /fsnode/create` a `workspace-v2/canvas` folder under that `canvases` folder with the web's initial content (`{data:{viewport, backgroundMode:'dots'}, metadata:{ownerUserId?, visibility?}}`) |
169
+ | `canvas owner <canvasId> [member] [--visibility owner\|members] [--none]` | without options shows owner + visibility; otherwise `PATCH /fsnode/list/:id` with the whole envelope `{data, metadata}` and `baseUpdatedAt` (retried on 409). **Workspace owner only** (403 otherwise). `owner` visibility = only the owner and the workspace owner see the canvas; it hides, it does not lock — with `members` any editor can edit it |
170
+ | `canvas tag <tag> [nodeIds...] [-c] [-l label] [--selected]` | sets `content.colorTag {colorId}` on the nodes (`contentPatch`); `none` removes it. `<tag>` is a color, color id or existing label. `-l` writes the color's label to the canvas folder `content.data.colorTagNames` (`""` clears) |
171
+ | `canvas copy [nodeIds...] --to <canvasIds...> [-c] [--selected] [--at x,y] [--same-position] [-y]` | the canvas's own copy-paste: new nodes (no position, `generate.historyId/pendingAssetId` dropped, finished asset shared via `file`), edges among them re-created oldest first so `@image1…` numbering holds, color tags kept and a missing label carried to the target. Edges from nodes outside the copy are left out. Default placement: right of what is already on the target |
165
172
  | `canvas nodes [-c] [-k kind] [-n regex] [--tag tags…\|--untagged]` | `GET /fsnode/list/:canvasId/children?limit=-1` + `POST /assets/check-status`. `-n` matches the node name as a case-insensitive regex (`/re/flags` to set flags yourself). `--tag` takes a label (`C01`, case-insensitive), a color (`red`) or a color id (`rose`); several values match any. Filters combine (AND) |
166
173
  | `canvas tags [-c] [-a]` | the canvas's color tags: color, label, node count (`-a` also unused, unlabelled colors) |
167
174
  | `canvas get <nodeId> [-c]` | same load; one node with references (`@image1 ← id`) and frame slots |
168
175
  | `canvas edges [-c] [--node]` | the `canvas/edge` children |
169
176
  | `canvas add <kind> [-c] [-n] [-t\|--text-file] [--plain] [--size w,h] [--asset] [--dataset] [-p\|--prompt-file] [-m] [-r] [--resolution] [-d] [--set] [--from ids…] [--at x,y]` | `POST /fsnode/create` (`canvas/node/<kind>`), then one `canvas/edge` per `--from`. Kinds: text, title, comment, image, video, audio, dataset. `add dataset --dataset <fsnodeId>` writes `content {datasetId, datasetName, datasetType, datasetParentName, description}` from the dataset node (must be `workspace/dataset`); it takes no `--from`. Text kinds are Markdown on the web; `--plain` turns every single line break into a Markdown hard break (`" \n"`, fenced code untouched), and without it the CLI warns when a single break would be joined. `--size` writes `content.width/height` |
170
- | `canvas set <nodeId> [-c] [-n] [-t\|--text-file] [--plain] [--move x,y] [--size w,h] [-p] [-m] [-r] [--resolution] [-d] [--set]` | read → merge → `PATCH /fsnode/list/:id` |
177
+ | `canvas set <nodeId> [-c] [-n] [-t\|--text-file] [--plain] [--move x,y] [--size w,h] [-p] [-m] [-r] [--resolution] [-d] [--set]` | read → merge → `PATCH /fsnode/list/:id` with `contentPatch` of only the top-level keys that changed, so a concurrent browser edit of another key survives (falls back to a whole-content write on a backend without `contentPatch`) |
171
178
  | `canvas connect <from> <to> [-c]` | `POST /fsnode/create` (`canvas/edge`); a first/last-frame video model gets `videoFrameSlot` start, then end |
172
179
  | `canvas disconnect <from> <to> [-c]` | `DELETE /fsnode/list/:edgeId` |
173
180
  | `canvas rm <nodeIds...> [-c] [-y]` | deletes the nodes' edges, then the nodes; refuses nodes still generating |
@@ -209,6 +216,71 @@ viewport, url}` on toggle (`takeover: true`), on selection change and every
209
216
  60s. A non-takeover `PUT` from a tab that no longer owns the link gets
210
217
  `409 canvas-link-gone`, which switches that tab's button off.
211
218
 
219
+ ## class
220
+
221
+ A class is a workspace the teacher owns; students are members (editors) and
222
+ each student's canvas is the one whose `metadata.ownerUserId` is them. Every
223
+ command takes `-w` (defaults to the linked workspace, then the profile's).
224
+
225
+ | Command | API / behaviour |
226
+ | --- | --- |
227
+ | `class roster` | members minus the owner, with role and owned canvases |
228
+ | `class canvases [--create] [--visibility owner\|members] [--update] [--name '{name}'] [--student …] [--app]` | lists each student's canvas; `--create` makes the missing ones (`POST /fsnode/create`, owner = student, default visibility `owner`); `--update` applies `--visibility` to existing ones. Idempotent |
229
+ | `class copy [nodeIds...] [-c] [--selected] [--student …] [--at x,y] [--same-position] [-y]` | `canvas copy` into every student canvas (default: the linked selection); 4 canvases at a time; failures reported per student with a rerun hint, exit 1 |
230
+ | `class status [--tag …] [-k kind] [--student …] [-s name\|recent\|progress]` | per student: nodes, generate nodes done / running / failed / not run, `GET /ai/assets/history/search?scope=canvas&scopeId=<canvas>&limit=1&sort[createdAt]=desc` for count + last generation, credits from `GET .../quota-usage` `byUserTotal` |
231
+ | `class results [--student …] [--tag …] [-k kind] [-n regex] [--since 2h] [--all] [-s recent\|name] [-l n] [-d dir]` | finished media on student canvases (generate nodes; `--all` adds display nodes), newest first; `-d` saves `<dir>/<student>/<node>-<id>.<ext>` |
232
+
233
+ `--tag` matches each canvas's own label (a label a canvas lacks matches nothing
234
+ there); `--student` takes names, emails or user ids.
235
+
236
+ ## npc
237
+
238
+ `<npc>` is an id, `@handle` or name among your NPCs (org NPCs with `--org`); an
239
+ unknown `@handle` falls back to `GET /npc-city/residents/by-handle/:h` (public).
240
+
241
+ | Command | API |
242
+ | --- | --- |
243
+ | `npc list [--public] [-k] [--status active\|debut\|hiatus] [--visibility] [--page] [--limit]` | `GET /npc-city/residents/mine` (`--public`: `GET /npc-city/residents`) |
244
+ | `npc get <npc>` | `GET /npc-city/residents/:id` |
245
+ | `npc create <name> --role --genre [--handle] [--tagline] [--bio] [--image url\|assetId] [--hero-image] [--color] [--status] [--visibility] [--social k=url…] [--tag k=v…] [--set k=v…]` | `GET …/handle-available`, then `POST /npc-city/residents` (needs profile `canSpawn`; private by default; name is uppercased) |
246
+ | `npc set <npc> [-n] [--role] [--genre] [same flags]` | `PATCH /npc-city/residents/:id` with only the given fields; `--social` / `--tag` merge into the current objects |
247
+ | `npc publish <npc>` / `npc unpublish <npc>` | `PATCH … {visibility}` |
248
+ | `npc rm <npc> [-y]` | `DELETE /npc-city/residents/:id` (soft delete) |
249
+ | `npc handle <handle> [--exclude <npc>]` | `GET /npc-city/residents/handle-available` |
250
+ | `npc job list <npc>` | the resident's `jobs[]`, numbered 1…n |
251
+ | `npc job add <npc> -t <type> --title --date YYYY-MM-DD [--detail] [--location] [--url]` | read, append, `PATCH {jobs}` |
252
+ | `npc job set <npc> <n> [same flags]` | read, merge into #n, `PATCH {jobs}` |
253
+ | `npc job rm <npc> <n...> [-y]` | read, drop, `PATCH {jobs}`; refuses if the list changed meanwhile |
254
+ | `npc soul get <npc>` | `GET /npc-city/residents/:id/soul` |
255
+ | `npc soul set <npc> <json\|@file\|->` | `PATCH /npc-city/residents/:id/soul {soulConfig}` (shallow merge) |
256
+ | `npc doc export <npc> [--format md\|json] [-o file]` | `GET /npc-city/residents/:id/document?format=` |
257
+ | `npc doc apply <npc> <@file\|-> [--dry-run] [-y]` | `POST …/document/preview`, confirm, `POST …/document` |
258
+ | `npc transfer send <npc> --to <email\|userId> [-y]` | `POST /npc-city/residents/:id/transfer` |
259
+ | `npc transfer list` | `GET /npc-city/transfers/incoming` + `/outgoing` |
260
+ | `npc transfer accept\|reject\|cancel <transferId>` | `POST /npc-city/transfers/:id/<action>` |
261
+
262
+ Job types: concert, release, collaboration, brand, event, ad, appearance. The
263
+ server drops jobs without a title or date and turns unknown types into `event`;
264
+ the CLI rejects both up front.
265
+
266
+ ## backreel
267
+
268
+ | Command | API |
269
+ | --- | --- |
270
+ | `backreel list [--all] [-k] [--page] [--limit]` | `GET /backreel/post/search/my` (`--all`: `GET /backreel/post/search`) |
271
+ | `backreel get <postId>` | `GET /backreel/post/list/:id` |
272
+ | `backreel create <title> [--kind showcase\|crowdfunding] [--category] [--project-status] [--tags a,b] [-d text\|@file] [--cover assetId] [--cover-portrait] [--trailer] [--body json]` | `POST /backreel/post/create` (always a draft) |
273
+ | `backreel set <postId> [--title] [same flags]` | `PUT /backreel/post/list/:id` with only the given fields |
274
+ | `backreel publish\|unpublish <postId>` | `POST /backreel/post/list/:id/publish\|unpublish` (publish needs a cover, media or an episode) |
275
+ | `backreel rm <postId> [-y]` | `DELETE /backreel/post/list/:id` |
276
+ | `backreel credit list <postId>` | the post's `credits[]`, numbered |
277
+ | `backreel credit add <postId> --role [--name] [--kind cast\|crew\|creative] [--npc] [--user] [--link] [--job <type>]` | read, append, `PUT {credits}`; `--job` then appends to the NPC's `jobs` (own NPCs only, checked first) |
278
+ | `backreel credit rm <postId> <n...> [-y]` | read, drop, `PUT {credits}` |
279
+
280
+ Project status: planning, pre_production, in_production, post_production,
281
+ completed. `-d` plain text becomes `<p>` paragraphs; HTML passes through and
282
+ is sanitized server-side. Admin routes (`/api/backreel/*`) reject `sk_` keys.
283
+
212
284
  ## gen
213
285
 
214
286
  Shared flags: `-m/--model` (required), `-p/--prompt`, `-n/--n`, `-w/--workspace`,
@@ -357,17 +429,6 @@ Crew packs are local or remote folders (`crew.json`, `agents/<seat>.md`, `skills
357
429
  | `crew uninstall <name> [--for targets] [-y]` | removes exactly the recorded paths; reminds you to clean `openclaw.json` by hand |
358
430
  | `crew check <dir>` | validates `crew.json` ↔ `agents/*.md` (names, skills, tools vs capabilities), every `SKILL.md` (name == folder, description ≤ 1024) and that relative links resolve |
359
431
 
360
- ## crew
361
-
362
- Crew packs are local/remote folders (`crew.json`, `agents/<seat>.md`, `skills/<name>/SKILL.md`, `AGENTS.md`) — no WJI API involved.
363
-
364
- | Command | Behaviour |
365
- | --- | --- |
366
- | `crew install [name] --for <claude,codex,openclaw,grok\|all> [--from dir\|zip\|tar.gz\|url] [--ref] [--project dir] [--link] [--out zip] [--no-register] [--dry-run] [-y]` | fetches the pack (registry → GitHub tarball, cached under `~/.wji/crews/`), validates it, prints the plan, then per host: **claude** copies `skills/*` → `~/.claude/skills/` and `agents/*.md` → `~/.claude/agents/`; **codex** copies skills → `~/.agents/skills/` and writes `~/.codex/agents/<seat>.toml` (`developer_instructions` = persona body, `sandbox_mode` from capabilities, `[[skills.config]]` per skill); **openclaw** shares `~/.agents/skills/`, writes `~/.openclaw/workspaces/<crew>/<seat>/{AGENTS.md,SOUL.md,skills→}` + `openclaw.agents.json5` and runs `openclaw agents add` when the binary exists; **grok** writes `<crew>-export.zip` (`skills/`, `bots/*.json`, `bots/crew-manifest.json`, `channels/*.json`, sibling links rewritten to `sand-workflow:`). `--project` targets `<dir>/.claude`, `.agents`, `.codex`, `openclaw` instead of `$HOME` |
367
- | `crew status [name]` | reads `~/.wji/crews/installed.json`; per path ✓ / ↗ symlink / ✗ missing |
368
- | `crew uninstall <name> [--for targets] [-y]` | removes exactly the recorded paths; reminds you to clean `openclaw.json` by hand |
369
- | `crew check <dir>` | validates `crew.json` ↔ `agents/*.md` (names, skills, tools vs capabilities), every `SKILL.md` (name == folder, description ≤ 1024) and that relative links resolve |
370
-
371
432
  Import rules: the zip must contain `SKILL.md` at its root (or one folder deep — a
372
433
  single common root folder is stripped). `SKILL.md` frontmatter `name:` is
373
434
  required; `description:` is read too. Visibility is `private` (default) or
@@ -0,0 +1,161 @@
1
+ ---
2
+ name: wji-classroom
3
+ description: Run a class on WJI with the `wji` CLI — a teacher's workspace where every student has their own Infinite Canvas. Set up the class workspace, invite students by email or share link, create one private canvas per student, hand out preset prompts and starter nodes (copy the teacher's selected nodes into every student's canvas), then check each student's progress and collect their generated results by name, recency or color tag. Use when a teacher / instructor / 老師 / 講師 mentions a class, course, workshop, students / 學生 / 学员, assignments / homework / 作業, or wants to manage members' canvases on WJI.
4
+ ---
5
+
6
+ # WJI classroom
7
+
8
+ This skill sits on top of the `wji` skill — read that one for sign-in,
9
+ models, generation and the canvas basics. Everything here is the `wji`
10
+ CLI; the class-wide commands live under `wji class`.
11
+
12
+ ## How a class maps onto WJI
13
+
14
+ | Class | WJI |
15
+ | --- | --- |
16
+ | the class | a workspace the teacher **owns** |
17
+ | a student | a workspace member with role **editor** (viewers cannot generate) |
18
+ | a student's desk | a canvas whose owner is that student, visibility `owner` — only they and the teacher see it |
19
+ | handouts | workspace prompt presets, and starter nodes copied into every canvas |
20
+ | an assignment | nodes carrying a color tag with a label, e.g. red = `HW1` |
21
+
22
+ Only the workspace **owner** can invite, create share links and set canvas
23
+ owners. Check first:
24
+
25
+ ```bash
26
+ wji auth whoami
27
+ wji ws member list <workspaceId> # your row must say owner
28
+ ```
29
+
30
+ ## 1. Create the class workspace
31
+
32
+ ```bash
33
+ wji ws create "Art 101 — Spring" -a canvas # the canvas app is all a class needs
34
+ wji ws use <workspaceId> # later commands default to it
35
+ ```
36
+
37
+ ## 2. Invite students
38
+
39
+ ```bash
40
+ wji ws member invite amy@school.edu, ben@school.edu # ≤50 per call; commas or spaces
41
+ wji ws member link # or a join link (valid 7 days) to post in the class chat
42
+ wji ws member link --show # the active link
43
+ wji class roster # who has joined, role, canvas
44
+ ```
45
+
46
+ - Registered emails join immediately (`added`); the others get an invitation
47
+ email and join after signing up (`invited`). Rerun `class roster` later.
48
+ - There is **one** active link per workspace. `member link` — and any
49
+ `member invite` that emails someone — revokes the previous link. Tell the
50
+ teacher before replacing a link they already shared.
51
+ - Late joiners via the link join as the link's role (default editor).
52
+ - Wrong role: `wji ws member role "Ben" editor`. Remove: `wji ws member rm "Ben"`.
53
+
54
+ ## 3. One canvas per student
55
+
56
+ ```bash
57
+ wji class canvases --create # named after each student, private
58
+ wji class canvases --create --name "{name} · Art 101"
59
+ wji class canvases --visibility members --update # let the class see each other's canvases
60
+ ```
61
+
62
+ It only creates what is missing, so rerun it after new students join. The
63
+ teacher (workspace owner) sees every canvas; each student sees only theirs
64
+ (plus any canvas with visibility `members`, e.g. a shared "Class board").
65
+ Individual canvases: `wji canvas owner <canvasId> "Amy" --visibility owner`.
66
+
67
+ ## 4. Preset prompts, so students don't have to type
68
+
69
+ Two ways, often both:
70
+
71
+ **Workspace presets** — a prompt library for the class. Students press `/`
72
+ on their canvas (the *workspace* tab) and the prompt becomes a text node, or
73
+ `/` inside a generate node's prompt box to insert it.
74
+
75
+ ```bash
76
+ wji preset create "Watercolor portrait" -w <workspaceId> -c utility -t hw1 \
77
+ -p "A soft watercolor portrait of @image1, loose brush strokes, paper texture"
78
+ wji preset workspace # what the class sees
79
+ ```
80
+
81
+ **Starter nodes** — a ready-to-run generate node (prompt, model, settings,
82
+ reference images already wired) that students only have to press Generate on.
83
+ Build it once on the teacher's canvas, then copy it to everyone (step 5):
84
+
85
+ ```bash
86
+ wji canvas add image -c <teacherCanvas> -n "HW1 portrait" -m <model> \
87
+ -p "@image1 as a watercolor portrait" --from <referenceImageNode>
88
+ ```
89
+
90
+ Pick the model with `wji models list --feature image` / `wji models get`.
91
+
92
+ ## 5. Copy nodes into every student's canvas
93
+
94
+ The usual way: the teacher selects the nodes in the browser and presses the
95
+ link button in the canvas top bar. Then:
96
+
97
+ ```bash
98
+ wji canvas status # confirm what is selected
99
+ wji canvas tag red --selected -l HW1 # optional: mark it as an assignment
100
+ wji class copy -y # the selection → every student canvas
101
+ wji class copy <nodeId> <nodeId> -c <canvasId> --student "Amy" "Ben" -y
102
+ ```
103
+
104
+ - Connections between the copied nodes come along with their `@image1…`
105
+ order; finished images/videos are shared (not regenerated); generate nodes
106
+ keep prompt, model and settings but start un-generated.
107
+ - The group lands to the right of what is already on each canvas (`--at x,y`
108
+ or `--same-position` to choose).
109
+ - Color tags come along; the label (`HW1`) is added to a student's canvas if
110
+ that color has no label there yet.
111
+ - Failures are reported per student with a `--student …` rerun hint.
112
+
113
+ ## 6. Check progress and gather results
114
+
115
+ ```bash
116
+ wji class status # every student: nodes, done / running / failed / not run, gens, last gen, credits
117
+ wji class status --tag HW1 --sort progress # just the assignment, least done first
118
+ wji class status --sort recent # who generated most recently
119
+ wji class results --tag HW1 # finished work, newest first
120
+ wji class results --student "Amy" --since 2h
121
+ wji class results --tag HW1 -d ./hw1 # download: ./hw1/<student>/<node>-<id>.png
122
+ wji class results --tag HW1 --all # also display nodes students uploaded
123
+ ```
124
+
125
+ To review, download and look at the files, then leave feedback on the
126
+ student's canvas:
127
+
128
+ ```bash
129
+ wji canvas list --owner "Amy"
130
+ wji canvas add comment -c <amyCanvas> -t "Lovely colors — try a warmer background" --at 0,-200
131
+ ```
132
+
133
+ ## Rules
134
+
135
+ - **Emails go out in the teacher's name.** Show the exact address list and
136
+ role and get a yes in the chat before `ws member invite`. Same for
137
+ `ws member link` when a link is already active (it stops working).
138
+ - **Copying writes into every student's canvas.** Say what will be copied
139
+ (node names, count of students) and get a yes, then pass `-y`.
140
+ - **Don't generate on students' canvases** unless the teacher asks — it
141
+ spends the teacher's credits and replaces what the student would do. When
142
+ asked, follow the `wji` skill's cost rules (show the total for N students).
143
+ - **Deleting in a student's canvas** (`canvas rm`) follows the `wji`
144
+ confirm-before-destroying rule, one canvas at a time.
145
+ - Look students up by name or email (`--student "Amy"`); if a name is
146
+ ambiguous the CLI says so — ask, don't guess.
147
+
148
+ ## Good to know
149
+
150
+ - Private (`owner`) visibility hides a canvas; it does not lock it. On a
151
+ `members` canvas any editor can edit anything.
152
+ - Students can edit or delete workspace presets (the backend has no role
153
+ check there). Keep the canonical prompts in the teacher's own presets too
154
+ (`wji preset create` without `-w`) and re-copy with `wji preset copy`.
155
+ - Generation history in a workspace is readable by every member, so students
156
+ can technically list each other's generations through the API even when
157
+ canvases are private.
158
+ - Organization admins who are not the workspace owner cannot invite or set
159
+ canvas owners — the workspace owner must.
160
+ - Credits in `class status` are what each student spent in this workspace
161
+ (all time); `wji ws quota` sets a workspace spending cap.