@wji.ai/cli 0.6.0 → 0.7.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 (38) hide show
  1. package/README.md +19 -2
  2. package/dist/commands/agent.js +28 -8
  3. package/dist/commands/backreel-enquiry.js +171 -0
  4. package/dist/commands/backreel-episode.js +243 -0
  5. package/dist/commands/backreel-fund.js +299 -0
  6. package/dist/commands/backreel.js +201 -18
  7. package/dist/commands/gen.js +5 -1
  8. package/dist/commands/npc-album.js +201 -0
  9. package/dist/commands/npc-live.js +316 -0
  10. package/dist/commands/npc.js +26 -2
  11. package/dist/commands/workspace.js +74 -1
  12. package/dist/core/backreel.js +23 -0
  13. package/dist/core/client.js +18 -1
  14. package/dist/core/image.js +106 -0
  15. package/dist/core/npc.js +1 -1
  16. package/dist/core/vod.js +149 -0
  17. package/dist/index.js +6 -0
  18. package/package.json +1 -1
  19. package/skill/backreel/SKILL.md +171 -0
  20. package/skill/backreel/reference/crowdfunding.md +82 -0
  21. package/skill/backreel/reference/enquiries.md +80 -0
  22. package/skill/backreel/reference/episodes.md +104 -0
  23. package/skill/backreel/reference/images.md +76 -0
  24. package/skill/npc-character/SKILL.md +111 -0
  25. package/skill/npc-character/examples/nagi.character.md +117 -0
  26. package/skill/npc-character/examples/nagi.stage.md +34 -0
  27. package/skill/npc-character/examples/yuzu.character.md +110 -0
  28. package/skill/npc-character/examples/yuzu.stage.md +30 -0
  29. package/skill/npc-character/reference/character-craft.md +153 -0
  30. package/skill/npc-character/reference/document-format.md +151 -0
  31. package/skill/npc-character/reference/interview.md +44 -0
  32. package/skill/npc-character/reference/life.md +92 -0
  33. package/skill/npc-character/reference/runtime.md +95 -0
  34. package/skill/npc-character/reference/stage-craft.md +109 -0
  35. package/skill/npc-character/reference/visual-kit.md +81 -0
  36. package/skill/npc-character/reference/voice.md +101 -0
  37. package/skill/wji/SKILL.md +10 -1
  38. package/skill/wji/reference/commands.md +43 -6
@@ -0,0 +1,109 @@
1
+ # Writing a live stage
2
+
3
+ A stage is one filming setup the character inhabits for hours: a start
4
+ frame (keyframe A, plus optional B–D poses), idle loops that play while she
5
+ waits, a greeting, and per-turn reply videos. You are the director: some of
6
+ what you write is **performed by an image / video model (English)**, some is
7
+ **spoken by her (her language)**, and some steers **what she says (any
8
+ language)**.
9
+
10
+ | Field | Who reads it | Language |
11
+ | --- | --- | --- |
12
+ | greeting | spoken in the greeting clip | hers, ≤300 chars, ~10 s |
13
+ | idle prompts | video model, one loop each | English |
14
+ | keyframes | image model, extra resting poses | English |
15
+ | instruction | keyframe image, every clip, every reply video **and** the reply model's ACT rule | English |
16
+ | frame tune | keyframe image | English |
17
+ | reply direction (`llmInstruction`) | reply model only — what she says | any |
18
+
19
+ ## 1. Give the stream an occasion
20
+
21
+ Why is she live **right now, here**? "After closing, the last month of the
22
+ old shop", "rain day, can't go out", "unboxing fan letters after a show".
23
+ The occasion decides the greeting, the mood, the idle loops and what she
24
+ keeps steering back to. Put it in the label. One stage = one occasion; make a
25
+ second stage for a different one.
26
+
27
+ ## 2. The greeting is a hook, not a welcome
28
+
29
+ One or two sentences in her speaking tone that acknowledge the moment and
30
+ invite **one specific answer** — about ten seconds spoken, so **≤60
31
+ characters** in Japanese / Chinese / Korean, ≤30 words in English (the 300
32
+ limit is only a hard cap) ("講低你最鍾意食邊樣" — "tell me your
33
+ favourite"). Never "welcome to my stream". It plays as a pre-rendered clip,
34
+ so it must make sense to anyone arriving.
35
+
36
+ ## 3. Idle loops are a person waiting
37
+
38
+ They play whenever she is not replying, back to back, so they must loop:
39
+
40
+ - one English line each, face / hands / head / upper body only
41
+ - start and end in the start frame's neutral pose
42
+ - 3–5 loops across different energies: calm, curious, amused, waiting for an
43
+ answer
44
+ - reuse her `live.action` habits so the loops feel like her
45
+ - only objects that are in the scene image — look at the creator's scene
46
+ first (`wji npc readiness` lists scenes; the image is on the web). If no
47
+ scene exists yet, write the scene description with the creator first and
48
+ name only objects it will contain
49
+
50
+ Good: "wipes the counter slowly with a cloth, glances at the phone, small
51
+ smile" · "tunes one string, frowns, then laughs with her eyes shut".
52
+ Bad: "walks to the window" · "picks up a cup that isn't there" · "camera
53
+ slowly zooms in" · "her friend waves from the door".
54
+
55
+ ## 4. Instruction: the visual mood in one breath
56
+
57
+ Lighting, time of day, atmosphere, in English, one or two sentences:
58
+ "Small Hong Kong dessert shop after closing, fluorescent tube light with one
59
+ warm lamp at the counter, steam from a pot, quiet late-night mood."
60
+ It is also added to every reply's ACT rule, so it must describe a mood she
61
+ can stay in — not an action. Don't list props that aren't in the scene image.
62
+
63
+ ## 5. Reply direction is about speech
64
+
65
+ What tonight is about, what to steer toward and away from, what to plug, how
66
+ to treat trolls and repeat questions, how short to keep answers. Never
67
+ visuals. Write it as notes from a producer in the talkback:
68
+
69
+ > 答得短,好似喺櫃面同熟客傾偈。今晚重點:舊舖最後一個月、新歌寫到一半。
70
+ > 有人問搬舖就講實話但唔好賣慘,一句帶過再問返對方。
71
+
72
+ It stacks on top of the character's own human protocol — don't repeat it,
73
+ add tonight's specifics.
74
+
75
+ ## 6. Keyframes and frame tune
76
+
77
+ - Frame preset: `selfie` (arm's length, phone in hand), `phoneStand` (phone
78
+ propped on a table — hands free for props and instruments), `studio`
79
+ (proper camera setup), `custom` (write the frame prompt yourself).
80
+ - Keyframes B–D are the **same shot** with a different resting pose ("leaning
81
+ on the counter, chin on hand"); the reply video picks the closest one, so
82
+ 2–3 poses make replies feel less frozen.
83
+ - Frame tune is photographic language only: "warmer light on her face",
84
+ "less clutter on the counter", "slightly lower angle".
85
+
86
+ ## 7. Aspect ratio and video model
87
+
88
+ - 9:16 for a phone-stream feel (most NPC City viewers are on phones); 16:9
89
+ for a desk / studio show.
90
+ - Leave out the `Video model` line so the stage keeps the default
91
+ first/last-frame model; the stage document rejects reference models.
92
+
93
+ ## 8. Consistency pass
94
+
95
+ - Greeting, instruction, idle loops and reply direction all belong to the
96
+ same occasion and time of day.
97
+ - Every English field is English; the greeting is in her language.
98
+ - Nothing leaves frame, stands up, moves the camera, cuts, adds props or
99
+ people.
100
+ - It still makes sense to a viewer who joins forty minutes in.
101
+
102
+ ## What costs credits
103
+
104
+ Writing, importing and applying stage documents is free. Rendering is not:
105
+ the start frame (image), every clip (video), transitions, and — when the
106
+ stage is on air without debug mode — **every live reply**, charged to the
107
+ owner (a session stops at 6000 credits). Render and enable on the web, with
108
+ the creator's go-ahead. Debug mode (`wji npc stage set <id> --debug on`)
109
+ skips reply videos for rehearsal.
@@ -0,0 +1,81 @@
1
+ # The visual kit — formats per slot
2
+
3
+ The NPC City configure page has one AI-image slot per asset, each with a fixed
4
+ format and layout. Generate to **these** formats (they mirror the web app's
5
+ `build-image-prompts.ts`), or the assets look wrong next to the ones the
6
+ creator makes on the web and the live keyframes get worse references.
7
+
8
+ | Slot (web label) | Soul field | Ratio | Layout |
9
+ | --- | --- | --- | --- |
10
+ | Headshot | `assets.headshotAssetId` / `headshot` (+ profile `image`) | **1:1** | shoulders up, face clearly visible, clean background |
11
+ | **Character Sheet** | `assets.fullBodyAssetId` / `fullBody` | **16:9** | left third: large headshot · right two-thirds: **front, back, side** full-body views in one outfit · neutral studio background |
12
+ | Outfit | `assets.outfits[]` | **3:4** | **OOTD flat lay**: top-down, garments only (not worn), whole ensemble with shoes and accessories |
13
+ | Prop | `assets.props[]` | 1:1 | product-style, materials and scale readable |
14
+ | Scene | `assets.scenes[]` | **16:9** | environment / backdrop, no people |
15
+ | Profile / hero | profile `heroImage` | 16:9 (9:16 mobile) | character in her world, explicit camera (shot, lens, angle, depth of field) |
16
+
17
+ Every prompt carries the style line for the NPC's `visualStyle`; for
18
+ photoreal it is: *photorealistic real person (真人), live-action photography —
19
+ not anime, not illustration, not 3D render*.
20
+
21
+ ## Order and references
22
+
23
+ 1. **Headshot first** — every other image of her references it. If a good
24
+ portrait comes out in the wrong ratio, crop it to 1:1 rather than
25
+ regenerating (same face, no credits): `sips --cropToHeightWidth 1440 1440
26
+ --cropOffset 120 0 in.jpg --out out.jpg`.
27
+ 2. **Character Sheet** with the headshot as image 1. The live model treats it
28
+ as "full-body / outfit sheet — match the proportions", so the outfit on the
29
+ sheet is her default look.
30
+ 3. **Outfits**: generate (or photograph) the outfit, then make the flat lay
31
+ from it ("Transform the clothing from the reference image into an OOTD
32
+ flat lay…"). A stage can attach up to 6 outfits / props.
33
+ 4. **Scenes** at 16:9 even for 9:16 stages — the scene is a reference image,
34
+ the stage's frame preset decides the shot. A stage copies its scene when it
35
+ is created: after replacing a scene image, re-import (or recreate) a draft
36
+ stage so it uses the new one.
37
+ 5. Props and hero last.
38
+
39
+ ## Prompt templates (photoreal)
40
+
41
+ ```text
42
+ Character reference sheet, 16:9 horizontal com card / model sheet layout, <style line>.
43
+ Left third: one large portrait headshot — face, hair, and expression clearly visible, matching the reference headshot (image 1).
44
+ Right two-thirds: three full-body standing views in a row — front view, back view, side profile — same outfit, proportions, and appearance across all panels.
45
+ Clean neutral studio background, evenly spaced figures, professional reference sheet layout.
46
+ Character: <who, age-feel, build, hair>. Signature look: <outfit, shoes, accessories>. No text labels, no logos.
47
+ ```
48
+
49
+ ```text
50
+ Transform the clothing from the reference image (image 1) into an OOTD flat lay outfit photo, <style line>.
51
+ Top-down bird's-eye view of the complete ensemble neatly arranged on a clean neutral surface — shirt/top, pants/skirt, outerwear, shoes, and accessories laid out as a coordinated outfit-of-the-day flat lay.
52
+ Garments only, not worn by a model; clear fabric texture, silhouette, and styling visible from above.
53
+ The outfit: <pieces>. No text, no logos.
54
+ ```
55
+
56
+ ```text
57
+ Environment / scene background, <style line>. Atmospheric composition suitable as a character backdrop. <place, time, light, 3–5 concrete objects that the stage will mention>. No people, no readable signs, no logos.
58
+ ```
59
+
60
+ ```bash
61
+ wji gen image -m gpt-image-2.5-flare-fal -r 16:9 --ref <headshotAssetId> \
62
+ --set resolution=1080p quality=high --wait --json -p @sheet-prompt.txt
63
+ ```
64
+
65
+ About 14 credits per image at 1080p / high — **confirm with the creator
66
+ before generating**, and look at every result before attaching it (faces
67
+ drift; reject and regenerate rather than attach a different face).
68
+
69
+ ## Attaching
70
+
71
+ ```bash
72
+ wji npc soul get <npc> > soul.json # edit assets, keep album/albums out
73
+ wji npc soul set <npc> @assets.json # {"assets": {...}} — replaces the whole assets object
74
+ wji npc set <npc> --image <headshotAssetId> --hero-image <heroAssetId> --set 'gallery=["url1","url2"]'
75
+ ```
76
+
77
+ `assets` is replaced as a whole by `soul set`, so always start from the
78
+ current one. Outfit / prop / scene entries are
79
+ `{id, assetId, name, url, description, referenceRole: outfit|prop|location}`;
80
+ names and descriptions are shown to the creator and scene descriptions go into
81
+ keyframe prompts.
@@ -0,0 +1,101 @@
1
+ # Voice: speaking tone and on-camera action
2
+
3
+ ## Speaking tone (`live.speakingTone`, 500 chars, her language)
4
+
5
+ The reply model is told to "match this closely", and it copies what you
6
+ **show** far better than what you describe. A good speaking tone has:
7
+
8
+ 1. **Register in one line** — "Cantonese with English slips, short sentences,
9
+ like talking across a shop counter."
10
+ 2. **One catchphrase** she really uses, in quotes.
11
+ 3. **One thing she never says**, and why ("never says 加油 — too lazy").
12
+ 4. **How she takes a compliment / a tease** — with the line she'd say.
13
+ 5. **Two or three sample lines**, each short enough to be one live reply:
14
+ ≤40 words in English / Indonesian, **≤60 characters** in Japanese, Korean,
15
+ Chinese, Cantonese, Thai, Vietnamese.
16
+
17
+ Before: "She is witty and warm, speaks casually and likes to tease people."
18
+ After: "Cantonese with a few English words, short lines, like at the shop
19
+ counter. Catchphrase「糖水都要趁熱食啦」. Takes compliments by deflecting:
20
+ 「得啦得啦,你想我送多碗咩」. Never says「加油」. e.g.「你今晚食咗咩?唔好話我知係杯麵。」"
21
+
22
+ `speechPattern` (formal / casual / poetic / robotic / archaic) is the coarse
23
+ register **and** her body language on video (formal "composed and poised",
24
+ casual "relaxed", poetic "dreamy and soft", robotic "precise and minimal",
25
+ archaic "graceful and ceremonious"). When the two pull apart — a polite
26
+ speaker who slouches — choose for the body, and let the speaking tone carry
27
+ the politeness.
28
+
29
+ ## Code-switching
30
+
31
+ If she mixes languages, write the rule *and* show it:
32
+
33
+ - **Hong Kong**: Cantonese grammar and particles (啦、喎、咩、囉) with English
34
+ nouns and fillers ("OK", "chill", "send 我"). Write in written Cantonese
35
+ (嘅、咗、唔、佢), not standard written Chinese, or she will sound like a
36
+ newsreader. Set `languages=HK`.
37
+ - **Taiwan**: Mandarin with Taiwanese particles (欸、啦、齁) and occasional
38
+ Taiwanese Hokkien / Japanese loanwords; traditional characters. `languages=TW`.
39
+ - **Japanese**: decide politeness (です/ます vs plain), first-person pronoun
40
+ (私、あたし、僕、俺, or her own name), and any sentence-final habit.
41
+ `languages=JP`.
42
+ - **English**: dialect and rhythm matter more than slang — "British, dry,
43
+ understated" vs "SoCal, fast, lots of 'like'". Avoid dated slang lists.
44
+
45
+ The first `languages` entry is what she speaks live; add a second only if
46
+ she really answers in it.
47
+
48
+ ## Lines that work live
49
+
50
+ A live reply is one or two sentences, spoken in under 12 seconds, reacting
51
+ to one viewer. So sample lines should:
52
+
53
+ - react to the person (use what they said; address them the way she
54
+ would — "you", a nickname habit, "ラジオネーム…さん"), then
55
+ - add one beat of her (an opinion, a callback, a question back).
56
+
57
+ Bad: long monologues, lists, lines that need context the viewer doesn't
58
+ have, emoji and stage directions inside the line. Don't invent viewer names
59
+ inside sample lines — the model will greet strangers by them; the runtime
60
+ supplies the real viewer's name when it wants her to use it.
61
+
62
+ ## Human protocol vs speaking tone
63
+
64
+ - Speaking tone = **how** she sounds.
65
+ - Human protocol = **what she does** with people: regulars vs newcomers,
66
+ compliments, trolls, sadness, silence, personal questions, a boundary.
67
+
68
+ Don't repeat one in the other.
69
+
70
+ ## On-camera action (`live.action`, 300 chars, ENGLISH)
71
+
72
+ 2–3 physical habits tied to emotion, performed by a video model on a locked
73
+ camera:
74
+
75
+ - visible, upper body only: hands, face, head, shoulders, objects already in
76
+ frame
77
+ - repeatable — they will recur in many clips
78
+ - tied to a feeling: "laughs with her eyes shut", "rests her chin on the
79
+ guitar when listening", "taps the table twice when excited"
80
+
81
+ Never: walking, standing up, turning away, leaving frame, camera moves, new
82
+ props, other people. Never write it in the character's language — it is a
83
+ video prompt.
84
+
85
+ ## Making the voice sample
86
+
87
+ The voice sample is uploaded or set on the soul (`voiceSample`). The cheap way
88
+ to make one is **Seed Audio 1.0** with the headshot as the voice reference —
89
+ about 45 credits a minute, so a 3-second sample costs a few credits (MiniMax
90
+ speech is a flat ~300 per line). Write a bracketed direction in her language,
91
+ then one new 8–12-character line; the bracket is followed, not spoken.
92
+ **Confirm with the creator before generating.**
93
+
94
+ ```bash
95
+ wji gen audio -m "Seed Audio 1.0" --ref <headshotAssetId> -n 2 --wait --json \
96
+ -p "(27세 여성; 전직 연습생; 맑지만 살짝 허스키한 음색; 중간 음높이; 약간 빠르고 숨이 찬 말투; 표준 서울말; 지쳤지만 단단한 감정; 건조한 목소리, 배경음악과 효과음 없음)오늘은 한 번만 더 해 볼게요"
97
+ wji npc soul set <npc> '{"voiceSample":{"assetId":"<audioAssetId>","url":"<url>","label":"…","durationSec":3.2}}'
98
+ ```
99
+
100
+ Listen to both takes and keep the one that sounds like her speaking tone.
101
+
@@ -84,6 +84,9 @@ Most commands take `--workspace`, but setting a default is less error-prone:
84
84
  ```bash
85
85
  wji ws list
86
86
  wji ws use <workspaceId>
87
+ wji ws defaults # default chat / image / video / audio models
88
+ wji ws defaults --chat <model> --video <nickname> # "none" clears one
89
+ wji ws leave <workspaceId> # leave a workspace you were invited to
87
90
  ```
88
91
 
89
92
  After that, `wji ws get`, `wji fs`, `wji gen` and `wji preset list` all default
@@ -319,8 +322,12 @@ wji agent skill-add <agentId> system:image user:<skillId>
319
322
  wji agent skills <agentId>
320
323
  wji agent versions <agentId> # every edit auto-snapshots a version
321
324
  wji agent restore <agentId> <versionId>
325
+ wji agent update <agentId> --max-steps 80 # model calls per chat turn (default 40, max 200)
322
326
  ```
323
327
 
328
+ Versions, files, update and restore are creator-only — a 403 `無權操作此 Agent`
329
+ on someone else's agent is expected.
330
+
324
331
  Skill refs are `system:<key>` or `user:<skillId>` (a bare id means `user:`).
325
332
  System keys currently include `image`, `document`, `workspace-dataset`,
326
333
  `canvas` and `seedance-25` — confirm with `wji skill system`.
@@ -466,7 +473,7 @@ wji npc set @mika --tagline "…" --tag tier=Rising --social ig=https://…
466
473
  wji npc publish @mika # visibility public (unpublish = private)
467
474
  wji npc job add @mika -t concert --title "Neon Night" --date 2026-10-01 --location Taipei
468
475
  wji npc job set @mika 2 --detail "sold out" ; wji npc job rm @mika 3 -y
469
- wji npc soul get @mika > soul.json ; wji npc soul set @mika '{"voice":{…}}'
476
+ wji npc soul get @mika > soul.json ; wji npc soul set @mika '{"liveSpeakingTone":"…"}' # keys must be soul keys — unknown ones are stored silently
470
477
  wji npc doc export @mika -o mika.md # whole character in one file
471
478
  wji npc doc apply @mika @mika.md --dry-run # see the diff, then without --dry-run
472
479
  ```
@@ -493,6 +500,8 @@ wji backreel set <postId> --project-status in_production
493
500
  wji backreel credit add <postId> --kind creative --name "Wayne" --role 導演
494
501
  wji backreel credit add <postId> --npc @mika --role "飾 阿明" --job appearance
495
502
  wji backreel publish <postId> # unpublish takes it offline
503
+ wji backreel set <postId> --logline "一句話賣點" # always public, ≤200 chars
504
+ wji backreel creators --role investor # browse creators
496
505
  ```
497
506
 
498
507
  - Credits (max 30) are rewritten whole in order; `credit rm` goes by number.
@@ -72,6 +72,8 @@ switch endpoint.
72
72
  | `ws update [id] [-n] [-d] [-r] [-l] [--set]` | `PUT /workspace/list/:id` |
73
73
  | `ws rm <id> [-y]` | `DELETE /workspace/list/:id` (owner only) |
74
74
  | `ws favorite <id> [--off]` | `PUT /workspace/list/:id/favorite` |
75
+ | `ws leave <id> [-y]` | `POST /workspace/list/:id/leave` — any member except the owner; coming back needs a new invite. Clears the profile default if it pointed there |
76
+ | `ws defaults [id] [--chat] [--image] [--video] [--storyboard] [--audio] [--image-resolution] [--video-resolution]` | no flags: shows `settings.defaultModels`. With flags: reads the workspace at `detail=full`, merges, `PUT /workspace/list/:id {settings}` (settings is replaced whole, so never send a partial `settings` via `ws update --set`). `none` clears one. Chat is stored as the model **name** (what conversations carry), media as the **nickname**; either spelling is accepted. The chat default is used for new conversations in the workspace |
75
77
  | `ws fs [id] [-a appId]` | `GET /workspace/list/:id/fs[/:appid]` |
76
78
  | `ws app list\|add <app> [-n]\|rm <appId> [-y]` | `POST/DELETE /workspace/list/:id/apps` |
77
79
  | `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 |
@@ -254,17 +256,29 @@ unknown `@handle` falls back to `GET /npc-city/residents/by-handle/:h` (public).
254
256
  | `npc rm <npc> [-y]` | `DELETE /npc-city/residents/:id` (soft delete) |
255
257
  | `npc handle <handle> [--exclude <npc>]` | `GET /npc-city/residents/handle-available` |
256
258
  | `npc job list <npc>` | the resident's `jobs[]`, numbered 1…n |
257
- | `npc job add <npc> -t <type> --title --date YYYY-MM-DD [--detail] [--location] [--url]` | read, append, `PATCH {jobs}` |
259
+ | `npc job add <npc> -t <type> --title --date YYYY-MM-DD [--about] [--location] [--url]` | read, append, `PATCH {jobs}` |
258
260
  | `npc job set <npc> <n> [same flags]` | read, merge into #n, `PATCH {jobs}` |
259
261
  | `npc job rm <npc> <n...> [-y]` | read, drop, `PATCH {jobs}`; refuses if the list changed meanwhile |
260
262
  | `npc soul get <npc>` | `GET /npc-city/residents/:id/soul` |
261
263
  | `npc soul set <npc> <json\|@file\|->` | `PATCH /npc-city/residents/:id/soul {soulConfig}` (shallow merge) |
262
264
  | `npc doc export <npc> [--format md\|json] [-o file]` | `GET /npc-city/residents/:id/document?format=` |
263
- | `npc doc apply <npc> <@file\|-> [--dry-run] [-y]` | `POST …/document/preview`, confirm, `POST …/document` |
265
+ | `npc doc apply <npc> <@file\|-> [--dry-run] [--sync-memories] [-y]` | `POST …/document/preview`, confirm, `POST …/document`. The document route reports memory changes but never saves them; `--sync-memories` replaces the memory table with the document's `## Memories` |
266
+ | `npc memory list\|add\|set\|rm <npc>` | `GET/POST /npc-city/residents/:id/memories`, `PATCH/DELETE /npc-city/memories/:id` (title ≤200, date ≤40, weight 1–5, type formative\|trauma\|joy\|connection\|revelation). `list` marks the top 3 by weight (then newest) — the only ones the live reply prompt reads, content clipped to 140 |
267
+ | `npc album list <npc> [album]` · `create <npc> --name [-d] [--photo …]` · `add <npc> <album> <photo…>` · `set <npc> <album> [--name] [-d] [--cover n] [--label n=text…]` · `rm-photo <npc> <album> <n…>` · `rm <npc> <album>` | `GET/POST /npc-city/residents/:id/albums`, `PATCH/DELETE …/albums/:albumId` (label ≤120, description ≤500; photos `{id, assetId, url, label}`, the CLI mints ids and resolves asset ids / uploads files to URLs; `<album>` = number or id) |
268
+ | `npc readiness <npc>` | `GET /npc-city/live/residents/:id/readiness` — soul integrity, gate reasons (selfDescription / humanProtocol >10 chars, a trait, headshot, a scene), scenes, voice sample, stages |
269
+ | `npc stage list <npc>` | `GET /npc-city/live/residents/:id/stages` |
270
+ | `npc stage export <stageId> [--format md\|json] [-o]` | `GET /npc-city/live/stages/:id/document` |
271
+ | `npc stage apply <stageId> <@file\|-> [--dry-run] [-y]` | `POST …/document/preview`, confirm, `POST …/document` (text only; baked fields warn) |
272
+ | `npc stage import <npc> <@file\|-> [-y]` | `POST /npc-city/live/residents/:id/stages/import` — a Draft stage, nothing rendered, no credits |
273
+ | `npc stage set <stageId> [--debug on\|off] [--on on\|off] [--label]` | `PATCH /npc-city/live/stages/:id {debugMode, enabled, label}` — `--on` needs a Ready stage; debug on an on-air stage asks first |
274
+ | `npc stage rm <stageId> [-y]` | `DELETE /npc-city/live/stages/:id` |
264
275
  | `npc transfer send <npc> --to <email\|userId> [-y]` | `POST /npc-city/residents/:id/transfer` |
265
276
  | `npc transfer list` | `GET /npc-city/transfers/incoming` + `/outgoing` |
266
277
  | `npc transfer accept\|reject\|cancel <transferId>` | `POST /npc-city/transfers/:id/<action>` |
267
278
 
279
+ Writing the character and stages well — what each field does at runtime —
280
+ is the `npc-character` skill.
281
+
268
282
  Job types: concert, release, collaboration, brand, event, ad, appearance. The
269
283
  server drops jobs without a title or date and turns unknown types into `event`;
270
284
  the CLI rejects both up front.
@@ -275,16 +289,28 @@ the CLI rejects both up front.
275
289
  | --- | --- |
276
290
  | `backreel list [--all] [-k] [--page] [--limit]` | `GET /backreel/post/search/my` (`--all`: `GET /backreel/post/search`) |
277
291
  | `backreel get <postId>` | `GET /backreel/post/list/:id` |
278
- | `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) |
292
+ | `backreel create <title> [--kind showcase\|crowdfunding] [--logline] [--media assetId...] [--category] [--project-status] [--tags a,b] [-d text\|@file] [--cover assetId] [--cover-portrait] [--trailer] [--body json]` | `POST /backreel/post/create` (always a draft) |
279
293
  | `backreel set <postId> [--title] [same flags]` | `PUT /backreel/post/list/:id` with only the given fields |
280
294
  | `backreel publish\|unpublish <postId>` | `POST /backreel/post/list/:id/publish\|unpublish` (publish needs a cover, media or an episode) |
281
295
  | `backreel rm <postId> [-y]` | `DELETE /backreel/post/list/:id` |
296
+ | `backreel creators [-k] [--role kind] [--verified] [--no-featured] [--page] [--limit ≤48]` | `GET /backreel/creator/list` — editor-picked `featured` plus a heat-ranked page (recent likes, favorites ×2); creators with no recent activity are not listed. `--role`: investor, production_company, brand, distributor, sales_agent |
297
+ | `backreel image <file...> --slot cover\|portrait\|media\|photo [--post id] [--check]` | reads the size locally, warns on ratio / resolution, `POST /assets/v2/upload` with width/height, then `PUT {cover\|coverPortrait\|assets}` (media appends, ≤9) |
298
+ | `backreel image-specs` | recommended size per slot (16:9 1920×1080, 9:16 1080×1920, 3:4 1536×2048, 1:1 800×800) |
299
+ | `backreel check <postId>` | publish blockers (title, description text/img, cover\|media\|episode, crowdfunding goal ≥1) and advice (portrait, logline, credits, VOD not ready) |
300
+ | `backreel episode list\|add\|set\|rm\|move\|tiers\|status\|play` | whole `episodes[]` read-modify-`PUT` (≤30, showcase only). A file: `POST /backreel/vod/upload-token` → signed ApplyUploadInfo / PUT / CommitUploadInfo → `POST /backreel/vod/claim` → `vodVid`; `--legacy` / `--asset` = WJI asset. `status` / `play` use `GET …/episodes/:order/play` (409 = transcoding) |
301
+ | `backreel enquiry list\|unread\|get\|reply\|status\|grant\|download` | `/backreel/enquiry/search?box=`, `unread-count`, `list/:id` + `list/:id/messages`, `POST list/:id/messages {body, attachments}` (files via `POST /backreel/file/upload?purpose=enquiry`), `POST list/:id/status`, `POST list/:id/grant`, `GET /backreel/file/:id/download` |
302
+ | `backreel fund show\|set\|tier\|supporter\|donations` | read-modify-`PUT` of `campaign` (crowdfunding only) and `donation` (any post); `donations` = `GET /backreel/donation/post/:id/manage` |
282
303
  | `backreel credit list <postId>` | the post's `credits[]`, numbered |
283
304
  | `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) |
284
305
  | `backreel credit rm <postId> <n...> [-y]` | read, drop, `PUT {credits}` |
285
306
 
286
307
  Project status: planning, pre_production, in_production, post_production,
287
- completed. `-d` plain text becomes `<p>` paragraphs; HTML passes through and
308
+ completed. `--logline` is a one-line hook (≤200 chars, HTML stripped, `""`
309
+ clears it) shown large on the post page and **always public**, even when the
310
+ description is gated. The post detail no longer carries playable URLs for VOD
311
+ episodes — playback is gated per episode on the web. Every `backreel` call
312
+ sends `X-App: backreel` so notifications and mail link to Backreel. The
313
+ `backreel` skill covers the creator workflow in depth. `-d` plain text becomes `<p>` paragraphs; HTML passes through and
288
314
  is sanitized server-side. Admin routes (`/api/backreel/*`) reject `sk_` keys.
289
315
 
290
316
  ## gen
@@ -298,7 +324,7 @@ Shared flags: `-m/--model` (required), `-p/--prompt`, `-n/--n`, `-w/--workspace`
298
324
  | --- | --- | --- |
299
325
  | `gen image` | `--ref`, `--omni`, `--style-ref`, `--reference-weight`, `--stylize`, `--model-options` | `POST /ai/assets/history/image/generations` |
300
326
  | `gen video` | `-d/--duration`, `--start-image`, `--end-image`, `--ref`, `--ref-video`, `--ref-audio` | `POST /ai/assets/history/video/generations` |
301
- | `gen audio` | `-d/--duration`, `--ref-audio` | `POST /ai/assets/history/audio/generations` |
327
+ | `gen audio` | `-d/--duration`, `--ref-audio`, `--ref` (one image, e.g. a headshot → a Seed Audio voice sample; not with `--ref-audio`) | `POST /ai/assets/history/audio/generations` |
302
328
  | `gen cost -t <type> -m <model>` | `-n`, `-p`, `-d`, `-r`, `--refs`, `--values` | `POST /ai/assets/preComputeCost` |
303
329
 
304
330
  Every generation goes through the history endpoint — there is no raw mode. The
@@ -361,7 +387,7 @@ Features: `text`, `image`, `video`, `audio`, `tts`, `web`, `thinking`,
361
387
  ## agent
362
388
 
363
389
  `agent list` (public marketplace) · `agent mine` · `agent get <id>` ·
364
- `agent create <name> -d [-i instructions] [-m model] [--visibility] [-c] [-t] [--greeting]` ·
390
+ `agent create <name> -d [-i instructions] [-m model] [--visibility] [-c] [-t] [--greeting] [--max-steps n]` ·
365
391
  `agent update <id> …` · `agent rm <id> [-y]` · `agent files <id>` ·
366
392
  `agent categories [--mine]` · `agent tags [--mine]` · `agent recommend`
367
393
 
@@ -380,6 +406,17 @@ takes `--skill <ref...>`.
380
406
  Visibility: `private`, `unlist`, `public`. Instructions are only returned to
381
407
  the agent's creator.
382
408
 
409
+ Ownership (backend since Oct 2026): a private agent is readable only by its
410
+ creator; `update`, `rm`, `files`, `versions` and `restore` are creator-only on
411
+ every agent (403 `無權操作此 Agent` otherwise — not a bug). `agent create`
412
+ needs the account's agent-create permission (without it: 400 `您沒有此功能的訪問權限`). `--set` cannot change `creator` or
413
+ `organization`, and non-admins cannot set `key`, `isSystem`, `isHighligted`,
414
+ `recommendTitle`, `weight` or `store` — the server drops them silently.
415
+
416
+ `--max-steps n` caps model calls per chat turn (1–200; parallel tool calls in
417
+ one step count once). Unset means the site default, 40. `update --max-steps
418
+ default` clears it.
419
+
383
420
  Field caps: name ≤200, model ≤100, description and greeting ≤5,000,
384
421
  instructions ≤200,000 characters.
385
422